Skip to content

[Bug]: codex injector still emits legacy env_http_headers; runtime 0.146+ contract is env_key #2073

Description

@rrmlima

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

  1. Keep env_http_headers and rely on x-opencodex-api-key admission — works today, but keeps two incompatible auth transports for the same proxy, and the runtime may drop env_http_headers support in a future release (the header name is not part of the documented 0.146+ provider contract).
  2. Emit both lines — redundant; the proxy treats either as admission, and the extra header is noise.
  3. Make it configurable (injectAuthForm = "env_key" | "env_http_headers") — unnecessary until a runtime actually rejects one of them; the modern contract is env_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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions