diff --git a/internal/api/token_oidc.go b/internal/api/token_oidc.go index 9a8c57ccb..6116e70b4 100644 --- a/internal/api/token_oidc.go +++ b/internal/api/token_oidc.go @@ -26,7 +26,7 @@ type IdTokenGrantParams struct { Issuer string `json:"issuer"` } -func (p *IdTokenGrantParams) getProvider(ctx context.Context, config *conf.GlobalConfiguration, r *http.Request) (*oidc.Provider, string, []string, error) { +func (p *IdTokenGrantParams) getProvider(ctx context.Context, config *conf.GlobalConfiguration, r *http.Request) (*oidc.Provider, *conf.OAuthProviderConfiguration, string, []string, error) { log := observability.GetLogEntry(r) var cfg *conf.OAuthProviderConfiguration @@ -84,20 +84,20 @@ func (p *IdTokenGrantParams) getProvider(ctx context.Context, config *conf.Globa } if !allowed { - return nil, "", nil, badRequestError(fmt.Sprintf("Custom OIDC provider %q not allowed", p.Issuer)) + return nil, nil, "", nil, badRequestError(fmt.Sprintf("Custom OIDC provider %q not allowed", p.Issuer)) } } if cfg != nil && !cfg.Enabled { - return nil, "", nil, badRequestError(fmt.Sprintf("Provider (issuer %q) is not enabled", issuer)) + return nil, nil, "", nil, badRequestError(fmt.Sprintf("Provider (issuer %q) is not enabled", issuer)) } oidcProvider, err := oidc.NewProvider(ctx, issuer) if err != nil { - return nil, "", nil, err + return nil, nil, "", nil, err } - return oidcProvider, providerType, acceptableClientIDs, nil + return oidcProvider, cfg, providerType, acceptableClientIDs, nil } // IdTokenGrant implements the id_token grant type flow @@ -126,7 +126,7 @@ func (a *API) IdTokenGrant(ctx context.Context, w http.ResponseWriter, r *http.R return oauthError("invalid request", "provider or client_id and issuer required") } - oidcProvider, providerType, acceptableClientIDs, err := params.getProvider(ctx, config, r) + oidcProvider, oauthConfig, providerType, acceptableClientIDs, err := params.getProvider(ctx, config, r) if err != nil { return err } @@ -165,16 +165,18 @@ func (a *API) IdTokenGrant(ctx context.Context, w http.ResponseWriter, r *http.R return oauthError("invalid request", "Unacceptable audience in id_token") } - tokenHasNonce := idToken.Nonce != "" - paramsHasNonce := params.Nonce != "" - - if tokenHasNonce != paramsHasNonce { - return oauthError("invalid request", "Passed nonce and nonce in id_token should either both exist or not.") - } else if tokenHasNonce && paramsHasNonce { - // verify nonce to mitigate replay attacks - hash := fmt.Sprintf("%x", sha256.Sum256([]byte(params.Nonce))) - if hash != idToken.Nonce { - return oauthError("invalid nonce", "Nonces mismatch") + if !oauthConfig.SkipNonceCheck { + tokenHasNonce := idToken.Nonce != "" + paramsHasNonce := params.Nonce != "" + + if tokenHasNonce != paramsHasNonce { + return oauthError("invalid request", "Passed nonce and nonce in id_token should either both exist or not.") + } else if tokenHasNonce && paramsHasNonce { + // verify nonce to mitigate replay attacks + hash := fmt.Sprintf("%x", sha256.Sum256([]byte(params.Nonce))) + if hash != idToken.Nonce { + return oauthError("invalid nonce", "Nonces mismatch") + } } } diff --git a/internal/conf/configuration.go b/internal/conf/configuration.go index bc865d539..df8a4c0f9 100644 --- a/internal/conf/configuration.go +++ b/internal/conf/configuration.go @@ -41,12 +41,13 @@ func (t *Time) UnmarshalText(text []byte) error { // OAuthProviderConfiguration holds all config related to external account providers. type OAuthProviderConfiguration struct { - ClientID []string `json:"client_id" split_words:"true"` - Secret string `json:"secret"` - RedirectURI string `json:"redirect_uri" split_words:"true"` - URL string `json:"url"` - ApiURL string `json:"api_url" split_words:"true"` - Enabled bool `json:"enabled"` + ClientID []string `json:"client_id" split_words:"true"` + Secret string `json:"secret"` + RedirectURI string `json:"redirect_uri" split_words:"true"` + URL string `json:"url"` + ApiURL string `json:"api_url" split_words:"true"` + Enabled bool `json:"enabled"` + SkipNonceCheck bool `json:"skip_nonce_check" split_words:"true"` } type EmailProviderConfiguration struct {