Skip to content

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.