How to mint, list, disable, and delete tenant API keys, and how obleth stores them securely.
API keys are the credentials clients use to authenticate with the obleth data plane. Every key belongs to exactly one tenant and inherits that tenant's weight, quota, and fairshare group.
obleth never stores the raw secret. When a key is created:
sk_ + 48 random hex characters).sha256(secret) is stored in Postgres (api_keys.key_hash).sk_a1b2c3d4e5f6a1b) is stored for dashboards.ResolvedKey (tenant details + weight + quota) is synced to Redis at obleth:key:{hash}.The raw secret is returned once in the creation response. If you lose it, the only option is to delete the key and create a new one.
curl -X POST http://localhost:9090/api/v1/tenants/$TID/keys \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "prod"}'
Response:
{
"key": {
"id": "...",
"tenant_id": "...",
"name": "prod",
"key_prefix": "sk_a1b2c3d4e5f6a1b",
"disabled": false,
"created_at": "2026-01-15T10:00:00Z"
},
"secret": "sk_a1b2c3d4e5f6..."
}
# All keys for a specific tenant
curl http://localhost:9090/api/v1/tenants/$TID/keys \
-H "Authorization: Bearer $TOKEN"
# All keys across all tenants (with optional filters)
curl "http://localhost:9090/api/v1/keys?limit=50" \
-H "Authorization: Bearer $TOKEN"
Disabling a key immediately prevents it from authenticating without deleting the key's audit history:
curl -X PUT http://localhost:9090/api/v1/keys/$KEY_ID/disabled \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"disabled": true}'
The change is synced to Redis and invalidated in moka across all pods. The key returns 403 api key disabled immediately on the next request.
Re-enable:
curl -X PUT http://localhost:9090/api/v1/keys/$KEY_ID/disabled \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"disabled": false}'
curl -X DELETE http://localhost:9090/api/v1/keys/$KEY_ID \
-H "Authorization: Bearer $TOKEN"
This removes the key from Postgres and Redis. The audit log retains the deletion event. Any client using the deleted key will receive 401 invalid api key.
To rotate a key with zero downtime:
POST /api/v1/tenants/$TID/keysDELETE /api/v1/keys/$OLD_KEY_IDDon't use disable+enable for rotation — just create a new one and delete the old.
A tenant can have many keys. All keys for the same tenant share the same weight and quota. Useful patterns:
prod, staging, cichatbot, search, summarizerUsage in ClickHouse is recorded per key_id, so you can break down cost by key even within the same tenant.