- a distinct account API key
- an optional delegated end-user ID via
X-On-Behalf-Of - downstream resource ownership and usage recorded against that authenticated context
Verify tenant isolation in practice
Treat each tenant as a separate account with its own API key. The goal is to show four things:- Tenant A and Tenant B use different API keys.
- Tenant A and Tenant B can have different quota settings.
- Tenant A and Tenant B can have different policies.
- A resource created under Tenant A is not accessible under Tenant B.
Step 1: define two tenants
Start with two separate API keys.- Tenant A and Tenant B do not share a key.
- Tenant A and Tenant B do not share the same quota configuration.
Step 2: configure different policies for each tenant
Now give the two tenants different guardrail policies. Configure Tenant A to block the wordconfidential.
- Tenant A fails because
confidentialis blocked in Tenant A’s policy. - Tenant B does not inherit Tenant A’s policy.
Step 3: demonstrate separate quotas
After creating two keys with different limits, send the same type of request through both keys. Tenant A uses the low-limit key:- Tenant A starts receiving
429earlier. - Tenant B continues to succeed because it has a different key and a different quota.
Step 4: demonstrate resource isolation
Create a resource under Tenant A. A conversation is an easy example because it is visible through the public API.conv_tenant_a_123.
Tenant A can read it:
- the same API surface is used
- the same platform is used
- but identity, policy, quota, and resource ownership are enforced separately
Optional Step 5: show separate usage ledgers
If you want one more visible proof point, query usage separately per tenant.What this walkthrough proves
If you run the walkthrough above, you can make these exact claims:- Independent keys: Tenant A and Tenant B authenticate with different API keys.
- Independent quotas: Tenant A and Tenant B can have different rate-limit settings and receive different
429behavior. - Independent policies: Tenant A and Tenant B can set different guardrails and get different results on the same content.
- Real isolation: A resource created under Tenant A is not readable under Tenant B.
How the identity model works underneath
Authentication in the MKA1 API has three layers:- Your API key identifies your account.
X-On-Behalf-Ofidentifies the end user your server is acting for.- An exchanged JWT gives a downstream service a short-lived credential derived from that API key and end-user context.
- Send
Authorization: Bearer <mka1-api-key>on every server-side request. - Add
X-On-Behalf-Ofwhen the request belongs to one of your end users. - Use
POST /api/v1/authentication/api-keys/exchange-tokenwhen another service should receive a short-lived token instead of your raw API key.
The request path
The MKA1 API does not ask downstream services to validate bearer tokens on their own. Requests pass through the gateway first, and the gateway injects trusted identity headers for the rest of the platform. When you also sendX-On-Behalf-Of, the gateway keeps that delegated end-user identity with the request:
JWT exchange adds one extra step:
The three core patterns
Pattern 1: backend-only requests
Use this when your backend is calling the MKA1 API for its own workflow and there is no separate end user to track.Pattern 2: multi-user server integration
Use this when your backend is making the request for one of your own application users.Pattern 3: exchange your API key for a short-lived JWT
Use this when another service should receive a time-limited token instead of your long-lived API key.Which headers you send vs which headers the platform injects
Headers you send
Trusted headers injected inside the platform
Clients send
Authorization and sometimes X-On-Behalf-Of.
Clients do not send the internal X-User-ID or X-Api-Key-ID headers directly.
Those are derived by the gateway after validation.How JWT exchange works
POST /api/v1/authentication/api-keys/exchange-token turns a long-lived API key into a short-lived token for another service.
The legacy singular path
POST /api/v1/authentication/api-key/exchange-token (SDK: auth.apiKey.getJwtFromKey()) is deprecated and will be removed in a future release. Use POST /api/v1/authentication/api-keys/exchange-token (SDK: auth.apiKeys.exchangeToken()) instead.audience: the exact service URL that should accept the JWTexternalUserId: the end-user ID placed into the JWT subjectexpiresIn: token lifetime in seconds, from300to2592000permissions: an optional subset of the API key permissions
ak: the API key ID used for lookup and rate-limit enforcementsub: your delegated end-user identityaud: the service that should accept the tokenpermissions: the allowed capability set for that token
How tenant scoping works in practice
The most important design choice is that end-user identity is explicit. If you sendX-On-Behalf-Of: user_123, downstream services can keep resources and usage associated with that user.
This matters for:
- saved conversations
- stored responses
- files and vector stores
- per-user usage and audit trails
- delegated authorization checks
X-On-Behalf-Of, requests run as backend-only account work.
When you include it, the request becomes a delegated request for a specific end user.
Use a stable identifier from your own system.
Do not use a mutable display name unless that is already your canonical user ID.
Rate limits and what callers should expect
API keys can carry custom rate-limit settings. The auth path enforces rate limits per API key before the request reaches downstream services. In practice, this means:- two different API keys can have different limits
- one overloaded API key does not imply another key is exhausted
- a
429is part of the auth path, not a downstream model error
Common mistakes
Sending X-On-Behalf-Of from browser code
Do not expose your API key in browser or mobile client code.
Your server should call the MKA1 API and attach X-On-Behalf-Of there.
Using an unstable end-user identifier
Use a durable internal ID likeuser_123.
Do not switch between email addresses, usernames, and display names for the same user.
Using the wrong audience in exchanged JWTs
The downstream service should validate the token for the intended audience.
Set audience to the actual service URL that should accept the JWT.
Requesting permissions broader than the API key
The exchange-token endpoint only allows a subset of the API key permissions. If you request a permission the API key does not have, the exchange fails.Treating internal propagated headers as public client headers
Headers likeX-User-ID and X-Api-Key-ID are part of the trusted internal request path.
They are not a substitute for Authorization.
Code-path appendix
The following snippets show the main implementation shape behind the public behavior.Kong validates the bearer token and injects trusted headers
X-User-ID, X-Api-Key-ID, and X-Exchange-JWT-External-User-ID after gateway validation.