Como habilitar autenticacion JWT
Pre-authenticated queda como modo por defecto del arquetipo (X-User-Id propagado por el API gateway). Para que el servicio valide tokens JWT por sí mismo, sin depender del gateway, se habilita el flujo OAuth2 resource server con uno o varios issuers de confianza.
1. Habilitar el mecanismo
En application.yaml:
app:
security:
jwt:
enabled: true
Con esto Spring Security agrega BearerTokenAuthenticationFilter a la cadena. Pre-authenticated y JWT pueden coexistir; cuando ambos están habilitados y una request trae las dos credenciales a la vez, CredentialAmbiguityFilter rechaza con 401.
2. Configurar issuers de confianza
Cada issuer requiere su issuer-uri (de donde se descubre el JWKS vía OIDC /.well-known/openid-configuration) y la audiencia esperada:
app:
security:
jwt:
enabled: true
issuers:
- issuer-uri: https://idp-corporate.example/realms/services
audiences: [orders-service]
- issuer-uri: https://idp-partner.example
audiences: [orders-service]
Para cada issuer:
-
issdebe coincidir conissuer-uri. -
auddebe contener al menos una de lasaudienceslistadas. -
expdebe estar en el futuro (clock skew estándar de Spring: 60 s). -
La firma se valida contra el JWKS del issuer.
Token cuyo iss no coincida con ningún issuer configurado → 401.
3. Mapear claims a authorities
Los IDPs no se ponen de acuerdo en el nombre del claim de authorities: Keycloak usa realm_access.roles o resource_access.{client}.roles, Auth0 usa permissions, Azure AD usa roles (app roles) o scp (scopes), Okta usa groups. Por eso authorities-claim se configura por issuer:
app:
security:
jwt:
issuers:
- issuer-uri: https://idp-corporate.example/realms/services
audiences: [orders-service]
authorities-claim: roles
- issuer-uri: https://idp-partner.example
audiences: [orders-service]
authorities-claim: permissions
Las authorities resultantes son los valores del claim, sin prefijo. @PreAuthorize("hasAuthority('admin')") funciona sin ajustes extra.
Sin authorities-claim, Spring lee scope/scp por default.
4. Cruzar identidad con tenant
Si el JWT trae el tenant en un claim — y el nombre del claim también varía por IDP — el arquetipo valida que coincida con X-Tenant-Id:
app:
security:
jwt:
issuers:
- issuer-uri: https://idp-corporate.example/realms/services
audiences: [orders-service]
tenant-claim: tenant_id
- issuer-uri: https://idp-partner.example
audiences: [orders-service]
tenant-claim: tid
Casos de rechazo:
-
Token sin el claim configurado → 401.
-
Request sin
X-Tenant-Id→ 401. -
Valor del claim ≠
X-Tenant-Id→ 401.
Sin tenant-claim para un issuer, el cruce identidad↔tenant se omite para ese issuer. Útil cuando el JWT no transporta tenant y se confía exclusivamente en el header.
5. Verificar con WhoAmI
GET /v1/whoami (montado en commons/adapter/in/web) devuelve la identidad resuelta:
export BEARER_TOKEN=eyJhbGciOiJSUzI1NiJ9...
curl http://localhost:8080/v1/whoami \
-H 'X-Tenant-Id: 674b414f-27b5-461b-a8da-933326669018' \
-H 'X-Application: BACKOFFICE' \
-H "Authorization: Bearer $BEARER_TOKEN"
X-Application es obligatorio: RequestContextInterceptor lo exige antes de que la cadena de seguridad se ejecute. Sin él la response es 400, no 401.
{
"subject": "user-42",
"mechanism": "jwt",
"authorities": ["admin"]
}
Si la cadena de auth falla por cualquier validador (iss, aud, exp, firma, tenant-claim), el endpoint devuelve 401.
Modo unsigned para desarrollo local
Para probar la integración sin levantar un IDP, un issuer puede declararse unsigned:
app:
security:
jwt:
enabled: true
issuers:
- issuer-uri: http://localhost/local
audiences: [dev]
unsigned: true
Con unsigned: true:
-
Se omite OIDC discovery y la verificación criptográfica.
-
iss,aud,exp,tenant-claimyauthorities-claimsiguen aplicando. -
Al arrancar, el servicio emite un WARN por cada issuer en este modo.
El token se genera en jwt.io con alg: none o con cualquier firma — el decoder no la verifica.
|
|
Ver también
-
Capa de seguridad — propiedades, validadores, puntos de extensión.
-
Como crear un endpoint REST — donde
@PreAuthorizeconsume las authorities mapeadas.