Repository navigation
[Bug]: codex injector still emits legacy env_http_headers; runtime 0.146+ contract is env_key #2073
Description
Summary
src/codex/inject.ts still emits the legacy env_http_headers = { "x-opencodex-api-key" = "OPENCODEX_API_AUTH_TOKEN" } line when injecting the opencodex provider into $CODEX_HOME/config.toml. Since codex-cli 0.146 the runtime contract for custom model providers is env_key = "<VAR>" (the proxy must read the API key from that environment variable), and env_http_headers with a dedicated x-opencodex-api-key header is no longer the preferred transport.
This is the generator side of the auth contract already fixed server-side in #1686: #1686 made /v1/responses accept an Authorization: Bearer admission token (what env_key produces), but the injector still writes the old header form, so fresh installs do not benefit from the modern contract.
Concretely, the divergence is visible today:
| Source | Form emitted |
|---|---|
src/codex/inject.ts (current main) |
env_http_headers = { "x-opencodex-api-key" = "OPENCODEX_API_AUTH_TOKEN" } |
src/grok/* injector (per #1686 body) |
env_key = "..." |
| codex-cli 0.146+ documented contract | env_key = "<VAR>" |
Reproduction
# 1. Install opencodex, start the proxy, run any sync that injects the provider:
ocx start # or: ocx sync
# 2. Inspect the generated provider block:
grep -n "env_key\|env_http_headers" "$CODEX_HOME/config.toml"
# → env_http_headers = { "x-opencodex-api-key" = "OPENCODEX_API_AUTH_TOKEN" }
# (legacy form — the modern runtime prefers env_key)
# 3. Run the CLI through the proxy:
codex exec --skip-git-repo-check -m cmd/deepseek/deepseek-v4-flash "responda apenas: OK"
# → works only because the operator manually edited config.toml to env_key,
# or because an older injector left env_key behind.Root cause
src/codex/inject.ts builds the provider TOML block:
if (includeApiAuthHeader) {
lines.push(
'env_http_headers = { "x-opencodex-api-key" = "OPENCODEX_API_AUTH_TOKEN" }',
);
}This string predates the codex-cli 0.146 env_key contract. The server-side admission (fixed in #1686) reads Authorization: Bearer and x-opencodex-api-key; the header form still works when the runtime forwards it, but the modern, documented, and already-server-supported form is env_key, and the two injectors are inconsistent.
Proposed diff
--- a/src/codex/inject.ts
+++ b/src/codex/inject.ts
@@ -228,7 +228,7 @@ export function buildOcxProviderBlock(
if (includeApiAuthHeader) {
lines.push(
- 'env_http_headers = { "x-opencodex-api-key" = "OPENCODEX_API_AUTH_TOKEN" }',
+ 'env_key = "OPENCODEX_API_AUTH_TOKEN"',
);
}
if (supportsWebsockets) lines.push("supports_websockets = true");Alternatives considered
- Keep
env_http_headersand rely onx-opencodex-api-keyadmission — works today, but keeps two incompatible auth transports for the same proxy, and the runtime may dropenv_http_headerssupport in a future release (the header name is not part of the documented 0.146+ provider contract). - Emit both lines — redundant; the proxy treats either as admission, and the extra header is noise.
- Make it configurable (
injectAuthForm = "env_key" | "env_http_headers") — unnecessary until a runtime actually rejects one of them; the modern contract isenv_key.
Test matrix
| Case | Expected |
|---|---|
Fresh ocx start / ocx sync on codex-cli 0.146+ |
config.toml contains env_key = "OPENCODEX_API_AUTH_TOKEN" |
codex exec -m <routed-model> after injection |
200, no 401 |
/v1/responses with Authorization: Bearer $OPENCODEX_API_AUTH_TOKEN |
200 (server side already accepts — #1686) |
Upgrade path: existing config with env_http_headers |
proxy still admits via x-opencodex-api-key (back-compat unchanged) |
| Claude Code / Grok injectors | unchanged (env_key already emitted there) |
Activity
coderabbitai commentedon Aug 18, 2026
🔗 Related PRs
#333 - fix(codex): preserve external model providers [merged]
#403 - feat(grok): auto-configure Grok Build and harden strict-client compatibility [merged]
#832 - fix(codex): preserve auto-compaction limit on inject [merged]
#1461 - fix(codex): preflight sync injection before catalog writes [merged]
#2061 - fix(codex): strip app-rewritten provider sub-tables so the provider never survives nameless [open]
📝 Issue Planner
Check the box below or use the
@coderabbitai plancommand to generate an implementation plan and prompts that you can use with your favorite coding assistant.🧪 Issue enrichment is currently in open beta.
To disable automatic issue enrichment, add the following to your
.coderabbit.yaml:💬 Have feedback or questions? Drop into our discord!
fix(codex): emit modern env_key admission line on non-loopback inject (…
lidge-jun commentedon Aug 19, 2026
Fixed on
devby #2076 (59964ad): the non-loopback injector now emitsenv_key = "OPENCODEX_API_AUTH_TOKEN"instead of the legacyenv_http_headerstable, matching the codex-cli 0.146+ contract (verified againstrust-v0.146.0source) and the #1686 server-side bearer admission + substitution already on dev. Loopback Design B still emits no auth line; existing legacy configs convert on the next inject (regression-pinned in tests/codex-inject-integration.test.ts). SoT and all 9 locale guides updated.fix(codex): emit modern env_key admission line on non-loopback inject (…