[BUG] Claude in Chrome v1.0.70: Infinite OAuth retry loop on persistent 403 causes side panel flicker and forced logout
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?
Title
[BUG] Claude in Chrome v1.0.70: Infinite OAuth retry loop on
persistent 403 causes side panel flicker and forced logout
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
(related but distinct from #29628, #34176 which involve scope errors
in different flows)
- [x] This is a single bug report
- [x] I am using the latest version of Claude in Chrome (v1.0.70)
Summary
The Claude in Chrome side panel flickers periodically (~every 10–20s)
and eventually forces a redirect to login, wiping all conversation
context. Network analysis (HAR) reveals an infinite retry loop: the
extension obtains a fresh OAuth token, attempts to upgrade a WebSocket
to bridge.claudeusercontent.com, receives a non-transient 403 error,
and immediately retries — repeatedly, indefinitely.
The server explicitly marks the error as transient: false, yet the
extension treats it as recoverable and re-attempts on every cycle.
Severity
🔴 High — Active sessions interrupted unpredictably; conversation
history permanently lost; reproduces consistently for affected accounts;
extension is unusable in this state.
Evidence (from HAR capture, 5-minute window)
In a 5-minute capture (17:43:24 → 17:48:25), 116 network requests
were recorded with the following pattern repeating ~25 times:
\\\\
loop:
POST https://platform.claude.com/v1/oauth/token → 200 OK
WS wss://bridge.claudeusercontent.com/chrome/<bridge_id>
send: { "type": "connect",
"client_type": "chrome-extension",
"extension_version": "1.0.70",
"os_platform": "Windows",
"device_id": "<uuid>",
"oauth_token": "sk-ant-oat01-..." }
receive: { "type": "error",
"error": "OAuth token forbidden (403) —
missing scope or org access",
"reason": "upstream_403",
"upstream_status": 403,
"transient": false }
WS close
GET /api/oauth/profile → 200 OK
(immediately retry)
\\
Key observations:
- All 25 WebSocket attempts received the identical 403 error
- Server explicitly sets
"transient": false— indicating retry
will not help
- A new OAuth token is minted every cycle — token rotates each
retry, but every fresh token receives the same 403
- All HTTP requests return 200 — there are no failed REST calls;
the failure is exclusively at the WebSocket layer
- The OAuth profile endpoint reports the user is authenticated
successfully, yet the bridge rejects the same identity
Suspected Root Cause
Two overlapping issues:
- Server-side authorization bug: The OAuth token issued to the
user is missing the scope or org access required by
bridge.claudeusercontent.com. This happens immediately after
login — never works for this account. Possibly related to scope
issues in #29628 and #34176.
- Client-side retry-loop bug: The extension does not honor the
server's transient: false flag and retries indefinitely. There
appears to be no exponential backoff or retry cap. This turns a
single auth misconfiguration into a continuous flicker/logout
loop that destroys user state.
The client behavior is independently a bug — even when the underlying
auth issue is fixed, the extension should not retry non-transient
errors aggressively, and should not destroy user-visible state on
each retry.
Steps to Reproduce
- Install Claude in Chrome v1.0.70 (ID:
fcoeoabgfenejglbffodgkkbkcdhcgfn) - Log in with affected account [details available privately if needed]
- Open the side panel, start a conversation
- Within ~10–20 seconds: side panel flickers
- After several flicker cycles: forced redirect to login
- Conversation context is lost
- Re-login produces the same loop
Expected Behavior
- WebSocket bridge accepts the OAuth token issued to a logged-in user
(server-side fix), OR clearly surfaces the actionable error to the
user (e.g., "Your account does not have access to Claude in Chrome —
contact your admin")
- On
transient: falseerrors, the client stops retrying and shows an
actionable error UI instead of looping
- Conversation state is preserved across transient WebSocket reconnects
Actual Behavior
- WebSocket bridge returns persistent 403 immediately on every connect
- Client retries indefinitely, treating non-transient error as transient
- Each retry cycle re-renders the side panel (visible flicker)
- After enough failures, user is logged out and conversation is wiped
Environment
- Extension version: 1.0.70
- Extension ID:
fcoeoabgfenejglbffodgkkbkcdhcgfn - OS: Windows (per WebSocket payload
os_platform: "Windows") - Chrome version: [TODO —
chrome://version] - Account type: [TODO — Pro / Team / Enterprise / Free]
- Org membership: [TODO — relevant if "missing org access" applies]
Tangentially related observations (likely not root cause)
While investigating, the following were also noted but appear unrelated
to the flicker/logout loop:
- CSP violations on
options.html#options:8for inline scripts
and a third-party Segment/Amplitude CDN load
(cdn.segment.com/.../amplitude-plugins/...). These are Manifest V3
compliance issues but the side panel and service worker continue
functioning despite them.
- Service worker is healthy during the loop:
Installation: ACTIVATED, Running: RUNNING, Version ID: 76
(per chrome://serviceworker-internals). The service worker
console log is empty.
- Build artifact name
service-worker.ts-gaAAsstG.jsretains
the .ts extension before the content hash — minor, but unusual
for a production build.
Suggested Triage
- Investigate why bridge service rejects OAuth tokens for this account
with missing scope or org access — coordinate with auth team
- Add client-side handling for
transient: falseerrors: stop
retrying, show actionable error UI
- Add exponential backoff and retry cap to WebSocket reconnect logic
regardless of error type
- Decouple side panel UI state from WebSocket connection lifecycle so
transient reconnects do not visibly re-render or clear conversations
Attachments (please request privately — contain credentials)
- HAR file with full WebSocket payloads (contains rotating OAuth tokens —
do not share publicly)
- Service worker internals snapshot
- Screenshots of CSP errors
What Should Happen?
The Claude in Chrome side panel should maintain a stable session
during normal use. Specifically:
- The WebSocket bridge at bridge.claudeusercontent.com should accept
the OAuth token issued to a successfully logged-in user. If the
token genuinely lacks required scope or org access, the user should
see a clear, actionable error message (e.g., "Your account does
not have access to Claude in Chrome — please contact your admin")
instead of being silently logged out.
- When the server returns an error with "transient": false, the
client should stop retrying and surface the error to the user,
not loop indefinitely.
- Conversation context in the side panel should persist across
transient WebSocket reconnects. The UI should not be destroyed
on every reconnect attempt.
- Users should not be forcibly redirected to the login screen
without explicit action (logout button, expired session after
long idle, etc.).
Error Messages/Logs
Steps to Reproduce
- Install Claude in Chrome v1.0.70 from the Chrome Web Store
(Extension ID: fcoeoabgfenejglbffodgkkbkcdhcgfn)
- Log in with an Anthropic account
- Open the side panel and start a conversation
- Open DevTools on the side panel → Network tab → enable "Preserve log"
- Wait 10-20 seconds during normal use
Observed loop (repeats every ~10-20 seconds):
a. POST https://platform.claude.com/v1/oauth/token → 200 OK
(fresh token issued)
b. WebSocket connect to wss://bridge.claudeusercontent.com/chrome/<id>
Sends: { "type": "connect", "extension_version": "1.0.70",
"oauth_token": "sk-ant-oat01-..." }
Receives: { "type": "error",
"error": "OAuth token forbidden (403) —
missing scope or org access",
"reason": "upstream_403",
"upstream_status": 403,
"transient": false }
c. WebSocket closes
d. GET /api/oauth/profile → 200 OK
e. Side panel flickers (visible re-render)
f. Loop restarts
After enough cycles: side panel forcibly redirects to login screen,
all conversation context is permanently lost. Re-login reproduces
the same loop.
In a 5-minute capture, this loop repeated 25 times with 116 total
network requests. Every WebSocket attempt received the identical
non-transient 403, but a NEW oauth token was minted each cycle
(token rotates every retry, all tokens get the same 403).
Additional context:
- Service worker remains healthy throughout (status: ACTIVATED +
RUNNING, console log empty per chrome://serviceworker-internals)
- All HTTP REST calls return 200; failure is exclusively at the
WebSocket layer
- HAR file with full payloads available on request
(contains rotating OAuth tokens, cannot be shared publicly)
Claude Model
None
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
N/A — this is a Claude in Chrome extension bug, not Claude Code CLI. Claude in Chrome extension version: 1.0.70 Extension ID: fcoeoabgfenejglbffodgkkbkcdhcgfn
Platform
Other
Operating System
Windows
Terminal/Shell
Other
Additional Information
_No response_
This issue has 13 comments on GitHub. Read the full discussion on GitHub ↗