API Authentication¶
⚠️ Known gap:
GET /monitoring/*endpoints are currently unauthenticated. These endpoints expose Celery queue stats, worker status, task results, and Evidently drift reports. Restricting them to authenticated callers is planned — see Implementation Status and Roadmap.
All POST /predict/* and GET /predict/* endpoints require an X-API-Key
request header. Requests without a valid key are rejected with HTTP 401.
Authentication scheme¶
| Property | Value |
|---|---|
| Header name | X-API-Key |
| Comparison | hmac.compare_digest (constant-time, prevents timing attacks) |
| Transport | TLS-only in production |
| OpenAPI scheme | ApiKeyAuth (type: apiKey, in: header) |
The key value is set via the FASTAPI_HEADER_TOKEN environment variable.
Exempt endpoints¶
The following endpoints do not require authentication:
| Endpoint | Reason |
|---|---|
GET / |
Root / landing |
GET /healthcheck/ |
Kubernetes liveness probe |
GET /metrics |
Prometheus scrape |
GET /monitoring/* |
Internal ops monitoring |
Generating a key¶
# Generate a random 32-byte hex key
python -c "import secrets; print(secrets.token_hex(32))"
# Set in .env (never commit)
FASTAPI_HEADER_TOKEN=<generated_key>
For production, store the key in SOPS-encrypted secrets and inject via K8s Secret.
Using the key¶
# cURL example
curl -X POST https://<host>/predict/ \
-H "X-API-Key: $FASTAPI_HEADER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"match_id": "abc123"}'
# Python example
import httpx
resp = httpx.post(
"https://<host>/predict/",
headers={"X-API-Key": api_key},
json={"match_id": "abc123"},
)
Testing¶
Auth behaviour is covered by tests/service/test_auth.py:
- 401 without key
- 401 wrong key
- Non-401 with correct key
- Structural test: hmac.compare_digest used in source
In tests, the auth dependency is bypassed via app.dependency_overrides.