-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Summary
Some OIDC providers require either PKCE (code_challenge) or nonce-based CSRF protection. Coder currently implements neither, which prevents integration with these providers.
This issue proposes implementing OIDC nonce support as an alternative to PKCE for CSRF protection, following RFC draft-ietf-oauth-security-topics Section 4.5.3.2.
Problem
When configuring OIDC authentication with certain identity providers that require PKCE, users receive:
{"message":"Encountered error in oidc process: invalid_request","detail":"Invalid request: Missing CodeChallenge (PKCE - RFC 7636)"}
Coder's OIDC client implementation uses the standard authorization code flow but does not include:
- PKCE parameters (
code_challenge,code_challenge_method,code_verifier) - OIDC nonce parameter and validation
Proposed Solution
Implement OIDC nonce support as a CSRF mitigation mechanism. Per the OAuth Security BCP:
With additional precautions, described in Section 4.5.3.2, confidential OpenID Connect clients MAY use the nonce parameter and the respective Claim in the ID Token instead [of PKCE].
Implementation Requirements
Per RFC requirements, the implementation must:
- Generate a cryptographically random nonce before the authorization request
- Bind nonce to user agent session (store in cookie similar to state parameter)
- Include nonce in authorization request using
oidc.Nonce()from go-oidc library - Validate nonce in ID Token from token endpoint response
- Disregard all tokens until nonce validation succeeds
Technical Approach
The github.com/coreos/go-oidc/v3 library already supports nonce:
// 1. Generate nonce before redirect
nonce, _ := cryptorand.String(32)
// 2. Store nonce in cookie (similar to state)
http.SetCookie(rw, &http.Cookie{
Name: "coder_oauth2_nonce",
Value: nonce,
Path: "/",
HttpOnly: true,
})
// 3. Add nonce to authorization URL
authURL := config.AuthCodeURL(state, oidc.Nonce(nonce))
// 4. On callback, validate nonce in ID token
verifier := provider.Verifier(&oidc.Config{
ClientID: clientID,
// This is currently NOT set in Coder
})
// After verification, manually check nonce claim matches stored value
var claims struct {
Nonce string `json:"nonce"`
}
idToken.Claims(&claims)
if claims.Nonce != storedNonce {
// Reject - potential authorization code injection attack
}Files to Modify
coderd/httpmw/oauth2.go- Add nonce generation, storage, and inclusion in auth URLcoderd/userauth.go- Add nonce validation inuserOIDC()callback handlercodersdk/deployment.go- Potentially add config option to enable/disable nonce
Alternative: PKCE Support
Full PKCE support (RFC 7636) would be a more comprehensive solution that also protects public clients. However, nonce is:
- Simpler to implement (no SHA256 hashing)
- Sufficient for confidential clients like Coder
- Already supported by the go-oidc library
A separate issue could track PKCE support if needed.