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):
- Authenticated. A non-empty
Bearer …header of length > 10 characters grants theAUTHENTICATEDtier. This is the tier used by the production API key. - Signed virtual session. A
v1:session_id:timestamp:hmacheader issued by the gateway itself. - Repo fingerprint. A hash of
repo_path+client_signature. Confidence must be ≥ 0.8 (i.e. both inputs are non-trivial). - 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
userfield 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:
- Stop traffic:
docker compose -p smart-supervisor-production -f /srv/apps/smart-supervisor-production/docker-compose.production.yml stop gateway. - Rotate the key in
.env.productionimmediately. - Restart the gateway.
- Audit
sgw_requests_totaland the structured routing logs for any traffic from the leaked identity. - 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).