Authentication
How callers authenticate to Permix — JWT bearer tokens, service API keys, and the admin API key for SaaS operations.
Edit this page on GitHubPermix supports three authentication modes. Which one you use depends on who is calling and from which part of the API.
JWT bearer tokens#
Most API calls are authenticated with a short-lived JWT issued by your identity provider. Pass the token in the standard Authorization header:
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6...The service validates the token's signature against the JWKS endpoint, then extracts claims to determine the caller's identity, roles, and domain.
Required claims:
| Claim | Description |
|---|---|
sub | Subject — the user or service identity |
iss | Issuer — used to look up the JWKS endpoint |
exp | Expiration time — tokens past expiry are rejected |
configured roles_claim | Roles array (default: realm_access.roles) |
configured domain_claim | Tenant domain (default: dom) |
See JWT for validation details and Identity Providers for claim configuration.
Service API keys#
Service-to-service calls that run outside a user session can use long-lived service API keys. Pass the key in the X-Service-Api-Key header:
X-Service-Api-Key: sak_live_xxxxxxxxxxxxxxxxService API keys are scoped to a tenant and carry a fixed set of permissions. They are ideal for background workers, CLI tools, and internal microservices that cannot obtain a JWT from an identity provider at runtime.
Create a service API key#
curl -X POST https://api.permix.dev/api/v1/service-api-keys \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "batch-importer",
"description": "Nightly invoice batch import worker"
}'Response 201:
{
"id": "sak_abc123",
"name": "batch-importer",
"key": "sak_live_xxxxxxxxxxxxxxxx",
"created_at": "2026-05-10T08:00:00Z"
}Store the key immediately
The raw key value is returned only once at creation. Store it in your secrets manager — it cannot be retrieved again.
List and revoke service API keys#
# List
GET /api/v1/service-api-keys
# Revoke
DELETE /api/v1/service-api-keys/{id}Admin API key#
SaaS admin operations (tenant provisioning, identity provider management) use a separate admin API key configured at deployment time via the ADMIN_API_KEY environment variable. Pass it as either:
X-Admin-Api-Key: your-admin-key
# or
Authorization: Bearer your-admin-keyAdmin routes are only mounted in MODE=saas. See Tenant Management for available admin endpoints.
Authentication by endpoint group#
| Endpoint group | Auth method |
|---|---|
GET /healthz/* | None — public |
POST /api/v1/check | JWT bearer |
POST /api/v1/resources/access/check | JWT bearer (forwarded by Java SDK) |
GET/POST/PUT/DELETE /api/v1/resources/* | JWT bearer or service API key |
GET/POST/PUT/DELETE /api/v1/abac/policies/* | JWT bearer or service API key |
GET/POST/DELETE /api/v1/service-api-keys/* | JWT bearer |
GET/POST/DELETE /admin/* | Admin API key |
Self-hosted mode#
In MODE=selfhost, all JWT tokens are validated against a single global JWKS URI configured via environment variables. There is no per-tenant IdP lookup.
OIDC_ENABLED=true
AUTH_SERVER_URL=https://keycloak.example.com/realms/myrealm
JWKS_URI=https://keycloak.example.com/realms/myrealm/protocol/openid-connect/certsSee Deployment for the full environment variable reference.