Authentication
API keys
The primary auth method is an API key issued from the portal.
- Format:
cloak_<base32>— 256 bits of entropy. - Header:
Authorization: Bearer cloak_…
Get an API key (headless / no browser)
You do not need a browser to get a working key. A single unauthenticated
POST returns a real, immediately-usable free-tier key for the SDK, the
gateway API, and the MCP server — ideal for CI, containers, and scripts.
# Anonymous, on-device key (no email needed):curl -sS -X POST https://api.cloakapi.io/api/v1/self-service/key \ -H 'Content-Type: application/json' -d '{}'
# …or attach an email so you can later verify it, claim a $2 trial credit,# and manage the key in the portal:curl -sS -X POST https://api.cloakapi.io/api/v1/self-service/key \ -H 'Content-Type: application/json' \ -d '{"email":"you@example.com","name":"my-ci-key"}'Response (201):
{ "api_key": "cloak_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "key_prefix": "cloak_XXXXXX", "tier": "free", "limits": { "rate_limit_rpm": 20, "on_device": "SDK + MCP tokenise / detokenise / detect / device-receipts work immediately.", "relay": "Content-blind LLM relay needs a positive wallet balance (402 at $0)." }, "warning": "This key is shown ONCE and is not recoverable. Store it securely."}Then use it straight away:
export CLOAKAPI_API_KEY=cloak_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # SDK + MCP read this# API: Authorization: Bearer $CLOAKAPI_API_KEYWhat the free tier gives you
- On-device work is unlimited and free —
detect_pii/tokenize/detokenize/ device-receipts in the SDK and the MCPtokenisefamily run entirely on your machine; the key only authenticates and attributes usage. - Rate-limited to
20requests/minute per key. - LLM relay is balance-gated. A fresh free-tier key has a
$0wallet, so the content-blind relay (POST /api/v1/chat/completions,/api/v1/messages) returns402 insufficient_balanceuntil you add credit. Verify your email for a$2trial credit, or top up at app.cloakapi.io/billing.
Guard rails. The endpoint is IP-rate-limited (≤5/hour, ≤20/day per network)
and refuses to mint a key onto an email that already has an account (409 account_exists — sign in at the portal instead). It never grants a paid tier or
touches another account.
- Scope: per-organisation. Sub-organisations (partner mode) get distinct keys with their own quotas, rate limits, and balances.
- Rotation: rotate at any time from API keys → Rotate. The previous key is deactivated immediately — deploy the new key right away (see Key rotation).
- Revocation: instant. Revoked keys return
401with a structurederror.code: "key_revoked"payload.
OIDC SSO
For human (portal) login, the gateway exposes a standard OIDC discovery surface:
| Endpoint | Path |
|---|---|
| Discovery | /.well-known/openid-configuration |
| JWKS | /oauth/jwks |
| Userinfo | /oauth/userinfo |
| Token | /oauth/token (standard OAuth2) |
| Authorize | /oauth/authorize |
Today this is backed by Laravel Passport. An Authentik identity provider is live at auth.cloakapi.io for federated / enterprise SSO flows; portal password login remains Laravel-native.
Per-request scoping
Inside the gateway, requests are scoped by:
- Tenant — derived from the API key.
- Sub-organisation — for partner / white-label flows.
- Capability — fine-grained allowlist (
gpt-4o,claude-sonnet-4-6, …) enforced before provider routing. - Quota — monthly token budget per (tenant, capability).
- Rate limit — sliding-window per (tenant, capability) at 60s and 3600s scales.
Per-key scope allowlist (permissions)
Each cloak_* API key carries a permissions array. The current enforced
vocabulary is published at GET /api/v1/keys/scopes
and contains:
| Scope | What it grants |
|---|---|
messages | POST /api/v1/messages (Anthropic-format chat) |
completions | POST /api/v1/chat/completions (OpenAI-format chat) |
buffer | Reserved for portal-side buffered-response reads (Sanctum-PAT) |
Semantics:
-
An empty or null
permissionsarray is treated as fully permissive (back-compat with keys minted before the allowlist was enforced). -
When
permissionsis non-empty and does not contain the scope a route requires, the gateway returns HTTP 403 with the structured envelope:{"error": {"type": "permission_error","code": "insufficient_scope","message": "This API key is not authorised for the 'completions' capability.","required": ["completions"],"granted": ["messages"]}}
Portal personal-access tokens (Sanctum PATs) are a separate axis used by
the dashboard and /api/v1/keys, /api/v1/billing/*, /api/v1/webhooks*
and the admin-session/* console. Their vocabulary is published in the UI
and includes abilities:write, ability:keys.read, ability:keys.write,
ability:billing.read, ability:billing.write, ability:byok.write, and
ability:admin. A cloak_* gateway key is never valid for those
portal routes, and a Sanctum PAT is never valid for /api/v1/messages
or /api/v1/chat/completions.