JWT Structure and Validation¶
Access Token (OIDC JWT)¶
Header:
{
"alg": "RS256",
"typ": "JWT",
"kid": "
Claims (example):
{
"iss": "https://sso.portugalodyssey.pt/realms/portugal-odyssey",
"aud": "public-app",
"sub": "1a2b3c4d-...", // Keycloak user id
"exp": 1735689600,
"iat": 1735688700,
"azp": "public-app",
"scope": "openid profile email",
"email": "user@example.com",
"email_verified": true,
"preferred_username": "user",
"tenant_id": "
Refresh Token¶
Opaque string maintained by Keycloak. Rotating refresh tokens are enabled; reuse detection invalidates the session. The auth-service can store a refresh_token_id/jti in iam.sessions to help track sessions and revoke selectively.
Validation¶
- Retrieve JWKS from
https://sso.<env-domain>/realms/portugal-odyssey/protocol/openid-connect/certs. - Cache JWKS keys in Redis; rotate on
kidmisses. - Validate:
- Signature (RS256)
issexact match for environmentaudin allowed clients (public-app,admin-app,partner-console,api-gateway)expnot expired; small clock skew allowed (<= 60s)- Optionally enforce
azp== caller client id
Node/Nest Middleware¶
-
API Gateway: Express middleware verifies JWT via JWKS, then sets:
-
req.user = { sub, email, roles, tenant_id, tenant_ids } -
Proxy adds headers
x-user-id,x-tenant-id,x-roles -
Services: NestJS
AuthGuard+RolesGuard+TenantGuardconsume the same claims.