Authentication

API key format, hash method, and how to authenticate against the data plane and Management API.

Data plane

All data-plane requests must include a tenant API key:

Authorization: Bearer sk_<48 hex chars>

Example:

curl http://localhost/v1/chat/completions \
  -H "Authorization: Bearer sk_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{"model": "my-model", "messages": [...]}'

Key format

ComponentValue
Prefixsk_
Secret part48 hex characters (24 random bytes)
Total length51 characters
Display prefixFirst 18 characters

Key storage

obleth never stores the raw key. On creation:

  1. The gateway generates 24 cryptographically random bytes.
  2. It hex-encodes them and prepends sk_.
  3. It computes SHA-256(full_secret_bytes) to produce the key hash.
  4. It stores the hash in Postgres (api_keys.key_hash) and Redis (obleth:key:{hex_hash}).
  5. It returns the full secret to the caller once.

On each request, the gateway re-hashes the incoming bearer token and looks up the hash. If Redis is cold or unavailable, it uses the in-process cache when possible.

Management API

All requests to the Management API (:9090) must include the admin bearer token:

Authorization: Bearer <OBLETH_ADMIN_TOKEN>
curl http://localhost:9090/api/v1/tenants \
  -H "Authorization: Bearer dev-admin-token"

There is no per-user RBAC for the Management API. The admin token is all-or-nothing. Protect it accordingly; see the Security guide.

Creating a key

curl -X POST http://localhost:9090/api/v1/tenants/$TENANT_ID/keys \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "my-app-key"}'

Response:

{
  "key": {
    "id": "...",
    "tenant_id": "...",
    "name": "my-app-key",
    "key_prefix": "sk_a1b2c3d4e5f6a1b",
    "disabled": false
  },
  "secret": "sk_a1b2c3d4e5f6..."
}

Key lifecycle

ActionEndpoint
CreatePOST /api/v1/tenants/{id}/keys
ListGET /api/v1/keys
DisablePUT /api/v1/keys/{id}/disabled with {"disabled": true}
DeleteDELETE /api/v1/keys/{id}

A disabled key returns 403 Forbidden. A deleted key returns 401 Unauthorized.