Token Verification and Header Enrichment
This document explains the critical role the API Gateway plays in securing the platform by verifying tokens and enriching requests with trusted authorization headers. Backend services rely on this mechanism for making authorization decisions.
Overview
Backend services operate on a "zero-trust" basis for any information coming directly from a client. However, they are designed to trust specially-named HTTP headers that are added by the API Gateway. This process is called Header Enrichment.
Important Clarification: The API Gateway does not create or modify "enriched JWTs." Instead, it:
- Verifies or introspects the user's authentication token (JWT or opaque token) via the
iam-service. - Calls the
iam-serviceto fetch Citadel-specific authorization claims. - Adds these authorization claims as
X-*headers to the request before forwarding it to the appropriate backend service. - The original token remains unchanged and can be passed through to downstream services.
Zero-Trust Mode: When zero-trust mode is enabled, the API Gateway bypasses verification entirely and passes the Authorization header directly to downstream services. In this mode, each downstream service is responsible for verifying the token with the iam-service independently.
End-to-End Request Flow
The following sequence diagram illustrates the entire process, from the end-user's API call to the final request received by a downstream service.
Traefik Middleware Configuration
This flow is implemented in Traefik using a ForwardAuth middleware. This middleware intercepts the request, calls the iam-service for the enrichment data, and then uses the authResponseHeaders directive to copy the claims from the iam-service's response back onto the original request.
Here is the concrete implementation from the project's dynamic configuration:
http:
middlewares:
iam-enrichment:
forwardAuth:
address: http://iam-service:8080/v1/system/enrich-token
authResponseHeaders:
- X-User-ID
- X-Tenant-ID
- X-User-Roles
Any route that requires user information must be configured to use this citadel-iam-enrichment middleware.
The Downstream Service Contract
When a backend service (e.g., iam-service, admin-bff) receives a request from the API Gateway, the security contract depends on the deployment mode:
Standard Mode (API Gateway Verification):
- Trust the Headers: The service MUST rely exclusively on the
X-*headers (X-User-ID,X-Tenant-ID,X-User-Roles) for all authorization decisions. These headers are considered trusted because they were injected by the gateway after it successfully verified the token via theiam-serviceand retrieved authorization claims. - Ignore the Bearer Token: The original
Authorization: Bearer <token>header may still be present on the request forwarded by the gateway. The downstream service MUST IGNORE this header. It MUST NOT attempt to re-validate or parse the token. This prevents duplicated validation logic and eliminates overhead.
Zero-Trust Mode (Downstream Verification):
- Verify Token Directly: When zero-trust mode is enabled, the API Gateway does not verify the token or add
X-*headers. Instead, it passes theAuthorizationheader through unchanged. - Service Responsibility: Each downstream service MUST call the
iam-servicedirectly to verify the token and retrieve authorization claims. - No Trusted Headers: Services operating in zero-trust mode MUST NOT trust any
X-*headers, as they are not added by the gateway in this mode.
This clear separation of concerns is fundamental to the architecture:
- API Gateway (Standard Mode): Handles Token Verification and Header Enrichment.
- API Gateway (Zero-Trust Mode): Passes through Authorization Header without verification.
- IAM Service: Handles Token Verification and Authorization Claims Retrieval.
- Downstream Services: Handle Authorization based on enriched claims (standard mode) or direct token verification (zero-trust mode).
The x-* Headers
When a backend service receives a request from the API Gateway, it can trust the following headers:
x-user-id: The unique identifier (subject) of the authenticated user.x-tenant-id: The ID of the tenant the user belongs to. All data access must be scoped to this tenant to ensure isolation.x-user-roles: A comma-separated list of the user's assigned role names (e.g.,"Admin,User,Super Admin"). The scope of these roles (global vs. tenant) is determined by the presence or absence of thex-tenant-idheader.