Skip to content

Discovery ​

Clients learn the OP's endpoints, signing keys, and capabilities by fetching one JSON document. For an OIDC OP that document is defined by OIDC Discovery 1.0 and lives at /.well-known/openid-configuration. RFC 8414 (OAuth Authorization Server Metadata) defines the same idea for plain OAuth under /.well-known/oauth-authorization-server; this library serves only the openid-configuration document, and it carries the RFC 8414 members too. This page tours that document.

Specs referenced on this page

Why this exists

Without a discovery document, every RP would hard-code the OP's endpoint URLs, signing algorithms and supported features, and every change on the OP would need a code change in every RP. With discovery, the RP only needs the issuer URL: https://op.example.com.

What's in the discovery document ​

The RP reads endpoints, keys and capabilities
The Relying Party sends one GET request to the well-known URL and receives the discovery document. The document answers three questions: where to send each request, which keys verify tokens, and what this OP accepts.Relying PartySDK or your appGET200 · JSONdiscovery documentauthorization_endpointtoken · userinfo · logoutWhere to send requestsno hard-coded URLsjwks_urithe OP's public keysWhich keys verify tokensfetch the JWKS, match kid*_supportedscopes, grants, PKCE…What this OP will acceptcheck before using it
One request replaces three kinds of hard-coded configuration. The response is served with Cache-Control: public, max-age=3600, so the RP asks again at most about once an hour.

The table lists the fields a beginner will meet first. The library emits each one when the matching feature is configured. Endpoint URLs are absolute and sit under the mount prefix (/oidc by default), for example https://op.example.com/oidc/auth.

FieldWhat it is
issuerThe OP's canonical identifier. The same string appears as iss in every signed token. RPs compare it byte-for-byte.
authorization_endpointURL of /auth — where the browser is redirected to log the user in.
token_endpointURL of /token — where the RP exchanges a code or refresh token.
userinfo_endpointURL of /userinfo — where the RP fetches fresh claims with an access token.
jwks_uriURL of the JWKS — the OP's public signing keys, published as a JWK Set.
introspection_endpointURL of /introspect (RFC 7662) — present when the introspection feature is wired.
revocation_endpointURL of /revoke (RFC 7009) — present when the revocation feature is wired.
end_session_endpointURL of /end_session — where the RP redirects the browser for RP-Initiated Logout. Present only when the authorization endpoint is.
backchannel_logout_supportedtrue whenever the authorization endpoint exists; the OP can send Back-Channel Logout tokens.
registration_endpointURL of /register (RFC 7591) — present when op.WithDynamicRegistration(...) is wired.
pushed_authorization_request_endpointURL of /par — present only when the PAR feature (RFC 9126) is enabled.
device_authorization_endpointURL of /device_authorization — present only when the device-code grant is wired.
backchannel_authentication_endpointURL of /bc-authorize — present only when the CIBA grant is wired.
grant_types_supportedGrant types the OP accepts at /token: authorization_code, refresh_token, client_credentials, …
response_types_supportedResponse types the authorization endpoint accepts. Browser-capable configurations advertise only code (the OIDC Core "code flow"). A client-credentials-only OP emits an empty array because no authorization endpoint is mounted.
response_modes_supportedHow the authorization endpoint returns the result: query, form_post, plus query.jwt, fragment.jwt, form_post.jwt, jwt when JARM is enabled.
authorization_response_iss_parameter_supportedAlways true: every authorization response carries iss (RFC 9207).
id_token_signing_alg_values_supportedJWS algorithms used to sign ID Tokens. The library publishes the one algorithm the OP signs with: ES256 by default, RS256 after op.WithSigningAlgorithm(op.AlgRS256).
request_parameter_supported / request_uri_parameter_supportedtrue only when JAR is enabled; otherwise false.
request_object_signing_alg_values_supportedJWS algorithms accepted on JAR request= parameters: RS256, PS256, ES256, EdDSA. FAPI profiles narrow it to PS256, ES256, EdDSA. Present only when JAR is enabled.
token_endpoint_auth_methods_supportedHow clients authenticate at /token. The default list includes client_secret_basic, client_secret_post, private_key_jwt, and none; FAPI profiles narrow it. The introspection and revocation auth-method lists intentionally omit none, because those endpoints require a confidential caller. With feature.MTLS enabled the lists also contain tls_client_auth and self_signed_tls_client_auth. mTLS endpoint metadata is advertised separately via mtls_endpoint_aliases.
code_challenge_methods_supportedPKCE transformations. The library advertises only S256.
subject_types_supportedpublic and (when op.WithPairwiseSubject(...) is wired) pairwise.
claims_supportedClaims the OP can return. Omitted unless you pass op.WithClaimsSupported(...), because the library cannot know what your user store holds.
scopes_supportedPublic scopes: the standard OIDC scopes plus every scope registered with op.WithScope(...) as public. Private scopes are not listed.
dpop_signing_alg_values_supportedPresent only when the DPoP feature (RFC 9449) is enabled.
require_pushed_authorization_requestsPresent as true only under a profile that mandates PAR (the FAPI 2.0 profiles).
acr_values_supportedThe authentication context classes the OP accepts in acr_values. Present only when op.WithACRValuesSupported(...) is wired; op.New refuses an entry the ACR policy cannot resolve, so declare non-AAL values with op.WithACRPolicy.
claims_parameter_supportedDefaults to true; pass op.WithClaimsParameterDisabled() to stop advertising and honoring OIDC §5.5 claims requests.
authorization_details_types_supportedThe RFC 9396 type values accepted in authorization_details. Present only when op.WithAuthorizationDetailTypes(...) is wired.
grant_management_endpointThe grant management endpoint URL. Present only when op.WithGrantManagement(...) is wired.
grant_management_actions_supportedThe grant management actions the OP accepts (create / replace / merge / query / revoke). Present with grant_management_endpoint.
grant_management_action_requiredEmitted as true only when WithGrantManagement(op.GrantManagement{..., ActionRequired: true}) — an authorization request must then carry grant_management_action.
introspection_endpoint_auth_signing_alg_values_supportedJWS algorithms accepted on a client_assertion at /introspect. Present when the introspection feature is wired and the endpoint's auth-method list contains an assertion-based method (private_key_jwt).
revocation_endpoint_auth_signing_alg_values_supportedJWS algorithms accepted on a client_assertion at /revoke. Present when the revocation feature is wired and the endpoint's auth-method list contains an assertion-based method (private_key_jwt).
prompt_values_supportedThe prompt values the authorization endpoint accepts: none, login, consent, select_account. create is added only when LoginFlow.Registration is set.
authorization_grant_profiles_supportedurn:ietf:params:oauth:grant-profile:id-jag. Experimental: present only when at least one ID-JAG issuer is trusted (ID-JAG). The issuers themselves are never published.
identity_chaining_requested_token_types_supportedurn:ietf:params:oauth:token-type:id-jag. Experimental: present only when op.WithIDJAGIssuance(...) is wired (ID-JAG).
client_id_metadata_document_supportedtrue when op.WithClientIDMetadataDocuments(...) is wired, so an HTTPS client_id resolves to its metadata document. Experimental; omitted otherwise (MCP authorization server).

When op.WithProtectedResources(...) is wired, the OP additionally serves RFC 9728 protected-resource metadata at /.well-known/oauth-protected-resource (one document per registered resource) — a separate well-known document, not a field on openid-configuration.

_supported fields are advertisements, not policy

A _supported list is what the OP will accept — not what every client must use. A client may use a subset. The OP rejects anything outside the list.

How clients use it ​

A typical RP SDK does the following on first start:

  1. GET https://op.example.com/.well-known/openid-configuration
  2. Cache the response, for at most the max-age the OP sends (3600 seconds).
  3. Read endpoints, supported algorithms, and supported features from the cached document.
  4. Refetch when the cache expires, or when signature verification fails on an unknown kid, which usually means the OP rotated its keys.

The library helps in two ways. The discovery document does not change between restarts of the same configuration, so RPs can cache it for a long time. During a key rotation, the embedder tells the library through op.WithJWKSRotationActive(predicate), and the JWKS endpoint switches from max-age=3600 to max-age=300, must-revalidate so RPs that refetch see the new key quickly.

The document is built once

The OP builds and marshals the document when the provider is created and serves the same JSON body for the provider's lifetime, so every instance with the same configuration returns identical bytes. Staleness is therefore an RP-side concern: see key rotation for how long an RP can keep using a cached JWKS.

How this library builds it ​

Discovery is constructed once at op.New from the wired feature set, so it cannot drift at runtime: if the embedder did not wire PAR, pushed_authorization_request_endpoint is absent and require_pushed_authorization_requests does not appear. If the embedder wired op.WithProfile(profile.FAPI2Baseline), the FAPI narrowing applies — token_endpoint_auth_methods_supported is filtered to the FAPI-permitted set, require_pushed_authorization_requests=true appears, and the introspection / revocation auth-method lists are copied from the same narrowed list with none removed. The authorization endpoint and its browser-only metadata are emitted only when a configured grant needs the browser authorization flow. A client_credentials-only OP therefore omits authorization_endpoint, end_session_endpoint, and backchannel_logout_supported, while retaining response_types_supported: [].

WithDiscoveryMetadata(DiscoveryMetadata{UILocalesSupported: ...}) is also a construction-time contract: every explicitly advertised locale must be served by the registered locale resolver. Advertising an unserved locale makes op.New fail instead of producing discovery metadata that the UI cannot honor.

Golden tests pin the document shape for each profile, so what discovery says and what the handlers do cannot diverge unnoticed. See design judgment #12 for the rationale.

The document is served at /.well-known/openid-configuration, outside the mount prefix. For an issuer with a path, the same document is also served at the issuer-relative path; see Issuer.

What the library does NOT advertise ​

The library narrows the discovery document deliberately:

  • No none alg. id_token_signing_alg_values_supported and request_object_signing_alg_values_supported never contain none. This is separate from the none client-authentication method listed for /token; none is never a signing algorithm (see JOSE basics and design judgment #11).
  • No HMAC-family alg for ID Tokens. HS256 / HS384 / HS512 are not advertised. The alg-confusion attack class needs them to be reachable, so the library never makes them reachable.
  • No request-object support unless JAR is wired. Without JAR, request_parameter_supported and request_uri_parameter_supported are false and the request-object algorithm lists are absent. pushed_authorization_request_endpoint appears only when PAR is wired.
  • claims_parameter_supported defaults to true, but can be disabled. Passing op.WithClaimsParameterDisabled() makes the discovery document omit OIDC §5.5 support and makes authorize / PAR ignore claims payloads after malformed JSON has been rejected.
  • No frontchannel_logout_supported or check_session_iframe. Front-Channel Logout 1.0 / Session Management 1.0 are not implemented; the discovery document is silent about them. Embedders use Back-Channel Logout 1.0 instead — see design judgment #5.

Discovery is a contract surface

Every _supported array is a commitment to accept those values. Adding a value widens the contract and removing one narrows it, and an RP may refuse to talk to an OP that stops advertising an algorithm it requires. Treat changes to the discovery document like changes to a public API.