[BUG] OAuth token refresh uses HTTP GET instead of CONNECT tunnel — breaks forward proxy environments
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Claude Code's OAuth client sends token refresh/profile requests as plain HTTP GET through the proxy instead of using a CONNECT tunnel. This causes forward proxies (e.g., Squid) to return 503 Service Unavailable.
The inference API (api.anthropic.com:443) correctly uses CONNECT tunnels and works fine through the same proxy. Only the OAuth endpoints use the wrong transport method.
Once the initial OAuth token expires mid-session, all subsequent API calls fail silently. Claude Code continues running (consuming time/resources) but produces no useful output — in our case, a session completed with 0 tool calls after 224 consecutive failed OAuth refresh attempts.
What Should Happen?
OAuth token refresh requests to api.anthropic.com should use CONNECT tunnels (the same way the inference API does), allowing the proxy to establish an encrypted tunnel to the destination.
# Expected (how inference API already works correctly):
TCP_TUNNEL/200 CONNECT api.anthropic.com:443
Error Messages/Logs
# Squid access.log — OAuth refresh failures (repeated 224 times in one session):
1741... TCP_MISS_ABORTED/503 0 GET https://api.anthropic.com/api/oauth/profile
1741... TCP_MISS_ABORTED/503 0 GET https://api.anthropic.com/api/oauth/profile
1741... TCP_MISS_ABORTED/503 0 GET https://api.anthropic.com/api/oauth/profile
... (224 total failures)
# For comparison — inference API in the SAME session works fine via CONNECT:
1741... TCP_TUNNEL/200 ... CONNECT api.anthropic.com:443
Steps to Reproduce
- Run Claude Code inside a Docker container with all traffic routed through a forward proxy (Squid) via
HTTP_PROXYandHTTPS_PROXYenvironment variables - Configure the proxy to allow
*.anthropic.comand*.claude.aidomains - Authenticate via OAuth — this works initially (the OAuth flow itself uses CONNECT correctly)
- Start a long-running autonomous session (e.g.,
claude --dangerously-skip-permissions) - Wait for the OAuth token to expire mid-session
- Observe: Claude Code attempts to refresh the token via
GET https://api.anthropic.com/api/oauth/profileinstead ofCONNECT api.anthropic.com:443— the proxy returns 503 on every attempt - The session silently dies — Claude Code continues running but cannot make any API calls
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.74 (also reproduced on 2.0.75)
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Other
Additional Information
Workaround
Adding api.anthropic.com to NO_PROXY bypasses the proxy for OAuth calls:
environment:
NO_PROXY: localhost,127.0.0.1,api.anthropic.com
This works but is undesirable in security-sensitive environments where all traffic must be auditable through the proxy.
Root Cause Hypothesis
The OAuth HTTP client (likely a different library or config path than the inference client) is not configured to use CONNECT tunnels for HTTPS URLs when an HTTP proxy is set. The inference client correctly uses CONNECT, suggesting a configuration inconsistency between the two HTTP clients within Claude Code.
Impact
- Session death: Once the token expires, the agent cannot recover
- Silent failure: Session appears to run but produces 0 tool calls / 0 output
- Affects all forward proxy environments: Corporate proxies, Docker-based security wrappers, audit-trail proxies
Related Issues
- #217 — Add HTTP Proxy support (closed/implemented — but OAuth client was apparently not covered)
- #29367 — API unreachable from VM behind corporate NTLM proxy (different proxy type, possibly related root cause)
Environment Details
- Proxy: Squid 6.x with domain whitelist (
acl anthropic_api dstdomain .anthropic.com .claude.ai) - Docker setup: airlocked-agent — firewalled environment for running AI coding agents autonomously
- Auth: OAuth (Pro subscription), tokens stored in named Docker volume
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗