diff --git a/docs/configuration/identity-providers/oidc.md b/docs/configuration/identity-providers/oidc.md index f29df5665..c70c4b2dd 100644 --- a/docs/configuration/identity-providers/oidc.md +++ b/docs/configuration/identity-providers/oidc.md @@ -469,15 +469,16 @@ particularly those that don't use [discovery](https://openid.net/specs/openid-co appended to the end of the primary URL used to access Authelia. For example in the Discovery example provided you access Authelia via https://auth.example.com, the discovery URL is https://auth.example.com/.well-known/openid-configuration. -| Endpoint | Path | -|:-------------:|:--------------------------------:| -| Discovery | .well-known/openid-configuration | -| JWKS | api/oidc/jwks | -| Authorization | api/oidc/authorize | -| Token | api/oidc/token | -| Introspection | api/oidc/introspect | -| Revocation | api/oidc/revoke | -| Userinfo | api/oidc/userinfo | +| Endpoint | Path | +|:-------------:|:---------------------------------------------:| +| Discovery | [root]/.well-known/openid-configuration | +| Metadata | [root]/.well-known/oauth-authorization-server | +| JWKS | [root]/api/oidc/jwks | +| Authorization | [root]/api/oidc/authorization | +| Token | [root]/api/oidc/token | +| Introspection | [root]/api/oidc/introspection | +| Revocation | [root]/api/oidc/revocation | +| Userinfo | [root]/api/oidc/userinfo | [OpenID Connect]: https://openid.net/connect/ [token lifespan]: https://docs.apigee.com/api-platform/antipatterns/oauth-long-expiration diff --git a/internal/handlers/const.go b/internal/handlers/const.go index 795ab1012..1b266f66f 100644 --- a/internal/handlers/const.go +++ b/internal/handlers/const.go @@ -73,14 +73,9 @@ const ( // OIDC constants. const ( - pathOpenIDConnectWellKnown = "/.well-known/openid-configuration" - - pathOpenIDConnectJWKs = "/api/oidc/jwks" - pathOpenIDConnectAuthorization = "/api/oidc/authorize" - pathOpenIDConnectToken = "/api/oidc/token" //nolint:gosec // This is not a hard coded credential, it's a path. - pathOpenIDConnectIntrospection = "/api/oidc/introspect" - pathOpenIDConnectRevocation = "/api/oidc/revoke" - pathOpenIDConnectUserinfo = "/api/oidc/userinfo" + pathLegacyOpenIDConnectAuthorization = "/api/oidc/authorize" + pathLegacyOpenIDConnectIntrospection = "/api/oidc/introspect" + pathLegacyOpenIDConnectRevocation = "/api/oidc/revoke" // Note: If you change this const you must also do so in the frontend at web/src/services/Api.ts. pathOpenIDConnectConsent = "/api/oidc/consent" diff --git a/internal/handlers/handler_oidc_wellknown.go b/internal/handlers/handler_oidc_wellknown.go index 6afe1f59b..3a5196c23 100644 --- a/internal/handlers/handler_oidc_wellknown.go +++ b/internal/handlers/handler_oidc_wellknown.go @@ -2,15 +2,13 @@ package handlers import ( "encoding/json" - "fmt" "github.com/valyala/fasthttp" "github.com/authelia/authelia/v4/internal/middlewares" - "github.com/authelia/authelia/v4/internal/oidc" ) -func oidcWellKnown(ctx *middlewares.AutheliaCtx) { +func wellKnownOpenIDConnectConfigurationGET(ctx *middlewares.AutheliaCtx) { issuer, err := ctx.ExternalRootURL() if err != nil { ctx.Logger.Errorf("Error occurred determining OpenID Connect issuer details: %+v", err) @@ -19,77 +17,33 @@ func oidcWellKnown(ctx *middlewares.AutheliaCtx) { return } - wellKnown := oidc.WellKnownConfiguration{ - Issuer: issuer, - JWKSURI: fmt.Sprintf("%s%s", issuer, pathOpenIDConnectJWKs), - - AuthorizationEndpoint: fmt.Sprintf("%s%s", issuer, pathOpenIDConnectAuthorization), - TokenEndpoint: fmt.Sprintf("%s%s", issuer, pathOpenIDConnectToken), - RevocationEndpoint: fmt.Sprintf("%s%s", issuer, pathOpenIDConnectRevocation), - UserinfoEndpoint: fmt.Sprintf("%s%s", issuer, pathOpenIDConnectUserinfo), - IntrospectionEndpoint: fmt.Sprintf("%s%s", issuer, pathOpenIDConnectIntrospection), - - Algorithms: []string{"RS256"}, - UserinfoAlgorithms: []string{"none", "RS256"}, - - SubjectTypesSupported: []string{ - "public", - }, - ResponseTypesSupported: []string{ - "code", - "token", - "id_token", - "code token", - "code id_token", - "token id_token", - "code token id_token", - "none", - }, - ResponseModesSupported: []string{ - "form_post", - "query", - "fragment", - }, - ScopesSupported: []string{ - "offline_access", - oidc.ScopeOpenID, - oidc.ScopeProfile, - oidc.ScopeGroups, - oidc.ScopeEmail, - }, - ClaimsSupported: []string{ - "aud", - "exp", - "iat", - "iss", - "jti", - "rat", - "sub", - "auth_time", - "nonce", - oidc.ClaimEmail, - oidc.ClaimEmailVerified, - oidc.ClaimEmailAlts, - oidc.ClaimGroups, - oidc.ClaimPreferredUsername, - oidc.ClaimDisplayName, - }, - CodeChallengeMethodsSupported: []string{"S256"}, - - RequestURIParameterSupported: false, - BackChannelLogoutSupported: false, - FrontChannelLogoutSupported: false, - BackChannelLogoutSessionSupported: false, - FrontChannelLogoutSessionSupported: false, - } - - if ctx.Configuration.IdentityProviders.OIDC.EnablePKCEPlainChallenge { - wellKnown.CodeChallengeMethodsSupported = append(wellKnown.CodeChallengeMethodsSupported, "plain") - } + wellKnown := ctx.Providers.OpenIDConnect.GetOpenIDConnectWellKnownConfiguration(issuer) ctx.SetContentType("application/json") - if err := json.NewEncoder(ctx).Encode(wellKnown); err != nil { + if err = json.NewEncoder(ctx).Encode(wellKnown); err != nil { + ctx.Logger.Errorf("Error occurred in JSON encode: %+v", err) + // TODO: Determine if this is the appropriate error code here. + ctx.Response.SetStatusCode(fasthttp.StatusInternalServerError) + + return + } +} + +func wellKnownOAuthAuthorizationServerGET(ctx *middlewares.AutheliaCtx) { + issuer, err := ctx.ExternalRootURL() + if err != nil { + ctx.Logger.Errorf("Error occurred determining OpenID Connect issuer details: %+v", err) + ctx.Response.SetStatusCode(fasthttp.StatusBadRequest) + + return + } + + wellKnown := ctx.Providers.OpenIDConnect.GetOAuth2WellKnownConfiguration(issuer) + + ctx.SetContentType("application/json") + + if err = json.NewEncoder(ctx).Encode(wellKnown); err != nil { ctx.Logger.Errorf("Error occurred in JSON encode: %+v", err) // TODO: Determine if this is the appropriate error code here. ctx.Response.SetStatusCode(fasthttp.StatusInternalServerError) diff --git a/internal/handlers/oidc_register.go b/internal/handlers/oidc_register.go index 3b9d78a2c..63af0362c 100644 --- a/internal/handlers/oidc_register.go +++ b/internal/handlers/oidc_register.go @@ -4,29 +4,34 @@ import ( "github.com/fasthttp/router" "github.com/authelia/authelia/v4/internal/middlewares" + "github.com/authelia/authelia/v4/internal/oidc" ) -// RegisterOIDC registers the handlers with the fasthttp *router.Router. TODO: Add paths for UserInfo, Flush, Logout. +// RegisterOIDC registers the handlers with the fasthttp *router.Router. TODO: Add paths for Flush, Logout. func RegisterOIDC(router *router.Router, middleware middlewares.RequestHandlerBridge) { // TODO: Add OPTIONS handler. - router.GET(pathOpenIDConnectWellKnown, middleware(oidcWellKnown)) + router.GET(oidc.WellKnownOpenIDConfigurationPath, middleware(wellKnownOpenIDConnectConfigurationGET)) + router.GET(oidc.WellKnownOAuthAuthorizationServerPath, middleware(wellKnownOAuthAuthorizationServerGET)) router.GET(pathOpenIDConnectConsent, middleware(oidcConsent)) router.POST(pathOpenIDConnectConsent, middleware(oidcConsentPOST)) - router.GET(pathOpenIDConnectJWKs, middleware(oidcJWKs)) + router.GET(oidc.JWKsPath, middleware(oidcJWKs)) - router.GET(pathOpenIDConnectAuthorization, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcAuthorization))) + router.GET(oidc.AuthorizationPath, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcAuthorization))) + router.GET(pathLegacyOpenIDConnectAuthorization, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcAuthorization))) // TODO: Add OPTIONS handler. - router.POST(pathOpenIDConnectToken, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcToken))) + router.POST(oidc.TokenPath, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcToken))) - router.POST(pathOpenIDConnectIntrospection, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcIntrospection))) + router.POST(oidc.IntrospectionPath, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcIntrospection))) + router.GET(pathLegacyOpenIDConnectIntrospection, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcIntrospection))) - router.GET(pathOpenIDConnectUserinfo, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcUserinfo))) - router.POST(pathOpenIDConnectUserinfo, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcUserinfo))) + router.GET(oidc.UserinfoPath, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcUserinfo))) + router.POST(oidc.UserinfoPath, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcUserinfo))) // TODO: Add OPTIONS handler. - router.POST(pathOpenIDConnectRevocation, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcRevocation))) + router.POST(oidc.RevocationPath, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcRevocation))) + router.POST(pathLegacyOpenIDConnectRevocation, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(oidcRevocation))) } diff --git a/internal/oidc/const.go b/internal/oidc/const.go index b084a3b53..db43595ff 100644 --- a/internal/oidc/const.go +++ b/internal/oidc/const.go @@ -2,10 +2,11 @@ package oidc // Scope strings. const ( - ScopeOpenID = "openid" - ScopeProfile = "profile" - ScopeEmail = "email" - ScopeGroups = "groups" + ScopeOfflineAccess = "offline_access" + ScopeOpenID = "openid" + ScopeProfile = "profile" + ScopeEmail = "email" + ScopeGroups = "groups" ) // Claim strings. @@ -17,3 +18,16 @@ const ( ClaimEmailVerified = "email_verified" ClaimEmailAlts = "alt_emails" ) + +// Paths. +const ( + WellKnownOpenIDConfigurationPath = "/.well-known/openid-configuration" + WellKnownOAuthAuthorizationServerPath = "/.well-known/oauth-authorization-server" + + JWKsPath = "/api/oidc/jwks" + AuthorizationPath = "/api/oidc/authorization" + TokenPath = "/api/oidc/token" //nolint:gosec // This is not a hard coded credential, it's a path. + IntrospectionPath = "/api/oidc/introspection" + RevocationPath = "/api/oidc/revocation" + UserinfoPath = "/api/oidc/userinfo" +) diff --git a/internal/oidc/provider.go b/internal/oidc/provider.go index b8b3bc2d8..862ddce64 100644 --- a/internal/oidc/provider.go +++ b/internal/oidc/provider.go @@ -1,6 +1,7 @@ package oidc import ( + "fmt" "net/http" "github.com/ory/fosite/compose" @@ -88,6 +89,75 @@ func NewOpenIDConnectProvider(configuration *schema.OpenIDConnectConfiguration) compose.OAuth2PKCEFactory, ) + provider.discovery = OpenIDConnectWellKnownConfiguration{ + CommonDiscoveryOptions: CommonDiscoveryOptions{ + SubjectTypesSupported: []string{ + "public", + }, + ResponseTypesSupported: []string{ + "code", + "token", + "id_token", + "code token", + "code id_token", + "token id_token", + "code token id_token", + "none", + }, + ResponseModesSupported: []string{ + "form_post", + "query", + "fragment", + }, + ScopesSupported: []string{ + ScopeOfflineAccess, + ScopeOpenID, + ScopeProfile, + ScopeGroups, + ScopeEmail, + }, + ClaimsSupported: []string{ + "aud", + "exp", + "iat", + "iss", + "jti", + "rat", + "sub", + "auth_time", + "nonce", + ClaimEmail, + ClaimEmailVerified, + ClaimEmailAlts, + ClaimGroups, + ClaimPreferredUsername, + ClaimDisplayName, + }, + }, + OAuth2DiscoveryOptions: OAuth2DiscoveryOptions{ + CodeChallengeMethodsSupported: []string{ + "S256", + }, + }, + OpenIDConnectDiscoveryOptions: OpenIDConnectDiscoveryOptions{ + IDTokenSigningAlgValuesSupported: []string{ + "RS256", + }, + UserinfoSigningAlgValuesSupported: []string{ + "none", + "RS256", + }, + RequestObjectSigningAlgValuesSupported: []string{ + "none", + "RS256", + }, + }, + } + + if configuration.EnablePKCEPlainChallenge { + provider.discovery.CodeChallengeMethodsSupported = append(provider.discovery.CodeChallengeMethodsSupported, "plain") + } + provider.herodot = herodot.NewJSONWriter(nil) return provider, nil @@ -107,3 +177,45 @@ func (p OpenIDConnectProvider) WriteError(w http.ResponseWriter, r *http.Request func (p OpenIDConnectProvider) WriteErrorCode(w http.ResponseWriter, r *http.Request, code int, err error, opts ...herodot.Option) { p.herodot.WriteErrorCode(w, r, code, err, opts...) } + +// GetOAuth2WellKnownConfiguration returns the discovery document for the OAuth Configuration. +func (p OpenIDConnectProvider) GetOAuth2WellKnownConfiguration(issuer string) OAuth2WellKnownConfiguration { + options := OAuth2WellKnownConfiguration{ + CommonDiscoveryOptions: p.discovery.CommonDiscoveryOptions, + OAuth2DiscoveryOptions: p.discovery.OAuth2DiscoveryOptions, + } + + options.Issuer = issuer + options.JWKSURI = fmt.Sprintf("%s%s", issuer, JWKsPath) + + options.IntrospectionEndpoint = fmt.Sprintf("%s%s", issuer, IntrospectionPath) + options.TokenEndpoint = fmt.Sprintf("%s%s", issuer, TokenPath) + + options.AuthorizationEndpoint = fmt.Sprintf("%s%s", issuer, AuthorizationPath) + options.RevocationEndpoint = fmt.Sprintf("%s%s", issuer, RevocationPath) + + return options +} + +// GetOpenIDConnectWellKnownConfiguration returns the discovery document for the OpenID Configuration. +func (p OpenIDConnectProvider) GetOpenIDConnectWellKnownConfiguration(issuer string) OpenIDConnectWellKnownConfiguration { + options := OpenIDConnectWellKnownConfiguration{ + CommonDiscoveryOptions: p.discovery.CommonDiscoveryOptions, + OAuth2DiscoveryOptions: p.discovery.OAuth2DiscoveryOptions, + OpenIDConnectDiscoveryOptions: p.discovery.OpenIDConnectDiscoveryOptions, + OpenIDConnectFrontChannelLogoutDiscoveryOptions: p.discovery.OpenIDConnectFrontChannelLogoutDiscoveryOptions, + OpenIDConnectBackChannelLogoutDiscoveryOptions: p.discovery.OpenIDConnectBackChannelLogoutDiscoveryOptions, + } + + options.Issuer = issuer + options.JWKSURI = fmt.Sprintf("%s%s", issuer, JWKsPath) + + options.IntrospectionEndpoint = fmt.Sprintf("%s%s", issuer, IntrospectionPath) + options.TokenEndpoint = fmt.Sprintf("%s%s", issuer, TokenPath) + + options.AuthorizationEndpoint = fmt.Sprintf("%s%s", issuer, AuthorizationPath) + options.RevocationEndpoint = fmt.Sprintf("%s%s", issuer, RevocationPath) + options.UserinfoEndpoint = fmt.Sprintf("%s%s", issuer, UserinfoPath) + + return options +} diff --git a/internal/oidc/provider_test.go b/internal/oidc/provider_test.go index 4a8cc71de..c8bfba7d1 100644 --- a/internal/oidc/provider_test.go +++ b/internal/oidc/provider_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/authelia/authelia/v4/internal/configuration/schema" ) @@ -64,3 +65,189 @@ func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GoodConfiguration(t *tes assert.NotNil(t, provider) assert.NoError(t, err) } + +func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GetOpenIDConnectWellKnownConfiguration(t *testing.T) { + provider, err := NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{ + IssuerPrivateKey: exampleIssuerPrivateKey, + HMACSecret: "asbdhaaskmdlkamdklasmdlkams", + Clients: []schema.OpenIDConnectClientConfiguration{ + { + ID: "a-client", + Secret: "a-client-secret", + Policy: "one_factor", + RedirectURIs: []string{ + "https://google.com", + }, + }, + }, + }) + + assert.NoError(t, err) + + disco := provider.GetOpenIDConnectWellKnownConfiguration("https://example.com") + + assert.Equal(t, "https://example.com", disco.Issuer) + assert.Equal(t, "https://example.com/api/oidc/jwks", disco.JWKSURI) + assert.Equal(t, "https://example.com/api/oidc/authorization", disco.AuthorizationEndpoint) + assert.Equal(t, "https://example.com/api/oidc/token", disco.TokenEndpoint) + assert.Equal(t, "https://example.com/api/oidc/userinfo", disco.UserinfoEndpoint) + assert.Equal(t, "https://example.com/api/oidc/introspection", disco.IntrospectionEndpoint) + assert.Equal(t, "https://example.com/api/oidc/revocation", disco.RevocationEndpoint) + assert.Equal(t, "", disco.RegistrationEndpoint) + + require.Len(t, disco.CodeChallengeMethodsSupported, 1) + assert.Equal(t, "S256", disco.CodeChallengeMethodsSupported[0]) + + assert.Len(t, disco.ScopesSupported, 5) + assert.Contains(t, disco.ScopesSupported, ScopeOpenID) + assert.Contains(t, disco.ScopesSupported, ScopeOfflineAccess) + assert.Contains(t, disco.ScopesSupported, ScopeProfile) + assert.Contains(t, disco.ScopesSupported, ScopeGroups) + assert.Contains(t, disco.ScopesSupported, ScopeEmail) + + assert.Len(t, disco.ResponseModesSupported, 3) + assert.Contains(t, disco.ResponseModesSupported, "form_post") + assert.Contains(t, disco.ResponseModesSupported, "query") + assert.Contains(t, disco.ResponseModesSupported, "fragment") + + assert.Len(t, disco.SubjectTypesSupported, 1) + assert.Contains(t, disco.SubjectTypesSupported, "public") + + assert.Len(t, disco.ResponseTypesSupported, 8) + assert.Contains(t, disco.ResponseTypesSupported, "code") + assert.Contains(t, disco.ResponseTypesSupported, "token") + assert.Contains(t, disco.ResponseTypesSupported, "id_token") + assert.Contains(t, disco.ResponseTypesSupported, "code token") + assert.Contains(t, disco.ResponseTypesSupported, "code id_token") + assert.Contains(t, disco.ResponseTypesSupported, "token id_token") + assert.Contains(t, disco.ResponseTypesSupported, "code token id_token") + assert.Contains(t, disco.ResponseTypesSupported, "none") + + assert.Len(t, disco.IDTokenSigningAlgValuesSupported, 1) + assert.Contains(t, disco.IDTokenSigningAlgValuesSupported, "RS256") + + assert.Len(t, disco.UserinfoSigningAlgValuesSupported, 2) + assert.Contains(t, disco.UserinfoSigningAlgValuesSupported, "RS256") + assert.Contains(t, disco.UserinfoSigningAlgValuesSupported, "none") + + assert.Len(t, disco.RequestObjectSigningAlgValuesSupported, 2) + assert.Contains(t, disco.RequestObjectSigningAlgValuesSupported, "RS256") + assert.Contains(t, disco.RequestObjectSigningAlgValuesSupported, "none") + + assert.Len(t, disco.ClaimsSupported, 15) + assert.Contains(t, disco.ClaimsSupported, "aud") + assert.Contains(t, disco.ClaimsSupported, "exp") + assert.Contains(t, disco.ClaimsSupported, "iat") + assert.Contains(t, disco.ClaimsSupported, "iss") + assert.Contains(t, disco.ClaimsSupported, "jti") + assert.Contains(t, disco.ClaimsSupported, "rat") + assert.Contains(t, disco.ClaimsSupported, "sub") + assert.Contains(t, disco.ClaimsSupported, "auth_time") + assert.Contains(t, disco.ClaimsSupported, "nonce") + assert.Contains(t, disco.ClaimsSupported, ClaimEmail) + assert.Contains(t, disco.ClaimsSupported, ClaimEmailVerified) + assert.Contains(t, disco.ClaimsSupported, ClaimEmailAlts) + assert.Contains(t, disco.ClaimsSupported, ClaimGroups) + assert.Contains(t, disco.ClaimsSupported, ClaimPreferredUsername) + assert.Contains(t, disco.ClaimsSupported, ClaimDisplayName) +} + +func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GetOAuth2WellKnownConfiguration(t *testing.T) { + provider, err := NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{ + IssuerPrivateKey: exampleIssuerPrivateKey, + HMACSecret: "asbdhaaskmdlkamdklasmdlkams", + Clients: []schema.OpenIDConnectClientConfiguration{ + { + ID: "a-client", + Secret: "a-client-secret", + Policy: "one_factor", + RedirectURIs: []string{ + "https://google.com", + }, + }, + }, + }) + + assert.NoError(t, err) + + disco := provider.GetOAuth2WellKnownConfiguration("https://example.com") + + assert.Equal(t, "https://example.com", disco.Issuer) + assert.Equal(t, "https://example.com/api/oidc/jwks", disco.JWKSURI) + assert.Equal(t, "https://example.com/api/oidc/authorization", disco.AuthorizationEndpoint) + assert.Equal(t, "https://example.com/api/oidc/token", disco.TokenEndpoint) + assert.Equal(t, "https://example.com/api/oidc/introspection", disco.IntrospectionEndpoint) + assert.Equal(t, "https://example.com/api/oidc/revocation", disco.RevocationEndpoint) + assert.Equal(t, "", disco.RegistrationEndpoint) + + require.Len(t, disco.CodeChallengeMethodsSupported, 1) + assert.Equal(t, "S256", disco.CodeChallengeMethodsSupported[0]) + + assert.Len(t, disco.ScopesSupported, 5) + assert.Contains(t, disco.ScopesSupported, ScopeOpenID) + assert.Contains(t, disco.ScopesSupported, ScopeOfflineAccess) + assert.Contains(t, disco.ScopesSupported, ScopeProfile) + assert.Contains(t, disco.ScopesSupported, ScopeGroups) + assert.Contains(t, disco.ScopesSupported, ScopeEmail) + + assert.Len(t, disco.ResponseModesSupported, 3) + assert.Contains(t, disco.ResponseModesSupported, "form_post") + assert.Contains(t, disco.ResponseModesSupported, "query") + assert.Contains(t, disco.ResponseModesSupported, "fragment") + + assert.Len(t, disco.SubjectTypesSupported, 1) + assert.Contains(t, disco.SubjectTypesSupported, "public") + + assert.Len(t, disco.ResponseTypesSupported, 8) + assert.Contains(t, disco.ResponseTypesSupported, "code") + assert.Contains(t, disco.ResponseTypesSupported, "token") + assert.Contains(t, disco.ResponseTypesSupported, "id_token") + assert.Contains(t, disco.ResponseTypesSupported, "code token") + assert.Contains(t, disco.ResponseTypesSupported, "code id_token") + assert.Contains(t, disco.ResponseTypesSupported, "token id_token") + assert.Contains(t, disco.ResponseTypesSupported, "code token id_token") + assert.Contains(t, disco.ResponseTypesSupported, "none") + + assert.Len(t, disco.ClaimsSupported, 15) + assert.Contains(t, disco.ClaimsSupported, "aud") + assert.Contains(t, disco.ClaimsSupported, "exp") + assert.Contains(t, disco.ClaimsSupported, "iat") + assert.Contains(t, disco.ClaimsSupported, "iss") + assert.Contains(t, disco.ClaimsSupported, "jti") + assert.Contains(t, disco.ClaimsSupported, "rat") + assert.Contains(t, disco.ClaimsSupported, "sub") + assert.Contains(t, disco.ClaimsSupported, "auth_time") + assert.Contains(t, disco.ClaimsSupported, "nonce") + assert.Contains(t, disco.ClaimsSupported, ClaimEmail) + assert.Contains(t, disco.ClaimsSupported, ClaimEmailVerified) + assert.Contains(t, disco.ClaimsSupported, ClaimEmailAlts) + assert.Contains(t, disco.ClaimsSupported, ClaimGroups) + assert.Contains(t, disco.ClaimsSupported, ClaimPreferredUsername) + assert.Contains(t, disco.ClaimsSupported, ClaimDisplayName) +} + +func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GetOpenIDConnectWellKnownConfigurationWithPlainPKCE(t *testing.T) { + provider, err := NewOpenIDConnectProvider(&schema.OpenIDConnectConfiguration{ + IssuerPrivateKey: exampleIssuerPrivateKey, + HMACSecret: "asbdhaaskmdlkamdklasmdlkams", + EnablePKCEPlainChallenge: true, + Clients: []schema.OpenIDConnectClientConfiguration{ + { + ID: "a-client", + Secret: "a-client-secret", + Policy: "one_factor", + RedirectURIs: []string{ + "https://google.com", + }, + }, + }, + }) + + assert.NoError(t, err) + + disco := provider.GetOpenIDConnectWellKnownConfiguration("https://example.com") + + require.Len(t, disco.CodeChallengeMethodsSupported, 2) + assert.Equal(t, "S256", disco.CodeChallengeMethodsSupported[0]) + assert.Equal(t, "plain", disco.CodeChallengeMethodsSupported[1]) +} diff --git a/internal/oidc/types.go b/internal/oidc/types.go index c52b9ac3e..007561789 100644 --- a/internal/oidc/types.go +++ b/internal/oidc/types.go @@ -19,6 +19,8 @@ type OpenIDConnectProvider struct { KeyManager *KeyManager herodot *herodot.JSONWriter + + discovery OpenIDConnectWellKnownConfiguration } // OpenIDConnectStore is Authelia's internal representation of the fosite.Storage interface. @@ -70,36 +72,6 @@ type ConsentGetResponseBody struct { Audience []string `json:"audience"` } -// WellKnownConfiguration is the OIDC well known config struct. -// -// See https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata -type WellKnownConfiguration struct { - Issuer string `json:"issuer"` - JWKSURI string `json:"jwks_uri"` - - AuthorizationEndpoint string `json:"authorization_endpoint"` - TokenEndpoint string `json:"token_endpoint"` - RevocationEndpoint string `json:"revocation_endpoint"` - UserinfoEndpoint string `json:"userinfo_endpoint"` - IntrospectionEndpoint string `json:"introspection_endpoint"` - - Algorithms []string `json:"id_token_signing_alg_values_supported"` - UserinfoAlgorithms []string `json:"userinfo_signing_alg_values_supported"` - - SubjectTypesSupported []string `json:"subject_types_supported"` - ResponseTypesSupported []string `json:"response_types_supported"` - ResponseModesSupported []string `json:"response_modes_supported"` - ScopesSupported []string `json:"scopes_supported"` - ClaimsSupported []string `json:"claims_supported"` - CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"` - - RequestURIParameterSupported bool `json:"request_uri_parameter_supported"` - BackChannelLogoutSupported bool `json:"backchannel_logout_supported"` - FrontChannelLogoutSupported bool `json:"frontchannel_logout_supported"` - BackChannelLogoutSessionSupported bool `json:"backchannel_logout_session_supported"` - FrontChannelLogoutSessionSupported bool `json:"frontchannel_logout_session_supported"` -} - // OpenIDSession holds OIDC Session information. type OpenIDSession struct { *openid.DefaultSession `json:"idToken"` @@ -107,3 +79,414 @@ type OpenIDSession struct { Extra map[string]interface{} `json:"extra"` ClientID string } + +/* +CommonDiscoveryOptions represents the discovery options used in both OAuth 2.0 and OpenID Connect. +See Also: + OpenID Connect Discovery: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata + OAuth 2.0 Discovery: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-discovery-10#section-2 +*/ +type CommonDiscoveryOptions struct { + /* + REQUIRED. URL using the https scheme with no query or fragment component that the OP asserts as its Issuer + Identifier. If Issuer discovery is supported (see Section 2), this value MUST be identical to the issuer value + returned by WebFinger. This also MUST be identical to the iss Claim value in ID Tokens issued from this Issuer. + */ + Issuer string `json:"issuer"` + + /* + REQUIRED. URL of the OP's JSON Web Key Set [JWK] document. This contains the signing key(s) the RP uses to + validate signatures from the OP. The JWK Set MAY also contain the Server's encryption key(s), which are used by + RPs to encrypt requests to the Server. When both signing and encryption keys are made available, a use (Key Use) + parameter value is REQUIRED for all keys in the referenced JWK Set to indicate each key's intended usage. + Although some algorithms allow the same key to be used for both signatures and encryption, doing so is NOT + RECOMMENDED, as it is less secure. The JWK x5c parameter MAY be used to provide X.509 representations of keys + provided. When used, the bare key values MUST still be present and MUST match those in the certificate. + */ + JWKSURI string `json:"jwks_uri,omitempty"` + + /* + REQUIRED. URL of the OP's OAuth 2.0 Authorization Endpoint [OpenID.Core]. + See Also: + OpenID.Core: https://openid.net/specs/openid-connect-core-1_0.html + */ + AuthorizationEndpoint string `json:"authorization_endpoint"` + + /* + URL of the OP's OAuth 2.0 Token Endpoint [OpenID.Core]. This is REQUIRED unless only the Implicit Flow is used. + See Also: + OpenID.Core: https://openid.net/specs/openid-connect-core-1_0.html + */ + TokenEndpoint string `json:"token_endpoint,omitempty"` + + /* + REQUIRED. JSON array containing a list of the Subject Identifier types that this OP supports. Valid types + include pairwise and public. + */ + SubjectTypesSupported []string `json:"subject_types_supported"` + + /* + REQUIRED. JSON array containing a list of the OAuth 2.0 response_type values that this OP supports. Dynamic + OpenID Providers MUST support the code, id_token, and the token id_token Response Type values. + */ + ResponseTypesSupported []string `json:"response_types_supported"` + + /* + OPTIONAL. JSON array containing a list of the OAuth 2.0 Grant Type values that this OP supports. Dynamic OpenID + Providers MUST support the authorization_code and implicit Grant Type values and MAY support other Grant Types. + If omitted, the default value is ["authorization_code", "implicit"]. + */ + GrantTypesSupported []string `json:"grant_types_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the OAuth 2.0 response_mode values that this OP supports, as specified + in OAuth 2.0 Multiple Response Type Encoding Practices [OAuth.Responses]. If omitted, the default for Dynamic + OpenID Providers is ["query", "fragment"]. + */ + ResponseModesSupported []string `json:"response_modes_supported,omitempty"` + + /* + RECOMMENDED. JSON array containing a list of the OAuth 2.0 [RFC6749] scope values that this server supports. + The server MUST support the openid scope value. Servers MAY choose not to advertise some supported scope values + even when this parameter is used, although those defined in [OpenID.Core] SHOULD be listed, if supported. + See Also: + OAuth 2.0: https://datatracker.ietf.org/doc/html/rfc6749 + OpenID.Core: https://openid.net/specs/openid-connect-core-1_0.html + */ + ScopesSupported []string `json:"scopes_supported,omitempty"` + + /* + RECOMMENDED. JSON array containing a list of the Claim Names of the Claims that the OpenID Provider MAY be able + to supply values for. Note that for privacy or other reasons, this might not be an exhaustive list. + */ + ClaimsSupported []string `json:"claims_supported,omitempty"` + + /* + OPTIONAL. Languages and scripts supported for the user interface, represented as a JSON array of BCP47 [RFC5646] + language tag values. + See Also: + BCP47: https://datatracker.ietf.org/doc/html/rfc5646 + */ + UILocalesSupported []string `json:"ui_locales_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of Client Authentication methods supported by this Token Endpoint. The + options are client_secret_post, client_secret_basic, client_secret_jwt, and private_key_jwt, as described in + Section 9 of OpenID Connect Core 1.0 [OpenID.Core]. Other authentication methods MAY be defined by extensions. + If omitted, the default is client_secret_basic -- the HTTP Basic Authentication Scheme specified in Section + 2.3.1 of OAuth 2.0 [RFC6749]. + See Also: + OAuth 2.0: https://datatracker.ietf.org/doc/html/rfc6749 + OpenID.Core Section 9: https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication + */ + TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the JWS signing algorithms (alg values) supported by the Token Endpoint + for the signature on the JWT [JWT] used to authenticate the Client at the Token Endpoint for the private_key_jwt + and client_secret_jwt authentication methods. Servers SHOULD support RS256. The value none MUST NOT be used. + See Also: + JWT: https://datatracker.ietf.org/doc/html/rfc7519 + */ + TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported,omitempty"` + + /* + OPTIONAL. URL of a page containing human-readable information that developers might want or need to know when + using the OpenID Provider. In particular, if the OpenID Provider does not support Dynamic Client Registration, + then information on how to register Clients needs to be provided in this documentation. + */ + ServiceDocumentation string `json:"service_documentation,omitempty"` + + /* + OPTIONAL. URL that the OpenID Provider provides to the person registering the Client to read about the OP's + requirements on how the Relying Party can use the data provided by the OP. The registration process SHOULD + display this URL to the person registering the Client if it is given. + */ + OPPolicyURI string `json:"op_policy_uri,omitempty"` + + /* + OPTIONAL. URL that the OpenID Provider provides to the person registering the Client to read about OpenID + Provider's terms of service. The registration process SHOULD display this URL to the person registering the + Client if it is given. + */ + OPTOSURI string `json:"op_tos_uri,omitempty"` +} + +// OAuth2DiscoveryOptions represents the discovery options specific to OAuth 2.0. +type OAuth2DiscoveryOptions struct { + /* + OPTIONAL. URL of the authorization server's OAuth 2.0 introspection endpoint [RFC7662]. + See Also: + OAuth 2.0 Token Introspection: https://datatracker.ietf.org/doc/html/rfc7662 + */ + IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"` + + /* + OPTIONAL. URL of the authorization server's OAuth 2.0 revocation endpoint [RFC7009]. + See Also: + OAuth 2.0 Token Revocation: https://datatracker.ietf.org/doc/html/rfc7009 + */ + RevocationEndpoint string `json:"revocation_endpoint,omitempty"` + + /* + OPTIONAL. URL of the authorization server's OAuth 2.0 Dynamic Client Registration endpoint [RFC7591]. + See Also: + OAuth 2.0 Dynamic Client Registration Protocol: https://datatracker.ietf.org/doc/html/rfc7591 + */ + RegistrationEndpoint string `json:"registration_endpoint,omitempty"` + + /* + OPTIONAL. JSON array containing a list of client authentication methods supported by this introspection endpoint. + The valid client authentication method values are those registered in the IANA "OAuth Token Endpoint + Authentication Methods" registry [IANA.OAuth.Parameters] or those registered in the IANA "OAuth Access Token Types" + registry [IANA.OAuth.Parameters]. (These values are and will remain distinct, due to Section 7.2.) If omitted, + the set of supported authentication methods MUST be determined by other means. + See Also: + IANA.OAuth.Parameters: https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml + OAuth 2.0 Authorization Server Metadata - Updated Registration Instructions: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-discovery-10#section-7.2 + */ + IntrospectionEndpointAuthMethodsSupported []string `json:"introspection_endpoint_auth_methods_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of client authentication methods supported by this revocation endpoint. + The valid client authentication method values are those registered in the IANA "OAuth Token Endpoint + Authentication Methods" registry [IANA.OAuth.Parameters]. If omitted, the default is "client_secret_basic" -- + the HTTP Basic Authentication Scheme specified in Section 2.3.1 of OAuth 2.0 [RFC6749]. + See Also: + IANA.OAuth.Parameters: https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml + OAuth 2.0 - Client Password: https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1 + */ + RevocationEndpointAuthMethodsSupported []string `json:"revocation_endpoint_auth_methods_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the JWS signing algorithms ("alg" values) supported by the revocation + endpoint for the signature on the JWT [JWT] used to authenticate the client at the revocation endpoint for the + "private_key_jwt" and "client_secret_jwt" authentication methods. This metadata entry MUST be present if either + of these authentication methods are specified in the "revocation_endpoint_auth_methods_supported" entry. No + default algorithms are implied if this entry is omitted. The value "none" MUST NOT be used. + See Also: + JWT: https://datatracker.ietf.org/doc/html/rfc7519 + */ + RevocationEndpointAuthSigningAlgValuesSupported []string `json:"revocation_endpoint_auth_signing_alg_values_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the JWS signing algorithms ("alg" values) supported by the + introspection endpoint for the signature on the JWT [JWT] used to authenticate the client at the introspection + endpoint for the "private_key_jwt" and "client_secret_jwt" authentication methods. This metadata entry MUST be + present if either of these authentication methods are specified in the + "introspection_endpoint_auth_methods_supported" entry. No default algorithms are implied if this entry is omitted. + The value "none" MUST NOT be used. + See Also: + JWT: https://datatracker.ietf.org/doc/html/rfc7519 + */ + IntrospectionEndpointAuthSigningAlgValuesSupported []string `json:"introspection_endpoint_auth_signing_alg_values_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of PKCE [RFC7636] code challenge methods supported by this authorization + server. Code challenge method values are used in the "code_challenge_method" parameter defined in Section 4.3 of + [RFC7636]. The valid code challenge method values are those registered in the IANA "PKCE Code Challenge Methods" + registry [IANA.OAuth.Parameters]. If omitted, the authorization server does not support PKCE. + See Also: + PKCE: https://datatracker.ietf.org/doc/html/rfc7636 + IANA.OAuth.Parameters: https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml + */ + CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"` +} + +// OpenIDConnectDiscoveryOptions represents the discovery options specific to OpenID Connect. +type OpenIDConnectDiscoveryOptions struct { + /* + RECOMMENDED. URL of the OP's UserInfo Endpoint [OpenID.Core]. This URL MUST use the https scheme and MAY contain + port, path, and query parameter components. + See Also: + OpenID.Core: https://openid.net/specs/openid-connect-core-1_0.html + */ + UserinfoEndpoint string `json:"userinfo_endpoint,omitempty"` + + /* + REQUIRED. JSON array containing a list of the JWS signing algorithms (alg values) supported by the OP for the ID + Token to encode the Claims in a JWT [JWT]. The algorithm RS256 MUST be included. The value none MAY be supported, + but MUST NOT be used unless the Response Type used returns no ID Token from the Authorization Endpoint (such as + when using the Authorization Code Flow). + See Also: + JWT: https://datatracker.ietf.org/doc/html/rfc7519 + */ + IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the JWS [JWS] signing algorithms (alg values) [JWA] supported by the + UserInfo Endpoint to encode the Claims in a JWT [JWT]. The value none MAY be included. + See Also: + JWS: https://datatracker.ietf.org/doc/html/rfc7515 + JWA: https://datatracker.ietf.org/doc/html/rfc7518 + JWT: https://datatracker.ietf.org/doc/html/rfc7519 + */ + UserinfoSigningAlgValuesSupported []string `json:"userinfo_signing_alg_values_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the JWS signing algorithms (alg values) supported by the OP for Request + Objects, which are described in Section 6.1 of OpenID Connect Core 1.0 [OpenID.Core]. These algorithms are used + both when the Request Object is passed by value (using the request parameter) and when it is passed by reference + (using the request_uri parameter). Servers SHOULD support none and RS256. + */ + RequestObjectSigningAlgValuesSupported []string `json:"request_object_signing_alg_values_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the JWE encryption algorithms (alg values) supported by the OP for the + ID Token to encode the Claims in a JWT [JWT]. + See Also: + JWE: https://datatracker.ietf.org/doc/html/rfc7516 + JWT: https://datatracker.ietf.org/doc/html/rfc7519 + */ + IDTokenEncryptionAlgValuesSupported []string `json:"id_token_encryption_alg_values_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the JWE [JWE] encryption algorithms (alg values) [JWA] supported by + the UserInfo Endpoint to encode the Claims in a JWT [JWT]. + See Also: + JWE: https://datatracker.ietf.org/doc/html/rfc7516 + JWA: https://datatracker.ietf.org/doc/html/rfc7518 + JWT: https://datatracker.ietf.org/doc/html/rfc7519 + */ + UserinfoEncryptionAlgValuesSupported []string `json:"userinfo_encryption_alg_values_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the JWE encryption algorithms (alg values) supported by the OP for + Request Objects. These algorithms are used both when the Request Object is passed by value and when it is passed + by reference. + See Also: + JWE: https://datatracker.ietf.org/doc/html/rfc7516 + */ + RequestObjectEncryptionAlgValuesSupported []string `json:"request_object_encryption_alg_values_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the JWE encryption algorithms (enc values) supported by the OP for the + ID Token to encode the Claims in a JWT [JWT]. + See Also: + JWE: https://datatracker.ietf.org/doc/html/rfc7516 + JWT: https://datatracker.ietf.org/doc/html/rfc7519 + */ + IDTokenEncryptionEncValuesSupported []string `json:"id_token_encryption_enc_values_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the JWE encryption algorithms (enc values) [JWA] supported by the + UserInfo Endpoint to encode the Claims in a JWT [JWT]. + See Also: + JWE: https://datatracker.ietf.org/doc/html/rfc7516 + JWA: https://datatracker.ietf.org/doc/html/rfc7518 + JWT: https://datatracker.ietf.org/doc/html/rfc7519 + */ + UserinfoEncryptionEncValuesSupported []string `json:"userinfo_encryption_enc_values_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the JWE encryption algorithms (enc values) supported by the OP for + Request Objects. These algorithms are used both when the Request Object is passed by value and when it is passed + by reference. + See Also: + JWE: https://datatracker.ietf.org/doc/html/rfc7516 + JWT: https://datatracker.ietf.org/doc/html/rfc7519 + */ + RequestObjectEncryptionEncValuesSupported []string `json:"request_object_encryption_enc_values_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the Authentication Context Class References that this OP supports. + */ + ACRValuesSupported []string `json:"acr_values_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the display parameter values that the OpenID Provider supports. These + values are described in Section 3.1.2.1 of OpenID Connect Core 1.0 [OpenID.Core]. + See Also: + OpenID.Core Section 3.1.2.1: https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest + */ + DisplayValuesSupported []string `json:"display_values_supported,omitempty"` + + /* + OPTIONAL. JSON array containing a list of the Claim Types that the OpenID Provider supports. These Claim Types + are described in Section 5.6 of OpenID Connect Core 1.0 [OpenID.Core]. Values defined by this specification are + normal, aggregated, and distributed. If omitted, the implementation supports only normal Claims. + See Also: + OpenID.Core Section 5.6: https://openid.net/specs/openid-connect-core-1_0.html#ClaimTypes + */ + ClaimTypesSupported []string `json:"claim_types_supported,omitempty"` + + /* + OPTIONAL. Languages and scripts supported for values in Claims being returned, represented as a JSON array of + BCP47 [RFC5646] language tag values. Not all languages and scripts are necessarily supported for all Claim values. + See Also: + BCP47: https://datatracker.ietf.org/doc/html/rfc5646 + */ + ClaimLocalesSupported []string `json:"claims_locales_supported,omitempty"` + + /* + OPTIONAL. Boolean value specifying whether the OP supports use of the request_uri parameter, with true indicating + support. If omitted, the default value is true. + */ + RequestURIParameterSupported bool `json:"request_uri_parameter_supported"` + + /* + OPTIONAL. Boolean value specifying whether the OP requires any request_uri values used to be pre-registered using + the request_uris registration parameter. Pre-registration is REQUIRED when the value is true. If omitted, the + default value is false. + */ + RequireRequestURIRegistration bool `json:"require_request_uri_registration"` + + /* + OPTIONAL. Boolean value specifying whether the OP supports use of the claims parameter, with true indicating + support. If omitted, the default value is false. + */ + ClaimsParameterSupported bool `json:"claims_parameter_supported"` +} + +// OpenIDConnectFrontChannelLogoutDiscoveryOptions represents the discovery options specific to +// OpenID Connect Front-Channel Logout functionality. +// See Also: +// OpenID Connect Front-Channel Logout: https://openid.net/specs/openid-connect-frontchannel-1_0.html#OPLogout +type OpenIDConnectFrontChannelLogoutDiscoveryOptions struct { + /* + OPTIONAL. Boolean value specifying whether the OP supports HTTP-based logout, with true indicating support. If + omitted, the default value is false. + */ + FrontChannelLogoutSupported bool `json:"frontchannel_logout_supported"` + + /* + OPTIONAL. Boolean value specifying whether the OP can pass iss (issuer) and sid (session ID) query parameters to + identify the RP session with the OP when the frontchannel_logout_uri is used. If supported, the sid Claim is also + included in ID Tokens issued by the OP. If omitted, the default value is false. + */ + FrontChannelLogoutSessionSupported bool `json:"frontchannel_logout_session_supported"` +} + +// OpenIDConnectBackChannelLogoutDiscoveryOptions represents the discovery options specific to +// OpenID Connect Back-Channel Logout functionality. +// See Also: +// OpenID Connect Back-Channel Logout: https://openid.net/specs/openid-connect-backchannel-1_0.html#BCSupport +type OpenIDConnectBackChannelLogoutDiscoveryOptions struct { + /* + OPTIONAL. Boolean value specifying whether the OP supports back-channel logout, with true indicating support. + If omitted, the default value is false. + */ + BackChannelLogoutSupported bool `json:"backchannel_logout_supported"` + + /* + OPTIONAL. Boolean value specifying whether the OP can pass a sid (session ID) Claim in the Logout Token to + identify the RP session with the OP. If supported, the sid Claim is also included in ID Tokens issued by the OP. + If omitted, the default value is false. + */ + BackChannelLogoutSessionSupported bool `json:"backchannel_logout_session_supported"` +} + +// OAuth2WellKnownConfiguration represents the well known discovery document specific to OAuth 2.0. +type OAuth2WellKnownConfiguration struct { + CommonDiscoveryOptions + OAuth2DiscoveryOptions +} + +// OpenIDConnectWellKnownConfiguration represents the well known discovery document specific to OpenID Connect. +type OpenIDConnectWellKnownConfiguration struct { + CommonDiscoveryOptions + OAuth2DiscoveryOptions + OpenIDConnectDiscoveryOptions + OpenIDConnectFrontChannelLogoutDiscoveryOptions + OpenIDConnectBackChannelLogoutDiscoveryOptions +}