Authentication
Verdifax authenticates API callers via a single header. Keys are provisioned out-of-band and shown to the operator exactly once.
Header
X-Verdifax-Key: vfx_<24-byte-random-hex>
Every authenticated endpoint accepts the same header. /health is public.
Two modes
Open mode, when no API keys exist in the database (a fresh deploy, before any key has been provisioned), every authenticated endpoint admits the caller as anonymous (api_key_id = 0). This keeps the docker quickstart trivial.
Locked mode, once any key exists, the API server enforces the header. Calls without a valid X-Verdifax-Key get 401. Run history is scoped to the key that produced it: /runs only returns runs owned by the calling key, and /runs/{id} 404s if the key didn't own that run.
Provisioning a key
curl -s -X POST http://localhost:9090/admin/keys \
-H "Content-Type: application/json" \
-d '{"name":"compliance-team-2026"}' | python3 -m json.tool
{
"ok": true,
"id": 1,
"name": "compliance-team-2026",
"secret": "vfx_a1b2c3d4...",
"hint": "Store this secret now, it will never be shown again."
}
The server stores only sha256(secret). Lose the secret and you must revoke + reissue.
Listing keys
curl -s http://localhost:9090/admin/keys \
-H "X-Verdifax-Key: vfx_..." | python3 -m json.tool
Returns names, creation timestamps, last-used timestamps, run counts, and revocation status, never the secrets.
Revoking a key
curl -s -X DELETE http://localhost:9090/admin/keys/1 \
-H "X-Verdifax-Key: vfx_..."
Revocation is immediate. Subsequent calls with that key get 401.
Rate limiting
Every authenticated endpoint is rate-limited at 100 requests/minute per key by default (configurable via --rate-limit). Anonymous callers in open mode are limited per remote address.
