anthropics / anthropics/claude-code

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

オープン
#91,469 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る
area:auth area:chrome bug has repro platform:windows
主要言語
Python
スター
145k
フォーク
23.1k
PR マージ指標
PR 指標を取得中

説明

## 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

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

調査の方向性

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.

索引モデルが issue の本文から書いたものです。

評価

技術スタック
powershell, python
領域
api, authentication, backend-api-design, desktop
issue の種類
バグ
難易度
5/5
見積もり時間
1週間以上
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
35/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。