Skip to main content

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:

  1. Verifies or introspects the user's authentication token (JWT or opaque token) via the iam-service.
  2. Calls the iam-service to fetch Citadel-specific authorization claims.
  3. Adds these authorization claims as X-* headers to the request before forwarding it to the appropriate backend service.
  4. 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 the iam-service and 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 the Authorization header through unchanged.
  • Service Responsibility: Each downstream service MUST call the iam-service directly 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 the x-tenant-id header.