Skip to content

Discovery and JWKS

This page helps you configure a client or an API from the auth server’s discovery document, and check the signature of a token it issued.

Two endpoints do this, and neither needs a token:

  • GET /.well-known/openid-configuration, the discovery document: where every endpoint is and what the auth server supports. Most OpenID Connect libraries need nothing else to configure themselves. The same document is at /.well-known/oauth-authorization-server, for OAuth clients that look there. See Where the document is.
  • GET /certs, the JSON Web Key Set (JWKS): the public keys the auth server signs tokens with. Its URL is the discovery document’s jwks_uri.
  1. Give your library the auth server’s base URL, or the discovery URL itself:

    Terminal window
    curl https://auth.example.com/.well-known/openid-configuration
  2. It reads the endpoints and the issuer from the answer:

    {
    "issuer": "https://auth.example.com",
    "authorization_endpoint": "https://auth.example.com/auth/authorize",
    "token_endpoint": "https://auth.example.com/auth/token",
    "userinfo_endpoint": "https://auth.example.com/userinfo",
    "end_session_endpoint": "https://auth.example.com/auth/logout",
    "jwks_uri": "https://auth.example.com/certs",
    ...
    }
  3. To check a token’s signature, it fetches the key set and picks the key whose kid matches the one in the token’s header:

    Terminal window
    curl https://auth.example.com/certs
    {
    "keys": [
    {
    "alg": "RS256",
    "kid": "0e0c3f6a-...",
    "kty": "RSA",
    "use": "sig",
    "n": "w8Zk...",
    "e": "AQAB"
    }
    ]
    }

Then it checks the token’s iss against the discovery document’s issuer, and its aud and exp. See Tokens.

The auth server serves its discovery document at two addresses, the one OpenID Connect Discovery 1.0 defines and the one RFC 8414 defines for OAuth servers in general:

  • /.well-known/openid-configuration, which OpenID Connect libraries read.
  • /.well-known/oauth-authorization-server, which OAuth clients read. MCP clients try it first.

Both answer GET and HEAD with the same document.

Keep the issuer the address clients reach the auth server at. A client refuses the discovery document when its issuer isn’t exactly the URL it fetched the document under, as RFC 8414 section 3.3 and OpenID Connect Discovery 1.0 section 4.3 require. An issuer naming another host breaks discovery at both addresses.

The auth server describes what it implements, which no setting changes but two: the issuer, and whether registration_endpoint is there. Every grant and response type is listed even while the implicit flow or the password grant is off, as OpenID Connect Discovery 1.0 and RFC 8414 define these fields: a client that isn’t allowed one is refused at the endpoint.

Field Value
issuer Issuer, under Admin, General in the admin console: an https URL with no query, fragment or user info, or exactly the auth server’s base URL, at most 60 characters. A new installation starts with the base URL. Every token’s iss is this value.
authorization_endpoint /auth/authorize, the authorization endpoint
token_endpoint /auth/token, the token endpoint
userinfo_endpoint /userinfo, the UserInfo endpoint
end_session_endpoint /auth/logout, the logout endpoint
jwks_uri /certs, the key set below
registration_endpoint /connect/register, only while dynamic client registration is on. See Dynamic client registration.
grant_types_supported authorization_code, refresh_token, client_credentials, password and implicit
response_types_supported code, token, id_token and id_token token
response_modes_supported query, fragment and form_post
prompt_values_supported none, login and consent. See prompt.
acr_values_supported urn:goiabada:level1, urn:goiabada:level2_optional and urn:goiabada:level2_mandatory. See ACR and AMR.
subject_types_supported public: a user’s sub is the same for every client
id_token_signing_alg_values_supported RS256
scopes_supported openid, profile, email, address, phone, groups, attributes and offline_access. Permission scopes aren’t listed. See Scopes.
claims_supported The claims about the user and the sign-in the auth server can supply, in ID tokens, access tokens and /userinfo
token_endpoint_auth_methods_supported client_secret_post, client_secret_basic and none, the last for a public client
code_challenge_methods_supported S256. See PKCE.
request_parameter_supported false: a request object is refused
request_uri_parameter_supported false: a request_uri is refused
authorization_response_iss_parameter_supported true: every authorization response carries iss, the same value as issuer. See The response.

Each endpoint is the auth server’s base URL, GOIABADA_AUTHSERVER_BASEURL, followed by its path. The admin console’s home page links to the document.

/certs answers with the public half of every signing key the auth server keeps, in this order:

  • The next key, which will sign tokens after the next rotation. It’s published before it signs anything, so a client that caches the set already has it when it starts being used.
  • The current key, which signs every token now.
  • The previous key, while there is one: it signed tokens before the last rotation, and some of them may still be valid.

Each key is a 4096-bit RSA key with alg RS256, use sig, and a kid that the header of every token it signs carries.

To rotate, choose Rotate keys under Admin, Signing keys in the admin console. The next key becomes the current one, the current one becomes the previous one, the old previous key is deleted, and a new next key is created. A token signed by the deleted key no longer verifies, refresh tokens included, so don’t rotate twice within the lifetime of your longest-lived token.

A rotation can fail at its very end, if the database connection is lost while the change is saved. The page then says the rotation may or may not have happened. To tell which, compare the keys listed now with the ones you saw before pressing Rotate keys: the rotation happened if the key that was next is now current. Don’t rotate again until you know, since a second rotation deletes the key that was current a moment ago.

The discovery document, at both its addresses, and /certs answer cross-origin requests from any origin, with nothing to register, so JavaScript in a browser can read them. See web origins for the endpoints that need one.