Files
wonderwall/pkg/config/openid.go
Trong Huu Nguyen da69847027 feat(openid): add opt-in toggle for typ header in accordance with RFC7523bis
Some providers require that the `typ` header has a value exactly equal
to `client-authentication+jwt` in accordance with changes introduced by
RFC7523bis.

This commit allows for opting in to setting the `typ` header with this new value.

The default behaviour is to use the previous de facto standard value, `JWT`.
Once the changes in RFC7523bis lands in the affected standards and
identity providers start supporting the new `typ` header (Entra ID being
notable for not supporting this as of this commit), we will default to
use `client-authentication+jwt`.
2025-08-26 08:29:27 +02:00

105 lines
4.7 KiB
Go

package config
import (
"fmt"
"github.com/lestrrat-go/jwx/v3/jwa"
flag "github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/nais/wonderwall/pkg/openid/acr"
)
type Provider string
const (
ProviderAzure Provider = "azure"
ProviderIDPorten Provider = "idporten"
ProviderOpenID Provider = "openid"
)
type OpenID struct {
ACRValues string `json:"acr-values"`
Audiences []string `json:"audiences"`
ClientID string `json:"client-id"`
ClientJWK string `json:"client-jwk"`
ClientSecret string `json:"client-secret"`
IDTokenSigningAlg string `json:"id-token-signing-alg"`
NewClientAuthJWTType bool `json:"new-client-auth-jwt-type"`
PostLogoutRedirectURI string `json:"post-logout-redirect-uri"`
Provider Provider `json:"provider"`
ResourceIndicator string `json:"resource-indicator"`
Scopes []string `json:"scopes"`
UILocales string `json:"ui-locales"`
WellKnownURL string `json:"well-known-url"`
}
func (in OpenID) TrustedAudiences() map[string]bool {
m := make(map[string]bool)
m[in.ClientID] = true
for _, aud := range in.Audiences {
m[aud] = true
}
return m
}
func (in OpenID) Validate() error {
_, ok := jwa.LookupSignatureAlgorithm(in.IDTokenSigningAlg)
if !ok {
return fmt.Errorf("invalid id_token signing algorithm: %q, must be one of %s", in.IDTokenSigningAlg, jwa.SignatureAlgorithms())
}
return nil
}
const (
OpenIDACRValues = "openid.acr-values"
OpenIDAudiences = "openid.audiences"
OpenIDClientID = "openid.client-id"
OpenIDClientJWK = "openid.client-jwk"
OpenIDClientSecret = "openid.client-secret"
OpenIDNewClientAuthJWTType = "openid.new-client-auth-jwt-type"
OpenIDIDTokenSigningAlg = "openid.id-token-signing-alg"
OpenIDPostLogoutRedirectURI = "openid.post-logout-redirect-uri"
OpenIDProvider = "openid.provider"
OpenIDResourceIndicator = "openid.resource-indicator"
OpenIDScopes = "openid.scopes"
OpenIDUILocales = "openid.ui-locales"
OpenIDWellKnownURL = "openid.well-known-url"
)
func openidFlags() {
flag.String(OpenIDACRValues, "", "Space separated string that configures the default security level (acr_values) parameter for authorization requests.")
flag.StringSlice(OpenIDAudiences, []string{}, "List of additional trusted audiences (other than the client_id) for OpenID Connect id_token validation.")
flag.String(OpenIDClientID, "", "Client ID for the OpenID client.")
flag.String(OpenIDClientJWK, "", "JWK containing the private key for the OpenID client in string format. If configured, this takes precedence over 'openid.client-secret'.")
flag.String(OpenIDClientSecret, "", "Client secret for the OpenID client. Overridden by 'openid.client-jwk', if configured.")
flag.String(OpenIDIDTokenSigningAlg, jwa.RS256().String(), "Expected JWA value (as defined in RFC 7518) of public keys for validating id_token signatures. This only applies where the key's 'alg' header is not set.")
flag.Bool(OpenIDNewClientAuthJWTType, false, "When enabled, sets the value of the \"typ\" header of the JWT used for client authentication equal to \"client-authentication+jwt\" in accordance with RFC7523bis. If not enabled, the value is set to \"JWT\".")
flag.String(OpenIDPostLogoutRedirectURI, "", "URI for redirecting the user after successful logout at the Identity Provider.")
flag.String(OpenIDProvider, string(ProviderOpenID), "Provider configuration to load and use, either 'openid', 'azure', 'idporten'.")
flag.String(OpenIDResourceIndicator, "", "OAuth2 resource indicator to include in authorization request for acquiring audience-restricted tokens.")
flag.StringSlice(OpenIDScopes, []string{}, "Comma separated list of additional scopes (other than 'openid') that should be used during the login flow.")
flag.String(OpenIDUILocales, "", "Space-separated string that configures the default UI locale (ui_locales) parameter for OAuth2 consent screen.")
flag.String(OpenIDWellKnownURL, "", "URI to the well-known OpenID Configuration metadata document.")
}
func resolveOpenIdProvider() {
switch Provider(viper.GetString(OpenIDProvider)) {
case ProviderIDPorten:
viper.BindEnv(OpenIDClientID, "IDPORTEN_CLIENT_ID")
viper.BindEnv(OpenIDClientJWK, "IDPORTEN_CLIENT_JWK")
viper.BindEnv(OpenIDWellKnownURL, "IDPORTEN_WELL_KNOWN_URL")
viper.SetDefault(OpenIDACRValues, acr.IDPortenLevelHigh)
viper.SetDefault(OpenIDUILocales, "nb")
case ProviderAzure:
viper.BindEnv(OpenIDClientID, "AZURE_APP_CLIENT_ID")
viper.BindEnv(OpenIDClientJWK, "AZURE_APP_JWK")
viper.BindEnv(OpenIDWellKnownURL, "AZURE_APP_WELL_KNOWN_URL")
default:
viper.Set(OpenIDProvider, ProviderOpenID)
}
}