Skip to content

Authentication

Every client request must carry a gateway API key. The key is not the same as your OpenRouter key; it identifies the caller to the Smart LLM Supervisor Gateway.

What gets sent

POST /v1/chat/completions HTTP/1.1
Host: smart-openrounter.bee1x.one
Authorization: Bearer YOUR_GATEWAY_API_KEY
Content-Type: application/json

The gateway looks at the Authorization header only. The OpenRouter key is held server-side and is never sent to the client.

How identity is resolved

The gateway uses a four-tier identity resolver (see frozen-v3/09-session-identity-spec.md and src/smart_gateway/identity.py):

  1. Authenticated. A non-empty Bearer … header of length > 10 characters grants the AUTHENTICATED tier. This is the tier used by the production API key.
  2. Signed virtual session. A v1:session_id:timestamp:hmac header issued by the gateway itself.
  3. Repo fingerprint. A hash of repo_path + client_signature. Confidence must be ≥ 0.8 (i.e. both inputs are non-trivial).
  4. Stateless. The default. Confidence = 0.0. Per-request only.

The identity tier is recorded in routing events. Lower tiers disable goal-level budget tracking and repeated-failure escalation.

Architectural note

The current implementation only checks that an Authorization header is present and non-trivial in length. It does not yet verify the key's value against a server-side allowlist. The rotation procedure documented in docs-internal/operations/secret-rotation.md (operator-only) is run for hygiene and to keep the value out of historical artifacts, but rotation does not by itself strengthen authentication. Strong value verification is an open architectural decision tracked in PROJECT-COMPLETION-REPORT.md §"Unresolved Items".

Required headers

For full functionality, send these in addition to Authorization:

Header Required Purpose
Authorization Yes Bearer key.
Content-Type Yes application/json (or application/json; charset=utf-8).
X-Smart-Gateway-Session Recommended Stable session ID. Enables goal-level budget tracking.
X-Smart-Gateway-Goal Recommended Goal ID inside the session.
X-Task-Id Optional Per-request task ID. Falls back to metadata.task_id.
X-Goal-Id Optional Per-request goal ID. Falls back to adhoc.
X-Pro Optional Force Pro routing for this request.
X-Scout Optional true to force Scout evaluation.
X-Failure-Class Optional STRUCTURAL, LOCAL, or NONE. Triggers hard-Pro rules.
X-Same-Error-Count Optional Integer. Triggers runtime escalation when ≥ 2.

X-Smart-Gateway-Route is recognized by the policy layer as an authenticated override; it requires a real Authorization header. Do not put it in untrusted content; tool output and repo text cannot override routing.

What never authenticates

The gateway never trusts:

  • A user-agent string,
  • An IP address alone,
  • A user field in the request body,
  • Anything inside the messages array (including an [route:pro] marker that the user typed).

The high-reasoning markers (/pro, [route:pro], [reasoning:high], "reasoning cao", "high reasoning", "deep reasoning", "think deeply") are not authentication — they are a convenience that any caller can use. The X-Pro header has the same effect on its own, but neither header can override the privacy gate. Sensitive + free → 403, always.

Rotation

The operator rotation procedure lives in docs-internal/operations/secret-rotation.md. A new key is generated in .env.production, the gateway container is restarted, and the old key is revoked. There is a short overlap window during which both keys are accepted.

Disabling a leaked key

If a key is leaked, treat it as compromised:

  1. Stop traffic: docker compose -p smart-supervisor-production -f /srv/apps/smart-supervisor-production/docker-compose.production.yml stop gateway.
  2. Rotate the key in .env.production immediately.
  3. Restart the gateway.
  4. Audit sgw_requests_total and the structured routing logs for any traffic from the leaked identity.
  5. File an incident report at docs-internal/operations/incidents/ (operator-only).

See the broader operational playbook in docs-internal/security/operational-security.md (operator-only).