Skip to content

security(api): require bearer-token auth on all endpoints (closes #179)#193

Open
jeremylongshore wants to merge 3 commits into
SpillwaveSolutions:mainfrom
jeremylongshore:security/issue-179-bearer-auth
Open

security(api): require bearer-token auth on all endpoints (closes #179)#193
jeremylongshore wants to merge 3 commits into
SpillwaveSolutions:mainfrom
jeremylongshore:security/issue-179-bearer-auth

Conversation

@jeremylongshore
Copy link
Copy Markdown
Contributor

What & why

agent-brain-server exposed every endpoint with no authentication (#179). On the multi-agent same-box deployment pattern, any local process could read the whole index via /query or wipe it via DELETE /index127.0.0.1 is not an authorization boundary (OWASP API1/API2:2023).

This adds bearer-token auth on every endpoint except /health, implementing the three adjustments you green-lit on #179.

How

Q1 — secure by default (not opt-in). agent-brain init auto-generates a key (secrets.token_urlsafe(32)) into .agent-brain/runtime.json at mode 600; the server backfills one on first start if absent (smooth upgrade for existing installs). The server refuses to start without a key unless --insecure is passed (loud warning) — mirroring Postgres --allow-empty-password / Redis protected-mode no. The CLI reads the key from runtime.json and sends it automatically, so single-user dev stays frictionless.

Q2 — Authorization: Bearer (not X-API-Key), for forward-compat with the MCP v4 OAuth 2.1 work (#188) — one scheme that evolves from a static key to OAuth-issued bearer tokens.

Q3 — docs gated. /docs, /redoc, /openapi.json are served only when DEBUG=true, so shared/prod hosts don't leak the API surface.

verify_bearer_token uses constant-time comparison, 401s on missing/malformed/wrong credentials, and fails closed (503) if auth is required but no key is configured.

Tests

  • Server (tests/test_api_auth.py, 17): every dependency branch (valid / missing / wrong / wrong-scheme / insecure / misconfigured), HTTP integration (/health open, /query 401 without token, 401 wrong, 200 right, insecure bypass), key generation + runtime.json mode-600 persistence + refuse-to-start.
  • CLI (tests/test_api_key_auth.py, 7): get_api_key resolution (env > runtime.json > none) and Authorization: Bearer header attachment.
  • Existing suite kept green via a session-scoped auth-bypass fixture; real auth is exercised explicitly in the new tests.
  • task server:pr-qa-gate: 1219 passed, 79.26% coverage.

Notes

  • Branch security/issue-179-bearer-auth per your <type>/issue-<N>-<slug> convention.
  • No version bumps (keeps the server/CLI alignment check green).
  • --insecure opt-out preserved for trusted single-user localhost dev.

Closes #179.

  • Jeremy Longshore
    intentsolutions.io

…llwaveSolutions#179)

Every endpoint except /health now requires `Authorization: Bearer <key>`.
127.0.0.1 is not an authorization boundary: on the multi-agent same-box
deployment pattern any local process could read the index via /query or
wipe it via DELETE /index (OWASP API1/API2:2023).

Implements the three adjustments green-lit on SpillwaveSolutions#179:

- Q1 secure-by-default: key auto-generated by `agent-brain init` into
  .agent-brain/runtime.json (mode 600); server backfills on first start;
  refuses to start without a key unless --insecure (loud warning), like
  Postgres --allow-empty-password / Redis protected-mode no. CLI sends the
  key automatically so single-user dev stays frictionless.
- Q2 Authorization: Bearer (not X-API-Key) for forward-compat with the
  MCP v4 OAuth 2.1 work (SpillwaveSolutions#188).
- Q3 /docs /redoc /openapi.json gated unless DEBUG=true.

verify_bearer_token uses constant-time comparison, 401s on missing/bad
credentials, and fails closed (503) if auth is on but misconfigured.

Tests: server 17 (unit branches + HTTP 401/200 + insecure + key
persistence + refuse-to-start), CLI 7 (key resolution + bearer header).
Existing suite kept green via a session-scoped auth-bypass fixture.
server:pr-qa-gate: 1219 passed, 79.26% coverage. No version bumps.
…illwaveSolutions#179)

`agent-brain init` now writes runtime.json to store the API key (Issue SpillwaveSolutions#179),
so `agent-brain stop` with no server running finds a PID-less runtime and was
reporting "No server PID found in runtime state" instead of "No server running"
— breaking test_stop_no_server_running. A runtime.json without a PID means no
server is running; report that. JSON status stays "not_running".
…pillwaveSolutions#179)

Match the repo convention (security PRs add a [Unreleased] ### Security
entry to docs/CHANGELOG.md, as SpillwaveSolutions#180 and SpillwaveSolutions#181 did) so the maintainer
doesn't have to add it on review.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

security(api): server exposes all endpoints with no authentication (critical)

1 participant