Skip to main content

0025: Tenant Switching via Client-Hinted Claims Enrichment

Date: 2025-09-17

Status: Proposed

Context

In a multi-tenant system, a single user may be a member of multiple tenants. The platform must provide a seamless and secure mechanism for a user to switch their active tenant context. This decision record outlines the flow for how a user can switch tenants and how the system reflects this change in subsequent API requests.

The current claims enrichment flow relies on the iam-service looking up a user's policy and returning a single tenant ID. This needs to be extended to support users with multiple tenant memberships.

Decision

We will implement a Client-Hinted Claims Enrichment flow. This approach extends the existing claims enrichment pattern by requiring the client application to provide the desired tenant context on each API request. This avoids turning the iam-service into an OIDC provider and allows clients to use standard OIDC libraries.

The iam-service remains a simple policy engine, and its responsibility is to validate the client's hint against the user's actual permissions.

The flow is as follows:

  1. Upstream Authentication: The user authenticates with the upstream IdP using a standard OIDC flow and receives a standard IdP token.

  2. Client-Side Tenant Selection: The client application (e.g., the UI) determines which tenant the user wants to act within. This can be done by fetching a list of the user's tenants from an endpoint like GET /api/iam/v1/me/tenants.

  3. API Call with Context Hint: For every subsequent API request, the client sends two headers:

    • Authorization: Bearer <IdP-Token>
    • X-Active-Tenant-ID: <selected-tenant-id>
  4. Gateway Orchestration: The API Gateway forwards the IdP token and the X-Active-Tenant-ID header to the iam-service's /system/enrich-token endpoint.

  5. Validation and Enrichment: The iam-service validates the IdP token to identify the user. It then performs a critical check: it verifies that this user is a member of the tenant specified in X-Active-Tenant-ID. If the check passes, it returns the user's roles and other claims for that specific tenant.

Consequences

Positive:

  • Standard Client Libraries: Clients can use any off-the-shelf OIDC library without modification. This dramatically simplifies client-side development.
  • Simple iam-service: The iam-service remains a simple, stateless policy and claims engine. It does not need to become an OIDC provider, manage sessions, or handle complex federation logic.
  • Secure and Explicit: The user's intent is explicit on every request, and this intent is validated by the iam-service against its policy database. Downstream services receive an unambiguous, pre-validated context.

Negative:

  • Slightly "Chattier" Flow: The iam-service is called on every API request, which is consistent with the claims enrichment pattern.
  • Client Responsibility: The client is responsible for storing the active tenant ID and sending it with each request. This is a minor and reasonable responsibility.

Implementation Notes

  • The /system/enrich-token handler must be updated to accept and validate the X-Active-Tenant-ID hint.
  • A new endpoint, GET /api/iam/v1/me/tenants, is required for the UI to discover the user's available tenants.
  • The iam-service does not need its own JWKS endpoint for this flow, as it is not issuing its own tokens. The previous removal of the JWKS endpoint was correct for this pattern.