Multi-tenant API
One API for every client on your platform, where each request is checked against the caller's tenant, role and features in one shared place.
By: Benjamin Clark
Intent
This pattern assumes a SaaS platform with an API behind an API gateway, and users identified as in multi-tenant Cognito auth. It makes the API the one place that enforces multi-tenancy: every request rebuilds the caller from verified claims, and one shared layer checks their tenant, their role and the tenant's features before any endpoint's own code runs. This enables three outcomes:
- Every endpoint applies the same rules, so a new endpoint can't forget a check.
- Turning a feature on or off for a client, or restricting an endpoint to a role, is configuration rather than code, as in config as data.
- Every client of the API, from the portal to an AI assistant, gets the same protection, because none of them decides what's allowed.
Motivation
Multi-tenant APIs usually grow their checks endpoint by endpoint. Each one validates the tenant and role in its own way, copied from the last, which fails in three ways:
- A missing check leaks data. One endpoint that forgets to compare the tenant exposes one client's data to another, which is the essence of broken access control.
- Rules drift. Copies of the same check diverge, until the same role can do different things on different endpoints.
- Front ends start enforcing. When the API doesn't make clear what a caller may do, each front end adds checks of its own, such as hiding a button from a role. Code in a browser runs on the user's own machine, so anyone who calls the API directly gets straight past those checks, and the checks in different front ends drift apart.
This pattern moves those checks into one shared layer that every endpoint passes through. The layer builds the caller from the verified token, confirms that their active tenant is one they belong to, and applies the role and feature rules each endpoint declares in its configuration, so endpoints do only their own work. The API also decides which fields a role may see, and returns errors with a machine-readable code, so a front end such as the multi-tenant portal frontend only has to present what it's given.
Applicability
Use this pattern when:
- A SaaS platform serves many clients through one API.
- Endpoints differ in who may call them, and in which client features they need.
- Several front ends or services, such as a portal, an MCP server or an AI assistant, call the same API.
Do not use this pattern when:
- The API has a handful of endpoints and one kind of user, where a check in each endpoint is simpler.
- Each client runs its own deployment of the API, so no request ever has to choose between tenants.
Structure
Participants
| Participant | Role |
|---|---|
| Caller | A front end, service or AI client, sending the user's token. |
| API gateway | Rejects bad tokens before any of your code runs. |
| Shared handler layer | Builds the caller from the verified claims, checks their tenant, role and features, and returns errors with a code. |
| Tenant directory | Holds each tenant and what's enabled for it, as in config as data. |
| Endpoint | Does its own work only, with the roles and features it needs declared in its configuration. |
Constraints and trade-offs
- Every endpoint depends on the shared layer, so a fault there affects the whole API, and changes to it need care and thorough tests.
- Every request reads the tenant's record to check its features. A cache would cut that read, at the cost of a slower response when a feature is switched off.
- Access rules sit in configuration, apart from the code they protect, so reading an endpoint's code alone doesn't show who may call it.
Part of how I deliver
This is the layer I put in place before a multi-tenant API grows past its first few endpoints. It's one of many patterns I bring through contract delivery, and every front end and service that calls your API is protected by it.
Is every new client a project?
I build multi-tenant platforms where adding a client is routine, and each client's data stays its own. If you're building one, or yours has become hard to scale, book a call and we'll talk it through.
