mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat!: support PKCE in the oauth2 client's auth/exchange flow (#21215)
**Breaking Change:** Existing oauth apps might now use PKCE. If an unknown IdP type was being used, and it does not support PKCE, it will break. To fix, set the PKCE methods on the external auth to `none` ``` export CODER_EXTERNAL_AUTH_1_PKCE_METHODS=none ```
This commit is contained in:
@@ -38,6 +38,10 @@ const (
|
||||
SessionTokenHeader = "Coder-Session-Token"
|
||||
// OAuth2StateCookie is the name of the cookie that stores the oauth2 state.
|
||||
OAuth2StateCookie = "oauth_state"
|
||||
// OAuth2PKCEVerifier is the name of the cookie that stores the oauth2 PKCE
|
||||
// verifier. This is the raw verifier that when hashed, will match the challenge
|
||||
// sent in the initial oauth2 request.
|
||||
OAuth2PKCEVerifier = "oauth_pkce_verifier"
|
||||
// OAuth2RedirectCookie is the name of the cookie that stores the oauth2 redirect.
|
||||
OAuth2RedirectCookie = "oauth_redirect"
|
||||
|
||||
|
||||
@@ -772,6 +772,9 @@ type ExternalAuthConfig struct {
|
||||
DisplayName string `json:"display_name" yaml:"display_name"`
|
||||
// DisplayIcon is a URL to an icon to display in the UI.
|
||||
DisplayIcon string `json:"display_icon" yaml:"display_icon"`
|
||||
// CodeChallengeMethodsSupported lists the PKCE code challenge methods
|
||||
// The only one supported by Coder is "S256".
|
||||
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported" yaml:"code_challenge_methods_supported"`
|
||||
}
|
||||
|
||||
type ProvisionerConfig struct {
|
||||
@@ -1681,8 +1684,7 @@ func (c *DeploymentValues) Options() serpent.OptionSet {
|
||||
Env: "CODER_BLOCK_DIRECT",
|
||||
Value: &c.DERP.Config.BlockDirect,
|
||||
Group: &deploymentGroupNetworkingDERP,
|
||||
YAML: "blockDirect", Annotations: serpent.Annotations{}.
|
||||
Mark(annotationExternalProxies, "true"),
|
||||
YAML: "blockDirect", Annotations: serpent.Annotations{}.Mark(annotationExternalProxies, "true"),
|
||||
},
|
||||
{
|
||||
Name: "DERP Force WebSockets",
|
||||
|
||||
+22
-21
@@ -396,27 +396,28 @@ func TestExternalAuthYAMLConfig(t *testing.T) {
|
||||
return string(data)
|
||||
}
|
||||
githubCfg := codersdk.ExternalAuthConfig{
|
||||
Type: "github",
|
||||
ClientID: "client_id",
|
||||
ClientSecret: "client_secret",
|
||||
ID: "id",
|
||||
AuthURL: "https://example.com/auth",
|
||||
TokenURL: "https://example.com/token",
|
||||
ValidateURL: "https://example.com/validate",
|
||||
RevokeURL: "https://example.com/revoke",
|
||||
AppInstallURL: "https://example.com/install",
|
||||
AppInstallationsURL: "https://example.com/installations",
|
||||
NoRefresh: true,
|
||||
Scopes: []string{"user:email", "read:org"},
|
||||
ExtraTokenKeys: []string{"extra", "token"},
|
||||
DeviceFlow: true,
|
||||
DeviceCodeURL: "https://example.com/device",
|
||||
Regex: "^https://example.com/.*$",
|
||||
DisplayName: "GitHub",
|
||||
DisplayIcon: "/static/icons/github.svg",
|
||||
MCPURL: "https://api.githubcopilot.com/mcp/",
|
||||
MCPToolAllowRegex: ".*",
|
||||
MCPToolDenyRegex: "create_gist",
|
||||
Type: "github",
|
||||
ClientID: "client_id",
|
||||
ClientSecret: "client_secret",
|
||||
ID: "id",
|
||||
AuthURL: "https://example.com/auth",
|
||||
TokenURL: "https://example.com/token",
|
||||
ValidateURL: "https://example.com/validate",
|
||||
RevokeURL: "https://example.com/revoke",
|
||||
AppInstallURL: "https://example.com/install",
|
||||
AppInstallationsURL: "https://example.com/installations",
|
||||
NoRefresh: true,
|
||||
Scopes: []string{"user:email", "read:org"},
|
||||
ExtraTokenKeys: []string{"extra", "token"},
|
||||
DeviceFlow: true,
|
||||
DeviceCodeURL: "https://example.com/device",
|
||||
Regex: "^https://example.com/.*$",
|
||||
DisplayName: "GitHub",
|
||||
DisplayIcon: "/static/icons/github.svg",
|
||||
MCPURL: "https://api.githubcopilot.com/mcp/",
|
||||
MCPToolAllowRegex: ".*",
|
||||
MCPToolDenyRegex: "create_gist",
|
||||
CodeChallengeMethodsSupported: []string{"S256"},
|
||||
}
|
||||
|
||||
// Input the github section twice for testing a slice of configs.
|
||||
|
||||
@@ -94,14 +94,15 @@ type ExternalAuthLink struct {
|
||||
|
||||
// ExternalAuthLinkProvider are the static details of a provider.
|
||||
type ExternalAuthLinkProvider struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Device bool `json:"device"`
|
||||
DisplayName string `json:"display_name"`
|
||||
DisplayIcon string `json:"display_icon"`
|
||||
AllowRefresh bool `json:"allow_refresh"`
|
||||
AllowValidate bool `json:"allow_validate"`
|
||||
SupportsRevocation bool `json:"supports_revocation"`
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Device bool `json:"device"`
|
||||
DisplayName string `json:"display_name"`
|
||||
DisplayIcon string `json:"display_icon"`
|
||||
AllowRefresh bool `json:"allow_refresh"`
|
||||
AllowValidate bool `json:"allow_validate"`
|
||||
SupportsRevocation bool `json:"supports_revocation"`
|
||||
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"`
|
||||
}
|
||||
|
||||
type ExternalAuthAppInstallation struct {
|
||||
|
||||
Vendored
+2
@@ -24,3 +24,5 @@ externalAuthProviders:
|
||||
regex: ^https://example.com/.*$
|
||||
display_name: GitHub
|
||||
display_icon: /static/icons/github.svg
|
||||
code_challenge_methods_supported:
|
||||
- S256
|
||||
|
||||
Reference in New Issue
Block a user