Summary
ClaudeCodeProvider.prepareHeaders() (packages/providers/src/providers/claude-code/provider.ts) sets Authorization: Bearer <access_token> for OAuth accounts but never sets the anthropic-beta: oauth-2025-04-20 header that Anthropic requires to recognize a Bearer token as a valid OAuth credential.
The compat translate route (/v1/ccflare/*, packages/proxy/src/compat/handler.ts) already sends this header as part of its ANTHROPIC_BETA constant. The direct native provider route (/v1/claude-code/*), which is documented in the README as the way to point Anthropic SDKs/curl at ccflare, does not.
Observed behavior
With a valid, unexpired OAuth token on a Pro-tier account:
model: claude-haiku-4-5 via /v1/claude-code/v1/messages → 200 OK
model: claude-sonnet-5 (or claude-sonnet-4-5) via the same route → 401 {"type":"authentication_error","message":"x-api-key header is required"}
Calling https://api.anthropic.com/v1/messages directly with the same OAuth access token (Authorization: Bearer ... + anthropic-beta: oauth-2025-04-20), bypassing ccflare entirely, correctly authenticates for both models — claude-sonnet-5 returns a normal 429 rate_limit_error instead of a 401, confirming the token itself is valid and entitled; ccflare's header omission is what causes the false 401.
Confusing secondary symptom
Because the account only has one OAuth account configured, a real upstream rate limit (429) on the account also surfaces as this same misleading 401: the first internal attempt is correctly authenticated, hits a genuine 429, gets marked rate-limited, and (with no other account to fail over to) returns a 502; the Anthropic SDK's automatic retry then hits ccflare again microseconds later, finds 0 available accounts, and falls through to the unauthenticated-request fallback path — producing the same 401 x-api-key header is required message for a completely different underlying cause. Worth keeping in mind when triaging reports of this error.
Fix
PR incoming: adds anthropic-beta: oauth-2025-04-20 in ClaudeCodeProvider.prepareHeaders(), merged with any anthropic-beta value already present on the request rather than overwriting it.
Summary
ClaudeCodeProvider.prepareHeaders()(packages/providers/src/providers/claude-code/provider.ts) setsAuthorization: Bearer <access_token>for OAuth accounts but never sets theanthropic-beta: oauth-2025-04-20header that Anthropic requires to recognize a Bearer token as a valid OAuth credential.The compat translate route (
/v1/ccflare/*,packages/proxy/src/compat/handler.ts) already sends this header as part of itsANTHROPIC_BETAconstant. The direct native provider route (/v1/claude-code/*), which is documented in the README as the way to point Anthropic SDKs/curl at ccflare, does not.Observed behavior
With a valid, unexpired OAuth token on a Pro-tier account:
model: claude-haiku-4-5via/v1/claude-code/v1/messages→ 200 OKmodel: claude-sonnet-5(orclaude-sonnet-4-5) via the same route →401 {"type":"authentication_error","message":"x-api-key header is required"}Calling
https://api.anthropic.com/v1/messagesdirectly with the same OAuth access token (Authorization: Bearer ...+anthropic-beta: oauth-2025-04-20), bypassing ccflare entirely, correctly authenticates for both models —claude-sonnet-5returns a normal429 rate_limit_errorinstead of a 401, confirming the token itself is valid and entitled; ccflare's header omission is what causes the false 401.Confusing secondary symptom
Because the account only has one OAuth account configured, a real upstream rate limit (429) on the account also surfaces as this same misleading 401: the first internal attempt is correctly authenticated, hits a genuine 429, gets marked rate-limited, and (with no other account to fail over to) returns a 502; the Anthropic SDK's automatic retry then hits ccflare again microseconds later, finds 0 available accounts, and falls through to the unauthenticated-request fallback path — producing the same
401 x-api-key header is requiredmessage for a completely different underlying cause. Worth keeping in mind when triaging reports of this error.Fix
PR incoming: adds
anthropic-beta: oauth-2025-04-20inClaudeCodeProvider.prepareHeaders(), merged with anyanthropic-betavalue already present on the request rather than overwriting it.