Skip to content

OIDC Discovery Document

Every Keycloak realm publishes an OpenID Connect discovery document at /.well-known/openid-configuration under /realms/<realm>.

Full URL:

https://<keycloak-host>/realms/<realm>/.well-known/openid-configuration

This is the single source of truth for every endpoint your app needs. Fetch it once at startup and you have everything — authorization endpoint, token endpoint, JWKS URI, and more.

Endpoint nameJSON keyPurpose
Authorization endpointauthorization_endpointRedirects users to the login page
Token endpointtoken_endpointExchanges codes for tokens
UserInfo endpointuserinfo_endpointReturns claims about the authenticated user
JWKS URIjwks_uriPublic keys for verifying JWT signatures
End session endpointend_session_endpointLogs the user out

Replace KC_URL and REALM with your values. The response is a JSON object with all the endpoint URLs listed above.

curl https://${KC_URL}/realms/${REALM}/.well-known/openid-configuration | jq .
OptionBenefitCost
Use the OIDC discovery documentThe app fetches its configuration automatically, with no endpoint URLs hardcodedAdds a network call at startup, and it must be cached properly so it isn’t refetched on every request
Hardcode the endpoint URLs yourselfFaster to get started, no dependency on the discovery documentWhen Keycloak moves the realm or changes its URL, every place you hardcoded it needs a code change
  • Confusing OAuth2 with OIDC — OAuth2 is an authorization framework (grants access to a resource), while OIDC is an identity layer built on top of OAuth2 (tells you who the user is). You must request scope=openid to get an id_token back.
  • Not verifying issuer in the discovery document — before trusting any endpoint, verify that issuer matches the expected Keycloak realm, or you risk being tricked by a forged discovery document.
  • Caching the discovery document forever and never refreshing it — if Keycloak rotates keys or moves an endpoint, an app that cached the old value permanently breaks with no warning. Set a TTL or refresh it periodically.

Real-world example

The “Log in with Google” or “Log in with GitHub” button — behind it is full OIDC: the app fetches Google’s/GitHub’s discovery document first to learn the authorization and token endpoints, then starts the flow.

Auth0 and Okta — commercial identity providers that use the same discovery-document pattern as Keycloak, so an app can switch provider with almost no code change, because they all speak the same OIDC language.

Where does Keycloak publish the OIDC discovery document?
Which JSON key in the discovery document gives you the token endpoint?
What is the JWKS URI used for?
Why should apps fetch the discovery document instead of hardcoding endpoints?