Saltar a contenido

OpenID Connect Discovery

El endpoint de Discovery (.well-known/openid-configuration) publica la configuración completa del servidor OpenID Connect. Los clientes usan este endpoint para descubrir automáticamente los endpoints de autorización, token, JWKS y UserInfo sin necesidad de configuración manual.

URL en Keycloak

Por realm:
https://{KC_HOSTNAME}/realms/{realm-name}/.well-known/openid-configuration

Ejemplos:
https://auth.example.com/realms/realm-internal/.well-known/openid-configuration
https://auth.example.com/realms/realm-partners/.well-known/openid-configuration

Consultar el discovery endpoint

curl -s https://auth.example.com/realms/realm-internal/.well-known/openid-configuration | jq .

Campos más importantes de la respuesta

{
  "issuer": "https://auth.example.com/realms/realm-internal",
  "authorization_endpoint": "https://auth.example.com/realms/realm-internal/protocol/openid-connect/auth",
  "token_endpoint": "https://auth.example.com/realms/realm-internal/protocol/openid-connect/token",
  "introspection_endpoint": "https://auth.example.com/realms/realm-internal/protocol/openid-connect/token/introspect",
  "userinfo_endpoint": "https://auth.example.com/realms/realm-internal/protocol/openid-connect/userinfo",
  "end_session_endpoint": "https://auth.example.com/realms/realm-internal/protocol/openid-connect/logout",
  "jwks_uri": "https://auth.example.com/realms/realm-internal/protocol/openid-connect/certs",
  "grant_types_supported": ["authorization_code", "implicit", "refresh_token", "password", "client_credentials", "device_code", "urn:openid:params:grant-type:ciba"],
  "response_types_supported": ["code", "none", "id_token", "token", "id_token token", "code id_token", "code token", "code id_token token"],
  "subject_types_supported": ["public", "pairwise"],
  "id_token_signing_alg_values_supported": ["PS384", "ES384", "RS384", "HS256", "HS512", "ES256", "RS256", "HS384", "ES512", "PS256", "PS512", "RS512"],
  "token_endpoint_auth_methods_supported": ["private_key_jwt", "client_secret_basic", "client_secret_post", "tls_client_auth", "client_secret_jwt"],
  "claims_supported": ["aud", "sub", "iss", "auth_time", "name", "given_name", "family_name", "preferred_username", "email", "acr"],
  "code_challenge_methods_supported": ["plain", "S256"]
}

Campos clave

Campo Descripción Uso
issuer Identificador del servidor de autorización Se valida en el claim iss de cada JWT
authorization_endpoint URL del flujo de autorización Redirigir al usuario para login
token_endpoint Intercambio de código por tokens POST para obtener access/refresh/id tokens
jwks_uri URI de las claves públicas (JWKS) Descarga de claves para verificar firma JWT
userinfo_endpoint Perfil del usuario autenticado Obtener claims adicionales del usuario
end_session_endpoint Logout del usuario Cerrar sesión en Keycloak
introspection_endpoint Verificar un opaque token No necesario con JWT (auto-validable)
code_challenge_methods_supported Métodos PKCE soportados Confirmar que S256 está disponible

Uso en Spring Security

Spring Security descarga automáticamente la configuración desde el issuer URI:

# application.yml
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          # Spring descarga {issuer-uri}/.well-known/openid-configuration
          # y usa jwks_uri automáticamente
          issuer-uri: https://auth.example.com/realms/realm-internal

Esto elimina la necesidad de configurar jwk-set-uri manualmente. Spring Security también usa el issuer del discovery para validar el claim iss de cada JWT recibido.

Cache del discovery endpoint

Spring Security cachea la respuesta del discovery endpoint en memoria. Si rotas las claves de firma en Keycloak, el servicio descargará las nuevas JWKs automáticamente cuando reciba un JWT con un kid desconocido. No es necesario reiniciar el servicio.

Latencia al arrancar

En el arranque, Spring Security hace una petición HTTP al discovery endpoint y al JWKS URI de Keycloak. Si Keycloak tarda en estar disponible (p. ej. en docker compose up), el servicio puede fallar el health check inicial. Configura depends_on y condition: service_healthy en compose.yml.