claude-in-chrome: Bridge rejects valid OAuth token with 'Invalid OAuth token' (close 1008)
Summary
claude-in-chrome fails to connect because the bridge server (wss://bridge.claudeusercontent.com) rejects the OAuth token issued by claude --chrome with {"type":"error","error":"Invalid OAuth token"} and closes the WebSocket with code 1008. Re-running /login does not fix it — a fresh token from keychain is rejected the same way. All local prerequisites (extension installed/enabled, manifests in place, native messaging host running, both ends connected to the bridge) are verified working.
Environment
- Claude Code: 2.1.121 (Claude Code)
- Chrome extension: 1.0.69 (ID
fcoeoabgfenejglbffodgkkbkcdhcgfn) - Browser: Google Chrome 147.0.7727.116 (arm64)
- OS: macOS 26.4.1 (Apple Silicon)
- Subscription: claude_max (
default_claude_max_20x, organizationTypeclaude_max, roleadmin) - Account: vladimir.pirotskiy@gmail.com
- accountUuid:
bfc431e6-4fb1-4b8d-8d43-034a2aac310b
Reproduction
claude --chrome --debug-to-stderr -p "use mcp__claude-in-chrome__tabs_context_mcp"- Tool returns
Browser extension is not connected.
Repeated immediately after a successful /login — same result.
Debug log (CLI side)
[INFO] Bridge URL: wss://bridge.claudeusercontent.com
[DEBUG] MCP server "claude-in-chrome": In-process Chrome MCP server started
[INFO] [Claude in Chrome] ensureConnected called, connected=false, authenticated=false
[DEBUG] [Claude in Chrome] Fetching user ID for bridge connection
[DEBUG] [Claude in Chrome] Fetching OAuth token for bridge connection
[INFO] [Claude in Chrome] Connecting to bridge:
wss://bridge.claudeusercontent.com/chrome/bfc431e6-4fb1-4b8d-8d43-034a2aac310b
[INFO] [Claude in Chrome] WebSocket connected, sending connect message
[DEBUG] [Claude in Chrome] Bridge received: {"type":"error","error":"Invalid OAuth token"}
[WARN] [Claude in Chrome] Bridge error: Invalid OAuth token
[INFO] [Claude in Chrome] Bridge connection closed (code: 1008, duration: 0ms)
[INFO] [Claude in Chrome] Bridge reconnecting in 2000ms (attempt 1)
The reconnect loop continues with the same error indefinitely.
Token state (after fresh /login, "Login successful")
Stored in Claude Code-credentials keychain entry, modified seconds before the failure:
scopes: ['user:file_upload', 'user:inference', 'user:mcp_servers',
'user:profile', 'user:sessions:claude_code']
expiresAt: 1777405575255 (well in the future)
subscriptionType: max
rateLimitTier: default_claude_max_20x
Token is fresh, has the expected user:mcp_servers and user:sessions:claude_code scopes, and is not expired — yet the bridge rejects it. The same OAuth context successfully authenticates regular CLI traffic (chat, MCP) to 160.79.104.10 (bridge IP) — only the WebSocket handshake on /chrome/<accountUuid> fails.
What is verified working (rules out common causes)
- Extension is installed/enabled in
chrome://extensions/, version 1.0.69 ≥ 1.0.36 (docs requirement). - Logged into claude.ai with the same email in the same Chrome profile; account UUID confirmed identical to the CLI.
- Native messaging host launches:
~/.claude/chrome/chrome-native-hostshim execs2.1.121 --chrome-native-hostand creates/tmp/claude-mcp-browser-bridge-vova/<pid>.sock. - Both manifests present and well-formed at
~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.anthropic.claude_code_browser_extension.json(path matches actual shim). - Coexistence with Claude Desktop: when
com.anthropic.claude_browser_extension.json(Claude Desktop's manifest) is also present, the extension preferentially launchesClaude.app/Contents/Helpers/chrome-native-hostand Claude Code's host is never invoked. Renaming the Desktop manifest to.bakwas required to make Claude Code's host start at all. (Worth fixing independently — Claude Desktop on the same machine silently breaks Claude Code's Chrome integration.) - After Desktop manifest is disabled and extension state is cleared (
Local Extension Settings/,Sync Extension Settings/,Extension State/), both CLI and Chrome establish ESTABLISHED TCP sessions to160.79.104.10:443— but the WebSocket handshake on the CLI side is rejected at the application layer with the error above. /login(which reports "Login successful" and refreshes the keychain entry'smdat) does not clear the bridge rejection; the next bridge connect attempt within seconds still getsInvalid OAuth token.- Network has no proxies/VPNs; direct HTTPS to bridge returns expected
426 Upgrade Requiredfrom Cloudflare edge.
Hypotheses
- The bridge requires a scope or claim (e.g.
user:chrome_bridge,user:claude_code_chrome) that is not in the scope set issued by/loginforclaude_maxsubscriptions. - Bridge auth is keyed on something different than
claudeAiOauth.accessToken(a session-scoped or ephemeral token), and the CLI is sending the wrong one. - Token is rejected because of a server-side org-routing mismatch (multi-org user) — though this user has only one org.
Workaround
None known on the user side. chrome-devtools-mcp (separate plugin) works; native claude-in-chrome does not.
Asks for the team
- Confirm which OAuth scope/audience the bridge expects from
claude_maxsubscriptions in 2.1.121. - If the issued token is missing a scope, server should respond with
Insufficient scoperather thanInvalid OAuth tokenso users can act on it. - Consider auto-detecting the Claude Desktop manifest collision and either skipping it or warning the user — currently it silently breaks the integration on machines that also have Claude Desktop installed.
I'm happy to provide more logs, packet captures of the WS handshake, or the (redacted) JWT header/payload of the rejected token if useful.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗