anthropics / anthropics/claude-code

Desktop SSH remote session fails with "401 OAuth access token is invalid" while the claude CLI on the same host, same user, same credentials file works

Offen
#92,613 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
area:auth area:desktop bug has repro platform:macos
Vorherrschende Sprache
Python
Sterne
145k
Forks
23.1k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

### Preflight Checklist

- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) 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?

Using the Claude desktop app's SSH connection feature to work inside a Docker Sandboxes (`sbx`) microVM:

- The **chat pane** fails immediately with `Failed to authenticate. API Error: 401 OAuth access token is invalid.`
- The **terminal panel in the same session, on the same connection and folder**, running `claude`, works perfectly — `Claude Code v2.1.263 · Opus 5 · Claude Max`, "Session is live and working".

Same host, same Linux user, same `~/.claude/.credentials.json`. The remote agent the desktop pushes is **ccd-cli 2.1.260**; the CLI that works is **2.1.263**.

Clicking "Sign in again" runs OAuth on the Mac and writes to the macOS Keychain, which the Linux guest never reads, so it has no effect. The loop is repeatable indefinitely.

### What we were trying to do, and why

We run each project in its own isolated Docker Sandboxes microVM. The motivation is security: a supply-chain compromise via `npm i && npm run dev` recently forced a full machine reformat. The goal is a safe host where every project's dependencies, build scripts and coding agents execute inside a disposable VM, while source code stays on the host.

On top of that we wanted **one OAuth sign-in shared from host to all VMs**, rather than a separate `/login` per VM — separate logins rotate the refresh token and invalidate the other VMs. So we mount a single host-side credential directory into every sandbox and symlink `~/.claude/.credentials.json` to it.

The CLI half of this works exactly as intended. The desktop chat half does not.

### What Should Happen?

The desktop chat session should authenticate using the same credentials the CLI on that same remote host just used successfully — or, if the remote agent is meant to receive a forwarded token from the Mac instead, that forwarding should happen (and should fail loudly with a diagnosable error if it cannot).

At minimum, the error shown should identify **which machine** needs the credential. "Sign in again" performs OAuth on the Mac and stores the result in the macOS Keychain, which can never fix authentication for a Linux guest reached over SSH.

### Error Messages/Logs

```shell
UI error (chat pane):

Authentication failed
Sign in again to continue.
Failed to authenticate. API Error: 401 OAuth access token is invalid.

Working CLI in the same container, run immediately before and after a failing chat request:

$ claude -p "reply with exactly: AUTH_OK"
AUTH_OK

Notably, ~/.claude/remote/run//remote-server.log contains NO 401, OAuth, or auth-related entries at all. The failure surfaces only in the UI, so there is nothing server-side to diagnose from.
```

### Steps to Reproduce

1. Create a Docker Sandboxes microVM with a project folder bind-mounted:

```
sbx create --name myproject codex ~/Projects/myproject
```

2. Inside the VM, install Claude Code and sign in:

```
sbx exec -it myproject bash
npm install -g @anthropic-ai/claude-code
claude # then /login, device-code flow
```

3. Confirm the CLI is authenticated inside the VM:

```
claude -p "reply with exactly: AUTH_OK"
# -> AUTH_OK
```

4. In the Claude desktop app, add the sandbox as an SSH connection (`myproject.sbx`), start a new session, select the project folder, and send any prompt.

**Result:** the chat pane returns `Failed to authenticate. API Error: 401 OAuth access token is invalid.` while step 3 continues to succeed, and the terminal panel in that same desktop session runs `claude` normally.

A plain Linux host reached over SSH should reproduce this too; the microVM is just how we hit it. The essential ingredients are a Max/OAuth account (no API key) and a remote host whose `~/.claude/.credentials.json` is valid.

### Claude Model

None

### Is this a regression?

No, this never worked

### Last Working Version

_No response_

### Claude Code Version

2.1.263 (Claude Code) in the guest; desktop remote agent is ccd-cli 2.1.260

### Platform

Other

### Operating System

macOS

### Terminal/Shell

Other

### Additional Information

### Related issues

This looks like the same family as two existing reports, both on the desktop SSH-remote path with OAuth accounts:

- **#56840** (open) — "Remote SSH session crashes immediately with exit code 1 on Max/OAuth accounts (ccd-cli 2.1.128)". That reporter notes `ccd-cli --help` documents a `--bare` mode where "OAuth and keychain are never read" and `ANTHROPIC_API_KEY` is required, and hypothesises the desktop spawns the remote binary in a mode that bypasses OAuth. **That hypothesis fits our evidence exactly**: we are Max/OAuth with no API key anywhere, and the remote agent reads the credentials file and rejects it while the CLI accepts it.
- **#70520** (closed as stale, not fixed) — same shape as ours (desktop SSH remote fails, CLI over SSH works, same account) but with `403 Request not allowed` instead of `401`. Three other users confirmed it there on macOS and Windows 11, Pro and Max.

If those are the same root cause, this is a long-standing break in the desktop remote path for subscription/OAuth accounts.

### Environment detail

| | |
|---|---|
| Host | macOS 26.6.2 (25G83), arm64 |
| Claude desktop app | 1.46388.4 |
| Docker Sandboxes (`sbx`) | v0.39.0 |
| Guest OS | Ubuntu 26.04 LTS (aarch64) |
| Node in guest | v22.22.1 |
| CLI in guest (works) | 2.1.263 |
| Desktop remote agent (fails) | ccd-cli 2.1.260 |
| Account | Claude Max 20x, single user, no API key |

### Diagnostics already performed

All of these were checked; none explains the failure.

1. **The credential is valid.** `claude -p` in the guest returns a correct answer repeatedly, immediately before and after a failing chat request. `~/.claude.json` shows the correct account with a fresh `profileFetchedAt`, which only updates after a successful authenticated API call.
2. **Not a mounted-filesystem problem** (cf. #22066). Our setup symlinks `~/.claude/.credentials.json` to a bind-mounted host file. We replaced it with a **plain local regular file**, mode 600, owned by the session user. CLI still worked; chat **still 401**.
3. **Not a stale daemon.** Restarted the container, confirmed zero `remote/srv` processes remained, reconnected so the desktop provisioned a fresh remote server. Still 401.
4. **Not a stale session.** Multiple brand-new sessions and a fully recreated sandbox reproduce it.
5. **No auth environment reaches the agent.** `/proc//environ` for the `ccd-cli` and `remote/srv` processes (variable names only) contains no `ANTHROPIC_*` or `CLAUDE_CODE_OAUTH_TOKEN` — only `GH_TOKEN`, `MCP_SENTINEL_TOKEN_NAME`, `SSH_AUTH_SOCK`, `SSH_AUTH_SOCK_GATEWAY`, `CLAUDE_SSH_DAEMON_CHILD`.
6. **The agent does read the file.** `~/.claude/.credentials.json` shows up in `find ~/.claude -newermt "-15 minutes"` after a failing request — so it reads the right path and rejects the contents.
7. **Nothing is logged.** `~/.claude/remote/run//remote-server.log` has no 401/OAuth/auth entries at all.
8. **Not the sandbox HTTP proxy.** Docker Sandboxes routes guest traffic through an MITM proxy with its own CA (`HTTPS_PROXY`, `NODE_EXTRA_CA_CERTS`). Ruled out, because the CLI authenticates through that same proxy from the same container.
9. **No API key anywhere.** No `ANTHROPIC_API_KEY` on host or guest; no stored `anthropic` secret. Pure OAuth.

### Suggested improvements regardless of root cause

1. **Log the auth failure server-side.** `remote-server.log` should record which credential source was tried and why it was rejected. Right now there is nothing to go on — the same complaint #56840 makes.
2. **Make the error actionable for remote sessions.** "Sign in again" runs OAuth on the Mac and writes to the macOS Keychain, which can never fix authentication for a Linux guest reached over SSH. The message should name the machine that needs the credential.
3. **Keep the pushed remote agent and the CLI in version lockstep**, or document the required remote CLI version.

### Workaround

Use the terminal panel inside the desktop session and run `claude` there. Same connection, same folder, works fine. Only the chat pane is affected.

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Rechercherichtung

Start by comparing the desktop-pushed ccd-cli 2.1.260 remote agent with the working claude 2.1.263 CLI in the guest, using the reproduction steps and the remote-server.log mentioned in the report. Trace which credential source each path uses and make the desktop chat authenticate with the valid guest OAuth credentials, while recording an actionable remote-side error when authentication fails.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
docker, linux, node.js
Bereich
authentication, cli, desktop
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Aktiv
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.