Skip to content

fix: OAuth credential proxy — auto-refresh tokens + beta header#1076

Open
glifocat wants to merge 1 commit intoqwibitai:mainfrom
glifocat:fix-oauth-proxy
Open

fix: OAuth credential proxy — auto-refresh tokens + beta header#1076
glifocat wants to merge 1 commit intoqwibitai:mainfrom
glifocat:fix-oauth-proxy

Conversation

@glifocat
Copy link
Collaborator

Type of Change

  • Skill - adds a new skill in .claude/skills/
  • Fix - bug fix or security fix to source code
  • Simplification - reduces or simplifies source code

Description

OAuth users are hitting 401 "OAuth authentication is currently not supported" because the credential proxy doesn't send the required anthropic-beta: oauth-2025-04-20 header. Additionally, OAuth tokens stored in .env expire after ~4 hours with no automatic refresh, causing silent auth failures.

This PR fixes both issues:

1. Beta header injection (credential-proxy.ts):

  • Injects anthropic-beta: oauth-2025-04-20 on all OAuth-proxied requests
  • Unconditional credential injection — the proxy always replaces auth headers, regardless of what the container sends. This prevents the SDK's OAuth exchange flow from delivering a working temp API key into the untrusted container.
  • req.pipe() streaming for large request bodies (base64 images)
  • /health endpoint, JSON error responses (502/503), 10-min timeout

2. Token auto-refresh (new oauth-token.ts):

  • Reads ~/.claude/.credentials.json (same file the claude CLI maintains)
  • In-memory cache with 5-minute expiry buffer
  • Auto-refreshes expired tokens via platform.claude.com/v1/oauth/token
  • Promise-chain serialization (only one refresh runs at a time)
  • Atomic file writes (write temp + rename) to prevent credential corruption
  • Falls back to .env token if credentials file is unavailable

Based on work by @calebfaruki (#871) and @kianwoon (#930, #969). Supersedes both PRs with a combined, tested implementation.

Related issues: #730 (OAuth tokens expire)

OAuth users hitting 401 "OAuth authentication is currently not supported"
because the proxy was missing the required `anthropic-beta: oauth-2025-04-20`
header. Additionally, tokens in .env expire after ~4 hours with no refresh.

Changes:
- Add src/oauth-token.ts: reads ~/.claude/.credentials.json, caches tokens
  in memory, auto-refreshes via platform.claude.com when expired, serializes
  concurrent refreshes through a promise chain, writes back atomically
- Rewrite credential proxy: async handler, unconditional credential injection
  (no exchange-based flow), beta header for OAuth, req.pipe() streaming,
  /health endpoint, JSON error responses, 10-min timeout
- Update tests for new behavior (mock getFreshOAuthToken, process.env for
  upstream URL, unconditional OAuth injection assertions)

Based on work by @calebfaruki (qwibitai#871) and @kianwoon (qwibitai#930/qwibitai#969).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Andy-NanoClaw-AI Andy-NanoClaw-AI added Status: Needs Review Ready for maintainer review PR: Fix Bug fix labels Mar 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR: Fix Bug fix Status: Needs Review Ready for maintainer review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants