feat: API authentication -- bearer token / API key for all REST endpoints #49

Closed
opened 2026-05-26 23:05:27 -07:00 by pyr0ball · 1 comment
Owner

The Turnstone REST API currently has no authentication. All endpoints are open to anyone who can reach port 8534. This is acceptable on a trusted LAN but not for any deployment that faces an enterprise network or is proxied publicly.

Design:

  • Static API key loaded from TURNSTONE_API_KEY env var (simple, no DB overhead)
  • If env var is set: all requests to /api/* require Authorization: Bearer <key> or X-API-Key: <key> header
  • If env var is unset: behave as today (no auth) -- preserves backward compat for local homelab use
  • SSE endpoints (/api/diagnose/stream, /api/glean/stream) must also be protected
  • Frontend reads key from TURNSTONE_API_KEY passed as VITE_API_KEY build var or runtime config endpoint

What auth does NOT cover in this issue:

  • Multi-user (out of scope -- this is single-operator auth)
  • OAuth / OIDC (out of scope)
  • Per-source ACLs (separate issue)

Acceptance criteria:

  • curl http://localhost:8534/api/sources returns 401 when key is set and header is absent
  • curl -H "X-API-Key: mykey" http://localhost:8534/api/sources returns 200
  • Frontend passes key transparently (user sets it once in settings or env)
  • Unit test: middleware blocks requests without valid key
The Turnstone REST API currently has no authentication. All endpoints are open to anyone who can reach port 8534. This is acceptable on a trusted LAN but not for any deployment that faces an enterprise network or is proxied publicly. **Design:** - Static API key loaded from `TURNSTONE_API_KEY` env var (simple, no DB overhead) - If env var is set: all requests to `/api/*` require `Authorization: Bearer <key>` or `X-API-Key: <key>` header - If env var is unset: behave as today (no auth) -- preserves backward compat for local homelab use - SSE endpoints (`/api/diagnose/stream`, `/api/glean/stream`) must also be protected - Frontend reads key from `TURNSTONE_API_KEY` passed as `VITE_API_KEY` build var or runtime config endpoint **What auth does NOT cover in this issue:** - Multi-user (out of scope -- this is single-operator auth) - OAuth / OIDC (out of scope) - Per-source ACLs (separate issue) **Acceptance criteria:** - `curl http://localhost:8534/api/sources` returns 401 when key is set and header is absent - `curl -H "X-API-Key: mykey" http://localhost:8534/api/sources` returns 200 - Frontend passes key transparently (user sets it once in settings or env) - Unit test: middleware blocks requests without valid key
pyr0ball added this to the beta milestone 2026-05-26 23:05:27 -07:00
pyr0ball added the
enhancement
security
labels 2026-05-26 23:05:27 -07:00
Author
Owner

Implemented in app/rest.py.

  • TURNSTONE_API_KEY env var (unset = no auth, backward compatible)
  • _check_api_key(request) FastAPI dependency using hmac.compare_digest for timing-safe comparison
  • Applied to both router and _ctx (context endpoints) via dependencies=[Depends(...)]
  • /turnstone/health always open for monitoring tools
  • 401 when header missing, 403 when token wrong
  • Token generation command added to .env.example
Implemented in `app/rest.py`. - `TURNSTONE_API_KEY` env var (unset = no auth, backward compatible) - `_check_api_key(request)` FastAPI dependency using `hmac.compare_digest` for timing-safe comparison - Applied to both `router` and `_ctx` (context endpoints) via `dependencies=[Depends(...)]` - `/turnstone/health` always open for monitoring tools - 401 when header missing, 403 when token wrong - Token generation command added to `.env.example`
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Circuit-Forge/turnstone#49
No description provided.