Px/

Tenant Management

Create and manage SaaS tenants, retrieve bootstrap keys, and configure per-tenant identity providers via the admin API.

Edit this page on GitHub

In 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:

rounded-md border px-1.5 py-0.5 font-mono text-[0.82em]
X-Admin-Api-Key: your-admin-key
# or
Authorization: Bearer your-admin-key

The key is configured via the ADMIN_API_KEY environment variable at startup.

Create a tenant#

bash
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:

json
{
  "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#

bash
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.

bash
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#

bash
curl \
  https://api.permix.dev/admin/tenants/{id}/identity-providers \
  -H "X-Admin-Api-Key: $ADMIN_KEY"

Remove an identity provider#

bash
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:

  1. Extracts the iss (issuer) claim from the JWT header.
  2. Looks up the registered IdP for that issuer via ValidatorCache.
  3. Fetches the JWKS from the IdP's jwks_uri and verifies the token signature.
  4. Applies the tenant's claim_config to extract roles, domain, and admin_domain.
  5. 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.