Multi-Tenant Isolation: Keeping Tenant A Out of Tenant B at the Token Level
Multi-Tenant Isolation
In a single-tenant system, a valid token means access. In a multi-tenant system, a valid token means access to one tenant’s data. The difference is a single claim and the enforcement logic around it.
The multi-tenant SaaS platform serves hundreds of tenants from a shared infrastructure. Same application instances, same database (logical separation via tenant_id columns), same Redis cluster. Tenant isolation is not a feature. It is the invariant that, if violated, turns a SaaS platform into a data breach.
Isolation failures are not exotic. They are the most common class of multi-tenant vulnerability. They happen when:
- A developer adds an endpoint and forgets the tenant check.
- A URL path parameter determines the tenant instead of the token claim.
- An admin API uses a different authorization path that skips tenant validation.
- A JOIN query crosses tenant boundaries because the WHERE clause is incomplete.
The Confused Deputy
The confused deputy problem: a system with legitimate authority acts on behalf of the wrong principal because it trusted a client-provided identifier instead of a cryptographically verified one.
In the SaaS platform: User Alice belongs to tenant “acme-corp.” Her JWT contains "tenant_id": "acme-corp". She sends a request to GET /api/tenants/globex-inc/projects. The resource server has two choices:
- Use the path parameter (
globex-inc) to determine which tenant’s data to serve. Alice sees Globex’s projects. Tenant isolation is broken. - Use the token claim (
acme-corp) to determine the tenant boundary. The path parameterglobex-incdoes not match the token’stenant_id. The request is rejected with 403.
Option 1 is the confused deputy. The server trusts Alice’s request to specify the tenant. Alice (or an attacker with Alice’s token) can enumerate every tenant’s data by changing the path parameter.
Option 2 is the correct approach. The tenant context comes from the signed JWT, which was issued by the authorization server after verifying Alice’s tenant membership. The client cannot forge or modify the tenant claim without invalidating the signature.
Isolation Layers
Tenant isolation requires defense-in-depth. A single enforcement point is a single point of failure.
| Layer | Mechanism | What it catches |
|---|---|---|
| Token | tenant_id claim in JWT | Cross-tenant request with valid auth |
| SecurityFilterChain | Custom AuthorizationManager | Missing endpoint-level tenant check |
| Service | TenantContext validation | Business logic accessing wrong tenant |
| Repository | Hibernate @Filter | Developer forgot WHERE tenant_id = ? |
| Database | PostgreSQL RLS | Direct SQL injection bypassing ORM |
Each layer assumes the layers above it have failed. The token layer catches 99% of cross-tenant attempts. The database layer catches the 1% that slip through application bugs. Together, they create a defense that requires failures at multiple levels to breach.
What This Chapter Covers
Section 1 implements token-level enforcement: extracting tenant from JWT claims, creating a TenantAwareAuthentication, and building a SecurityFilterChain that rejects cross-tenant requests before they reach any controller.
Section 2 implements database-level enforcement: Hibernate filters that automatically scope every query to the current tenant, Spring Data JPA integration, and PostgreSQL row-level security as the ultimate backstop.