API Key Management¶
DB-managed API keys are stored as SHA-256 hashes in the TDB registry. The raw key value is shown once — at creation or rotation time — and cannot be retrieved afterwards. Keep it safe.
All key management endpoints require admin role. See RBAC →.
Key format¶
All DB-managed keys are prefixed with tdbk_ followed by 32 URL-safe random bytes:
Create a key¶
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string (1–100 chars) | Yes | Human-readable label |
expires_in_days |
integer > 0 | No | Key auto-expires after this many days. Omit for no expiry. |
rate_limit |
integer > 0 | No | Requests per minute. Omit to use the server default (TDB_DEFAULT_RATE_LIMIT, default 60). |
role |
"read", "readwrite", or "admin" |
No | RBAC role. Default: "admin". See RBAC →. |
Response (HTTP 201):
{
"key": {
"id": "f47ac10b-...",
"name": "ci-pipeline",
"key_prefix": "tdbk_a1b2",
"created_at": "2026-05-22T09:00:00Z",
"expires_at": "2026-08-20T09:00:00Z",
"revoked_at": null,
"last_used_at": null,
"rate_limit": 120,
"role": "read",
"allowed_tools": null
},
"raw_key": "tdbk_a1b2c3d4e5f6..."
}
Save the raw key now
The raw_key field is returned exactly once. It cannot be retrieved later.
If you lose it, rotate the key to get a new one.
List keys¶
Returns metadata for all keys (active, expired, and revoked). The raw key value is never included.
Response:
{
"keys": [
{
"id": "f47ac10b-...",
"name": "ci-pipeline",
"key_prefix": "tdbk_a1b2",
"created_at": "2026-05-22T09:00:00Z",
"expires_at": "2026-08-20T09:00:00Z",
"revoked_at": null,
"last_used_at": "2026-05-22T10:30:00Z",
"rate_limit": 120
}
]
}
The key_prefix (first 12 characters) lets you identify which key is which
without exposing the full value.
Revoke a key¶
Immediately invalidates the key. Revocation is permanent — use rotation instead if you want a replacement.
Returns HTTP 204 on success. Returns HTTP 404 if the key ID is not found or is already revoked.
Rotate a key¶
Atomically revokes the existing key and issues a replacement with the same name, expiry, and rate limit. The new raw key is returned once.
Response:
{
"key": {
"id": "new-uuid-...",
"name": "ci-pipeline",
"key_prefix": "tdbk_z9y8",
...
},
"raw_key": "tdbk_z9y8x7w6..."
}
The old key stops working immediately. Update the key value in your integration before the old one is rotated out.
Set key role¶
Change the RBAC role of a key at any time. Role changes take effect immediately on the next request.
Request body:
Valid values: "read", "readwrite", "admin".
Response: the updated key record.
See Role-based access control → for the full access matrix.
Restrict MCP tools¶
Limit which MCP tools a key is allowed to call. Pass null to restore unrestricted access (the default).
Request body — restrict to specific tools:
Request body — allow all tools:
When a key with a tool allow-list calls a disallowed tool, TDB returns a tool-error response (HTTP 200 with isError: true) rather than a protocol-level error, so MCP clients handle it gracefully.
Response: the updated key record.
Set per-key rate limit¶
Override the rate limit for a specific key. Pass null to reset to the server
default (TDB_DEFAULT_RATE_LIMIT).
Request body:
To reset to the server default:
Response: the updated key record.
Rate limiting behaviour¶
Rate limiting uses a fixed window aligned to calendar minutes (e.g., 09:00:00–09:00:59).
When a rate limit is exceeded, TDB returns HTTP 429 with headers:
Rate limiting applies to DB-managed keys only. Static env keys and JWT tokens are not rate-limited.
Key lifecycle example¶
# 1. Create a read-only key for a data analyst
curl -X POST http://localhost:8000/v1/auth/keys \
-H "Authorization: Bearer <YOUR_ADMIN_KEY>" \
-H "Content-Type: application/json" \
-d '{"name":"analyst-team","expires_in_days":90,"role":"read"}'
# Save the raw_key from the response
# 2. Create a readwrite key for a data pipeline that registers sources
curl -X POST http://localhost:8000/v1/auth/keys \
-H "Authorization: Bearer <YOUR_ADMIN_KEY>" \
-H "Content-Type: application/json" \
-d '{"name":"etl-pipeline","role":"readwrite"}'
# 3. Restrict an MCP key to query and schema tools only
curl -X PUT http://localhost:8000/v1/auth/keys/<key_id>/tools \
-H "Authorization: Bearer <YOUR_ADMIN_KEY>" \
-H "Content-Type: application/json" \
-d '{"tools":["query_source","schema_source"]}'
# 4. Use a read key to run a query
curl -X POST http://localhost:8000/v1/query \
-H "Authorization: Bearer tdbk_..." \
-H "Content-Type: application/json" \
-d '{"source_id":"...","sql":"SELECT COUNT(*) FROM data"}'
# 5. Rotate after 90 days (inherits same role)
curl -X POST http://localhost:8000/v1/auth/keys/<key_id>/rotate \
-H "Authorization: Bearer <YOUR_ADMIN_KEY>"
# 6. Revoke a key that's no longer needed
curl -X DELETE http://localhost:8000/v1/auth/keys/<key_id> \
-H "Authorization: Bearer <YOUR_ADMIN_KEY>"