Authentication & Authorization Architecture – Portugal Odyssey¶
Overview¶
We adopt a centralized Identity and Access Management (IAM) design based on Keycloak (Open Source OAuth2/OIDC server) and a NestJS-based auth-service facade for platform-specific features. This satisfies OAuth2/OIDC, JWT, RBAC, multi-tenant needs, social login, password policies, 2FA, and session SSO across subdomains.
- OAuth2/OIDC Provider: Keycloak
- Auth Facade: NestJS
auth-service(TypeScript) - Token Format: OIDC JWT access tokens + refresh tokens
- Cache/Session: Redis (JWKS caching, token blacklists, session mapping)
- User Data: Keycloak DB for identities; platform-specific profile stored in Postgres (
iamschema) - Transport: REST + GraphQL (auth-service) for complex profile/tenant queries
- Frontends: Public, Admin, Partner Console integrate via PKCE authorization code flow
- Gateways/Services: Validate JWT via JWKS + enforce RBAC/tenant guards
Domains¶
- Dev:
dev.codecomedy.dev(e.g.,auth-dev.portugalodyssey.pt,sso-dev.portugalodyssey.pt) - Qual:
po.codecomedy.dev(e.g.,auth-qual.portugalodyssey.pt,sso-qual.portugalodyssey.pt) - Prod:
portugalodyssey.pt(e.g.,auth.portugalodyssey.pt,sso.portugalodyssey.pt)
Traefik terminates TLS and routes to Keycloak and the auth-service. Cookies use SameSite=None; Secure for cross-subdomain SSO where applicable.
Tenancy Model¶
Single Keycloak realm: portugal-odyssey.
- Tenants modeled as groups in Keycloak (
tenant:{tenantId}), synced to platform DB. - Roles:
customer,partner,adminat realm level; optional client roles per application. - Tokens include:
realm_access.rolesfor global rolesresource_accessfor client roles- Custom claim
tenant_id(single) andtenant_ids(array) via Keycloak Protocol Mapper
High-Level Flows¶
-
Login (PKCE, Authorization Code):
-
Frontend redirects to Keycloak → user authenticates (password policy + 2FA/WebAuthn)
- Keycloak issues
code→ frontend exchanges via backend or directly (PKCE) foraccess_token+refresh_token. -
Frontend stores access token in memory; refresh token via secure HTTP-only cookie (optional) on
auth-servicedomain to centralize refresh. -
Social Login:
-
Keycloak configured with Google/Facebook IdPs.
-
After login, tokens carry normal roles/tenant claims.
-
API Requests:
-
Clients send
Authorization: Bearer <access_token>to API Gateway → gateway middleware validates JWT via JWKS (cached in Redis) and injectsx-user,x-tenantheaders for services. -
Services:
-
NestJS guards validate tenant membership and RBAC, using token claims and, when needed, platform DB lookups.
-
Session Logout:
- Frontend calls
auth-service /auth/logout→ revokes Keycloak refresh token (introspection/revocation endpoint) and clears cookies. Keycloak Single Logout propagates to clients.
Components¶
-
Keycloak
-
Realm:
portugal-odyssey - Clients:
public-app,admin-app,partner-console,auth-service,api-gateway - Identity Providers: Google, Facebook
- Policies: Password history/strength; OTP, WebAuthn
-
Mappers:
tenant_id,tenant_ids,preferred_username,email_verified -
Auth-Service (NestJS)
-
REST: login helpers, refresh, logout, user profile patch, tenant invites
- GraphQL: rich profile + tenant graph queries
- RBAC: guards based on roles and permissions
- Tenancy: guards using
tenant_idclaim + DB check -
Integrations: Keycloak admin API (KC Admin client) for user provisioning and group management
-
Shared Validation
- Express middleware for API Gateway
- NestJS
AuthGuard+RolesGuard+TenantGuardfor services - JWKS retrieval with caching and rotation handling
Security¶
- HTTPS only; HSTS via Traefik
- PKCE mandatory for public clients
- Access token TTL: 15 minutes; Refresh TTL: 30 days (rotating, reuse detection)
- Rate limiting on auth endpoints; device-based session mapping; suspicious login alerts via Notification service
- Bcrypt for internal secrets; helmet, CSRF where cookies used
Alternative (Ory Hydra + Ory Kratos)¶
If Keycloak is not desired, equivalent setup with Hydra (OAuth2) and Kratos (identity) is supported. The NestJS guards and gateway middleware remain identical; token issuer/metadata and admin integration differ. See ory-notes.md for migration notes (to be added upon request).