Repository navigation
[Bug]: No management-plane support for provider headers — custom providers needing client fingerprints (Agent Router) 401 after headers are lost #959
Description
Activity
Automated translation bookkeeping — detected language: unknown.
- addedbugSomething isn't workingSomething isn't workingproxyHTTP proxy, routing, reverse-proxy / management authHTTP proxy, routing, reverse-proxy / management auth
on Aug 3, 2026 Maintainer triage: the core management-plane gap is confirmed. The config schema and adapters support validated custom
headers, but currentPATCH /api/providersandocx provider editexpose no way to set, merge, or clear them.Draft PR #961 is the active implementation, so I will not duplicate the contributor work. Its current merge/clear semantics and sensitive-header validation are directionally correct, but the draft is not review-ready yet: a casing-only update can preserve conflicting keys such as
X-Fooandx-foo, and concurrent PATCH requests can still persist stale provider snapshots and erase each other. The documentation also needs to state the validation and clear behavior consistently.One scope clarification:
ocx provider edit ... --enabledalready uses PATCH and preserves existing headers.POST /api/providersis an overwrite operation, so omission replaces the submitted provider shape; the independently confirmed bug is that the supported management surfaces cannot safely edit or restore the header block.Leaving this open and linked to #961 until those blockers are addressed and the focused management/CLI tests are green.
- linked a pull request that will close this issuefeat: manage provider custom headers via PATCH and ocx provider edit --headers #961
on Aug 4, 2026 - added a commit that references this issue
on Aug 5, 2026 - added a commit that references this issue
on Aug 5, 2026 Fixed on
devin #1033 (merged as51c4be686).Custom provider headers can now be managed through
PATCH /api/providers/:nameandocx provider edit --headers <json>, with merge semantics and{}/-to clear. Header names are matched case-insensitively and static headers are restored correctly.Two things are deliberately constrained. The validator rejects standard credential header names (
Authorization,X-Api-Key,Cookie, …) and points atapiKey/authModeinstead, andGET /api/providersexposes onlyhasHeaders— presence, never names or values — matching the existing presence-only DTO on/api/config.Worth reading before you use it:
--headersis documented in all five locales as non-secret request metadata. The validator cannot recognize an arbitrary name likeX-My-Token, and the JSON is a command-line argument, so a secret placed there lands in shell history and the process list, and persists inconfig.jsonin cleartext unlike API keys.Thanks to @Yuxin-Qiao — #961 is the implementation that shipped, carried with authorship intact.
Not in a release yet. This is on
dev, andmainis atv2.10.0. It ships in the next release.
Client or integration
Direct HTTP/API client (Codex App / Claude Code also affected via the proxy)
Area
Proxy and routing · Provider adapter
Summary
The provider management API and CLI have no way to set or restore the
headersfield on a provider.PATCH /api/providersaccepts only a fixed allowlist of fields (disabled,adapter,baseUrl,defaultModel,authMode,apiKeyTransport,note,allowPrivateNetwork,liveModels,codexAccountMode,setDefault) andocx provider editexposes the same set as flags — there is noheadersoption. If a custom provider'sheadersblock is lost (e.g. the provider entry is re-saved viaPOST /api/providerswithout round-tripping it, or a config migration drops it), the only recovery is hand-editing~/.opencodex/config.jsonand restarting the proxy.Concrete failure: the Agent Router gateway (agentrouter.org) rejects requests that carry a valid API key but not the Claude Code CLI client fingerprint (User-Agent,
x-app,X-Stainless-*,anthropic-version,anthropic-beta). Theopenai-chatadapter sendsAuthorization: Bearer <key>and then mergesprovider.headers; without the fingerprint headers the gateway returns401 unauthorized client detected. In this install theheadersblock on theAGR-OAIprovider (present in a 2026-07-29 config backup) was missing from the 2026-08-02 config, and every routed request failed with that 401 until the block was restored by hand.Expected:
PATCH /api/providersandocx provider editshould acceptheaders(merge or replace), and any provider save path should round-trip unknown provider fields so custom headers survive.Reproduction
@bitkyc08/opencodex2.10.0 and start the proxy (ocx start).~/.opencodex/config.json:{ "providers": { "AGR-OAI": { "adapter": "openai-chat", "baseUrl": "https://agentrouter.org/v1", "authMode": "key", "apiKey": "sk-<redacted>", "headers": { "User-Agent": "claude-cli/2.1.219 (external, sdk-cli)", "anthropic-version": "2023-06-01", "anthropic-beta": "claude-code-20250219,interleaved-thinking-2025-05-14,effort-2025-11-24", "x-app": "cli", "X-Stainless-Retry-Count": "0", "X-Stainless-Package-Version": "0.94.0" } } } }POST /api/providerswith a provider payload that omitsheaders(the field is optional and not validated as required), then send a request with an image-free message:~/.opencodex/config.json(restoringheaders) plus a restart fixes it; the management plane cannot.Version
2.10.0 (npm
@bitkyc08/opencodex); Codex runtime 0.146.0Operating system
Windows 11 (current), America/Fortaleza timezone
Provider and model
agentrouter.org via custom provider
AGR-OAI(openai-chat adapter), modelgpt-5.6-sol; same issue applies to any provider needing custom headers (e.g.AGRanthropic adapter uses the same header block)Logs or error output
Verified live:
GET https://agentrouter.org/v1/modelswithAuthorization: Bearer <key>and no fingerprint headers → 401; with the claude-cli headers added → 200 and the model list is returned.Redacted configuration
{ "providers": { "AGR-OAI": { "adapter": "openai-chat", "baseUrl": "https://agentrouter.org/v1", "authMode": "key", "apiKey": "sk-<redacted>", "headers": { "User-Agent": "claude-cli/2.1.219 (external, sdk-cli)", "anthropic-version": "2023-06-01", "anthropic-beta": "claude-code-20250219,interleaved-thinking-2025-05-14,effort-2025-11-24", "anthropic-dangerous-direct-browser-access": "true", "x-app": "cli", "X-Stainless-Retry-Count": "0", "X-Stainless-Timeout": "600", "X-Stainless-Lang": "js", "X-Stainless-Package-Version": "0.94.0", "X-Stainless-OS": "MacOS", "X-Stainless-Arch": "arm64", "X-Stainless-Runtime": "node", "X-Stainless-Runtime-Version": "v26.3.0" } } } }Code references
PATCH /api/providersfield allowlist:src/server/management/provider-routes.ts— onlydisabled,adapter,baseUrl,defaultModel,authMode,apiKeyTransport,note,allowPrivateNetwork,liveModels(plus the exclusivecodexAccountMode/setDefaultpaths); unknown fields →400 "no recognized fields to update".src/cli/provider-runtime.ts(ocx provider edit ...has no--headers).provider.headersafter the defaultAuthorizationheader:src/adapters/openai-chat.tsandsrc/adapters/anthropic.ts.providerHeadersConfigErrorinsrc/config.tsalready validates theheadersshape, so the schema supports it — only the management-plane mutation paths are missing it.Suggested fix
headers(object) inPATCH /api/providers, merging or replacing per field semantics, validated byproviderHeadersConfigError.--headers <json>option toocx provider edit(or a dedicated management route).POST /api/providerssave paths (GUI/CLI) round-trip unknown provider fields likeheadersso a provider re-save does not silently drop them.Checks