anthropics / anthropics/claude-code

[SOLVED] Claude in Chrome "not connected" on Windows: stale oauth:tokenCache causes a 401 loop — fix inside

Đang mở
#91,469 1 bình luận 0 reaction 0 người được giao Xem trên GitHub
area:auth area:chrome bug has repro platform:windows
Ngôn ngữ chính
Python
Star
145k
Fork
23.1k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

## TL;DR — this is SOLVED, here is the fix

If `list_connected_browsers` / `tabs_context_mcp` returns **"Claude in Chrome is not connected"** on Windows and you have already reinstalled the extension, re-signed in, restarted Chrome and rebooted — **stop, none of that is the problem.**

Two stale encrypted OAuth caches in Claude Desktop's `config.json` put the app in an endless `401` loop. Delete them and it works:

```powershell
# 1. Fully quit Claude Desktop first.

$cfg = "$env:LOCALAPPDATA\Packages\Claude_\LocalCache\Roaming\Claude\config.json"

# 2. Back up byte-for-byte
Copy-Item $cfg "$cfg.bak-$(Get-Date -Format yyyyMMddTHHmmss)"

# 3. Remove ONLY these two keys, keep everything else:
# oauth:tokenCache
# oauth:tokenCacheV2

# 4. Start Claude Desktop. It reissues fresh tokens by itself.
```

Verification after restart: `/api/oauth/profile` returns `200` instead of `401`, and `list_connected_browsers` returns your browser. Rollback is restoring the backup.

Total time: about a minute. We spent two hours before finding it, because the error message points at the wrong thing (see below).

---

## Why the error message sends everyone the wrong way

This is the most expensive part of the bug, and it is a one-line fix.

`list_connected_browsers` calls `ensureConnected()` first:

- success → returns JSON; an empty roster is `[]`
- failure → returns the generic `onToolCallDisconnected()` text

That generic text is:

> The Chrome extension isn't reachable right now. […] the extension is likely not installed or not signed in.
> 1. Install the Claude in Chrome extension […]
> 2. Open the Claude side panel in Chrome and sign in with the same account as this app.

**It is not a statement about the extension.** It is emitted when *Claude Code's own bridge client* fails to connect or authenticate. But it reads as a diagnosis of the user's setup, so every user does exactly what it says — reinstall, re-login, restart Chrome — and none of it can possibly help.

Reading the closed duplicates below, the same pattern repeats in nearly all of them: users verify the extension and login exhaustively, because the message told them to.

**Ask:** distinguish "client failed to connect/authenticate" from "connected, zero browsers", and do not blame the user's extension when the failure is local.

---

## Root cause of the connection failure

After a hard reboot plus a re-authentication, `config.json` retained two stale encrypted OAuth caches: `oauth:tokenCache` and `oauth:tokenCacheV2`.

- The app polled `/api/oauth/profile` every ~30s and received `401`.
- The current version clears the token cache automatically **only on `403`**, not on `401`.
- So it looped indefinitely on a cache it would never invalidate.
- Fresh, valid credentials in `~/.claude/.credentials.json` were present the whole time and simply unused.

**Ask:** invalidate the cached token on `401` as well (or on any auth failure), instead of `403` only.

---

## Second, independent defect: the integration is silently gated off in Desktop

Separate from the above, Claude Code launched **by Claude Desktop** never enables Claude in Chrome at all.

The gate (from the shipped bundle, order matters):

```js
function qBe(e){
if(!fKt()) return false; // 1. OAuth scope check
if(e===true) return true; // 2. --chrome
if(e===false) return false; // --no-chrome
if(CLAUDE_CODE_ENABLE_CFC===true) return true; // 3. env var
if(CLAUDE_CODE_ENABLE_CFC===false) return false;
if(De()) return false; // 4. ← returns true under Desktop
let o=ie();
if(o.claudeInChromeDefaultEnabled!==undefined) // 5. never reached
return o.claudeInChromeDefaultEnabled;
return false;
}
```

Observed:

- No `claude.exe` process spawned by Desktop carries `--chrome` (verified across all running processes).
- No `--claude-in-chrome-mcp` child process exists.
- The user setting `claudeInChromeDefaultEnabled` was already `true` and is never consulted, because `De()` short-circuits first.
- The browser tools are still advertised in the tool list and, when called, emit the misleading text above.

Workaround, since the env var is checked before `De()`:

```powershell
[Environment]::SetEnvironmentVariable('CLAUDE_CODE_ENABLE_CFC','true','User')
# then fully restart Claude Desktop
```

Confirmed by A/B: the same binary run headless **without** `--chrome` but **with** the env var returns the browser; without the env var the MCP server is not registered at all.

**Ask:** Desktop should honour `claudeInChromeDefaultEnabled`, or pass `--chrome`.

---

## Third, minor: Desktop ships a dangling native-messaging registration

`HKCU\Software\Google\Chrome\NativeMessagingHosts\com.anthropic.claude_browser_extension` points at

```
…\LocalCache\Roaming\Claude\ChromeNativeHost\com.anthropic.claude_browser_extension.json
```

which the installation never creates — the folder contains only `chrome-native-host.exe`. Authoring the JSON by hand does make Chrome launch the host, but it does **not** affect `list_connected_browsers`, because the normal transport is the hosted bridge, not native messaging.

Package is `SignatureKind: Developer`, so this may be specific to that distribution channel. Same finding independently reported in #58968.

---

## For anyone debugging this: how the connection actually works

Worth stating, because it invalidates most of the obvious guesses.

The primary transport is **not** native messaging. Extension and Claude Code each open an independently authenticated WebSocket to:

```
wss://bridge.claudeusercontent.com/chrome/
```

`list_connected_browsers` sends `list_extensions` over that socket. Native messaging (`\\.\pipe\claude-mcp-browser-bridge-`) is a separate, secondary transport.

**Verified NOT to be the cause** — we tested all of these:

| Suspected | Result |
|---|---|
| Extension not installed / not signed in | Installed, signed in, `from_webstore: true`, no `disable_reasons` |
| Chrome side panel not open | Open, no effect |
| Missing native-host manifest | Created it → host launched → still "not connected" |
| Chrome enterprise policies | None present in HKLM / HKCU / WOW6432Node |
| Chrome restart / machine reboot | No effect |
| Claude Code version skew (2.1.255 vs 2.1.257) | Fresh 2.1.255 works fine |
| Stale in-memory token in a long-lived process | A process started 42 min after re-auth failed identically — the staleness was on disk |
| `ant-device-registry.json` frozen weeks earlier | Browser tools worked for a week after that date |
| Filesystem corruption (boot chkdsk) | `0 bad file records`, nothing repaired |

Discriminator that finally isolated it: within the same minute, on the same machine, same extension, same account, same binary version — a **headless** `claude.exe --chrome -p …` returned the browser while the **Desktop-hosted** session returned "not connected".

---

## Environment

- Windows 11 Pro 10.0.26200
- Chrome 152.0.7977.65, extension `fcoeoabgfenejglbffodgkkbkcdhcgfn` v1.0.90
- Claude Desktop 1.40609.1.0 (MSIX, `SignatureKind: Developer`)
- Claude Code bundled in Desktop 2.1.255; standalone CLI 2.1.257

## Summary of asks

1. Clear the OAuth token cache on `401`, not only on `403`.
2. Make the browser-tool error distinguish a local connect/auth failure from an empty roster, and stop attributing it to the user's extension.
3. Have Desktop honour `claudeInChromeDefaultEnabled` (or pass `--chrome`).
4. Ship the missing `com.anthropic.claude_browser_extension.json`.

## Related issues

All describe the same symptom; all closed without a working resolution:
#58009, #58968, #72606, #76347, #79228, #29528, #71058

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Hướng nghiên cứu

Start by tracing the Desktop-hosted browser integration from the qBe gate and ensureConnected(), then inspect the OAuth polling around /api/oauth/profile and the config.json token-cache keys. Reproduce the Desktop-versus-headless difference and the 401 loop described in the issue. Done means the four listed asks are addressed and browser-tool errors distinguish authentication failure from an empty roster.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
powershell, python
Lĩnh vực
api, authentication, backend-api-design, desktop
Loại issue
Lỗi
Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức độ hoạt động
Sôi nổi
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
35/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.