Skip to content

Gateway: send each engine its own key, never the node's - #126

Merged
T-Crypt merged 5 commits into
mainfrom
T-Crypt/ninfer-n1-engine-key
Oct 21, 2026
Merged

T-Crypt merged 5 commits into
mainfrom
T-Crypt/ninfer-n1-engine-key

Conversation

@T-Crypt

@T-Crypt T-Crypt commented Oct 21, 2026

Copy link
Copy Markdown
Owner

OME GWV6JQR, found while reviewing #114.

Clients authenticate to the gateway with the node's API key. The reverse proxy passed that Authorization header on to every engine, so each engine, its logs and any proxy in front of it saw the node key, and an engine with its own credential got the wrong one. #114 dropped it on the fallback hop only.

Every proxied route now goes through one function, engineAuth. It removes the client's header and sends the engine's own key when its entry has one (api_key_env or api_key_file). This covers the OpenAI routes, the fallback, POST /prompt and the rest of the ComfyUI routes. A discovered engine with no entry gets no Authorization. A credential that will not resolve sends none and logs one WARN line that names the engine and the error, never the key.

Who notices: anyone whose engine checked the node's key. They need to give that engine its own key in berth.toml. The CHANGELOG says so under a new Security heading.

Proof:

  • TestProxySendsNoKeyToACredentiallessEngine and TestComfyRoutesSendNoKey fail against main's gateway (the engine receives the node key) and pass with this change.
  • Tests for an engine's own key, the fallback's own key, and an unresolvable key (one WARN line, no key in it).
  • Full proof green: build, gofmt, vet, go test ./..., go test -race ./internal/gateway, Windows build and vet, golangci-lint (0 issues). mkdocs build --strict passes.

Red: an engine without its own credential receives the client's node
key. It is the client's credential for this gateway, not for the
engine.
… node's

The guard checks the client's node key and the reverse proxy passed
that header on, so every engine, its logs and any proxy in front of
it saw the node's API key. One engineEntry now finds the configured
entry behind a target (its own entry when the gateway may start it,
otherwise the entry whose url is the target's; a discovered engine
has none), and engineAuth sets the engine's own bearer from
api_key_env or api_key_file on every proxied route: forward for the
primary and, on a fallback switch, for the fallback, and the
ComfyUI routes. An engine without a credential, or a credential that
will not resolve, gets no Authorization; the latter logs one WARN
line naming the engine and the error, never the key. The request
goes through either way.
An engine without a credential receives no Authorization; one with
api_key_env receives its own bearer; a fallback with its own key
receives that key; the ComfyUI routes receive none; a credential that
will not resolve sends nothing and logs one WARN line naming the
engine and the error, never the key.
One paragraph next to the API key bullet: a proxied request carries
the engine's own key from its entry when it has one, none otherwise,
and a credential that will not resolve logs one WARN line, never the
key. The fallback section says the same of a fallback with its own
key, and the CHANGELOG gains a Security entry that tells a user whose
engine checked the node's key to give that engine its own.
@T-Crypt
T-Crypt merged commit 419b88f into main Oct 21, 2026
4 checks passed
@T-Crypt
T-Crypt deleted the T-Crypt/ninfer-n1-engine-key branch October 21, 2026 23:09
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.

1 participant