Skip to content

[Bug]: No management-plane support for provider headers — custom providers needing client fingerprints (Agent Router) 401 after headers are lost #959

Description

@brunoflma

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 headers field on a provider. PATCH /api/providers accepts only a fixed allowlist of fields (disabled, adapter, baseUrl, defaultModel, authMode, apiKeyTransport, note, allowPrivateNetwork, liveModels, codexAccountMode, setDefault) and ocx provider edit exposes the same set as flags — there is no headers option. If a custom provider's headers block is lost (e.g. the provider entry is re-saved via POST /api/providers without round-tripping it, or a config migration drops it), the only recovery is hand-editing ~/.opencodex/config.json and 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). The openai-chat adapter sends Authorization: Bearer <key> and then merges provider.headers; without the fingerprint headers the gateway returns 401 unauthorized client detected. In this install the headers block on the AGR-OAI provider (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/providers and ocx provider edit should accept headers (merge or replace), and any provider save path should round-trip unknown provider fields so custom headers survive.

Reproduction

  1. Install @bitkyc08/opencodex 2.10.0 and start the proxy (ocx start).
  2. Add a custom provider that requires fingerprint headers, e.g. Agent Router, in ~/.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"
          }
        }
      }
    }
  3. Try to manage the headers through the management plane:
    ocx provider edit AGR-OAI --enabled on          # works, headers preserved
    ocx provider edit AGR-OAI --headers '{"x-app":"cli"}'   # no such flag; exits with usage error
    
    Or via API:
    PATCH /api/providers?name=AGR-OAI
    { "headers": { "x-app": "cli" } }
    → 400 {"error":"no recognized fields to update"}
    
  4. Simulate headers being lost: POST /api/providers with a provider payload that omits headers (the field is optional and not validated as required), then send a request with an image-free message:
    POST /v1/responses
    { "model": "AGR-OAI/gpt-5.6-sol", "input": [...] }
    → 401 {"error":{"message":"unauthorized client detected, contact support for assistance at https://discord.gg/aYq5B4RW3"},"message":"UNAUTHENTICATED","success":false,"type":"unauthorized_client_error"}
    
  5. Observe: only a hand edit of ~/.opencodex/config.json (restoring headers) plus a restart fixes it; the management plane cannot.

Version

2.10.0 (npm @bitkyc08/opencodex); Codex runtime 0.146.0

Operating system

Windows 11 (current), America/Fortaleza timezone

Provider and model

agentrouter.org via custom provider AGR-OAI (openai-chat adapter), model gpt-5.6-sol; same issue applies to any provider needing custom headers (e.g. AGR anthropic adapter uses the same header block)

Logs or error output

Provider error 401: {"error":{"message":"unauthorized client detected, contact support for assistance at https://discord.gg/aYq5B4RW3"},"message":"UNAUTHENTICATED","success":false,"type":"unauthorized_client_error"}

Verified live: GET https://agentrouter.org/v1/models with Authorization: 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/providers field allowlist: src/server/management/provider-routes.ts — only disabled, adapter, baseUrl, defaultModel, authMode, apiKeyTransport, note, allowPrivateNetwork, liveModels (plus the exclusive codexAccountMode / setDefault paths); unknown fields → 400 "no recognized fields to update".
  • CLI flags mirror that allowlist: src/cli/provider-runtime.ts (ocx provider edit ... has no --headers).
  • The adapter applies provider.headers after the default Authorization header: src/adapters/openai-chat.ts and src/adapters/anthropic.ts.
  • providerHeadersConfigError in src/config.ts already validates the headers shape, so the schema supports it — only the management-plane mutation paths are missing it.

Suggested fix

  1. Accept headers (object) in PATCH /api/providers, merging or replacing per field semantics, validated by providerHeadersConfigError.
  2. Add a --headers <json> option to ocx provider edit (or a dedicated management route).
  3. Ensure POST /api/providers save paths (GUI/CLI) round-trip unknown provider fields like headers so a provider re-save does not silently drop them.

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingproxyHTTP proxy, routing, reverse-proxy / management auth

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions