API Keys
Issue scoped, rate-limited credentials so frontends and integrations can consume the REST API safely.
Routes
| Route | Method | Purpose |
|---|---|---|
/admin/api-keys | GET | List keys |
/admin/api-keys/create | GET | New key form |
/admin/api-keys | POST | Create key (secret shown ONCE on response) |
/admin/api-keys/{key}/edit | GET | Edit key metadata |
/admin/api-keys/{key} | PUT | Update scopes, origins, rate limit, expiry |
/admin/api-keys/{key} | DELETE | Revoke (soft delete) |
Key attributes
| Field | Description |
|---|---|
name | Human-readable label ("Website Production", "Mobile App") |
key | Public identifier sent in request headers (unique, 32 chars) |
secret_hash | bcrypt hash of the secret — plaintext never stored |
scopes | JSON array: read, write, delete |
allowed_origins | JSON array of CORS origins (wildcard * allowed) |
rate_limit | Requests per minute (default 60) |
expires_at | Optional auto-expiry timestamp |
is_active | Soft pause without deletion |
usage_count | Lifetime request count (incremented by the api.log middleware) |
last_used_at / last_used_ip | Diagnostics |
Scopes
- read — GET endpoints (always allowed for any active key)
- write — POST / PUT endpoints
- delete — DELETE endpoints
Scopes are enforced by the api.scope middleware on a per-route basis. See API: Authentication & Scopes for full details.
Rate limiting
The api.rate middleware applies a sliding window keyed by the API key's UUID, defaulting to the key's rate_limit value (requests/min). Exceeded limits return 429 Too Many Requests with a Retry-After header.
CORS
The api.cors middleware checks the request's Origin header against allowed_origins. Empty or wildcard lists allow any origin. Preflight (OPTIONS) requests are handled automatically.
Secret handling
Request audit
Every authenticated request is logged to api_request_logs by the api.log middleware: API key, endpoint, status, duration, IP, user agent. View the trail per-key on the API Key detail page.