feat: support the OAuth2 device flow with GitHub for signing in (#16585)

First PR in a series to address
https://github.com/coder/coder/issues/16230.

Introduces support for logging in via the [GitHub OAuth2 Device
Flow](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#device-flow).

It's previously been possible to configure external auth with the device
flow, but it's not been possible to use it for logging in. This PR
builds on the existing support we had to extend it to sign ins.

When a user clicks "sign in with GitHub" when device auth is configured,
they are redirected to the new `/login/device` page, which makes the
flow possible from the client's side. The recording below shows the full
flow.


https://github.com/user-attachments/assets/90c06f1f-e42f-43e9-a128-462270c80fdd

I've also manually tested that it works for converting from
password-based auth to oauth.

Device auth can be enabled by a deployment's admin by setting the
`CODER_OAUTH2_GITHUB_DEVICE_FLOW` env variable or a corresponding config
setting.
This commit is contained in:
Hugo Dutka
2025-02-21 18:42:16 +01:00
committed by GitHub
parent 660746462e
commit 8c5e7007cd
24 changed files with 657 additions and 111 deletions
+11
View File
@@ -505,6 +505,7 @@ type OAuth2Config struct {
type OAuth2GithubConfig struct {
ClientID serpent.String `json:"client_id" typescript:",notnull"`
ClientSecret serpent.String `json:"client_secret" typescript:",notnull"`
DeviceFlow serpent.Bool `json:"device_flow" typescript:",notnull"`
AllowedOrgs serpent.StringArray `json:"allowed_orgs" typescript:",notnull"`
AllowedTeams serpent.StringArray `json:"allowed_teams" typescript:",notnull"`
AllowSignups serpent.Bool `json:"allow_signups" typescript:",notnull"`
@@ -1572,6 +1573,16 @@ func (c *DeploymentValues) Options() serpent.OptionSet {
Annotations: serpent.Annotations{}.Mark(annotationSecretKey, "true"),
Group: &deploymentGroupOAuth2GitHub,
},
{
Name: "OAuth2 GitHub Device Flow",
Description: "Enable device flow for Login with GitHub.",
Flag: "oauth2-github-device-flow",
Env: "CODER_OAUTH2_GITHUB_DEVICE_FLOW",
Value: &c.OAuth2.Github.DeviceFlow,
Group: &deploymentGroupOAuth2GitHub,
YAML: "deviceFlow",
Default: "false",
},
{
Name: "OAuth2 GitHub Allowed Orgs",
Description: "Organizations the user must be a member of to Login with GitHub.",
+4
View File
@@ -227,3 +227,7 @@ func (c *Client) RevokeOAuth2ProviderApp(ctx context.Context, appID uuid.UUID) e
}
return nil
}
type OAuth2DeviceFlowCallbackResponse struct {
RedirectURL string `json:"redirect_url"`
}