Tenant Management
Create and manage SaaS tenants, retrieve bootstrap keys, and configure per-tenant identity providers via the admin API.
Edit this page on GitHubIn MODE=saas, every resource, ABAC policy, and RBAC rule is scoped to a tenant. Platform operators manage tenants through the /admin/* endpoints, which require an X-Admin-Api-Key header.
SaaS mode only
Tenant management endpoints are only active when MODE=saas. In selfhost mode, all operations use a single implicit tenant and the admin routes are not mounted.
Authentication#
All admin endpoints require the admin API key either as:
X-Admin-Api-Key: your-admin-key
# or
Authorization: Bearer your-admin-keyThe key is configured via the ADMIN_API_KEY environment variable at startup.
Create a tenant#
curl -X POST https://api.permix.dev/admin/tenants \
-H "X-Admin-Api-Key: $ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Corp",
"slug": "acme"
}'Response 201:
{
"id": "tenant_abc123",
"name": "Acme Corp",
"slug": "acme",
"bootstrapKey": "bk_live_xxxxx"
}Save the bootstrap key
The bootstrapKey is returned only once at creation time. Store it securely — it is the initial admin credential for this tenant and cannot be retrieved again.
List tenants#
curl https://api.permix.dev/admin/tenants \
-H "X-Admin-Api-Key: $ADMIN_KEY"Register an identity provider#
Each tenant must have an identity provider (IdP) configured before SaaS JWT tokens can be validated.
curl -X POST \
https://api.permix.dev/admin/tenants/{id}/identity-providers \
-H "X-Admin-Api-Key: $ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"issuer_url": "https://keycloak.acme.com/realms/acme",
"jwks_uri": "https://keycloak.acme.com/realms/acme/protocol/openid-connect/certs",
"claim_config": {
"roles_claim": "realm_access.roles",
"domain_claim": "dom",
"admin_domain_claim": "adm"
}
}'One IdP per tenant
Each tenant supports one active identity provider. Attempting to add a second IdP returns HTTP 409. Remove the existing IdP first before registering a new one.
List identity providers#
curl \
https://api.permix.dev/admin/tenants/{id}/identity-providers \
-H "X-Admin-Api-Key: $ADMIN_KEY"Remove an identity provider#
curl -X DELETE \
https://api.permix.dev/admin/tenants/{id}/identity-providers/{idpId} \
-H "X-Admin-Api-Key: $ADMIN_KEY"How SaaS JWT validation works#
When a request arrives in SaaS mode, the middleware:
- Extracts the
iss(issuer) claim from the JWT header. - Looks up the registered IdP for that issuer via
ValidatorCache. - Fetches the JWKS from the IdP's
jwks_uriand verifies the token signature. - Applies the tenant's
claim_configto extractroles,domain, andadmin_domain. - Scopes all database queries to the resolved
tenant_id.
The ValidatorCache is keyed per issuer URL and refreshes its JWKS TTL automatically.
Tenant data isolation#
All resource, ABAC policy, and RBAC rule tables include a tenant_id foreign key. Queries in SaaS mode always include a WHERE tenant_id = ? clause derived from the validated JWT. There is no cross-tenant data bleed at the database layer.