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

Status Open
Reported on v2.1.260
Maintainer reply None cached
Activity 0 comments · opened Sep 7, 2026

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?

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

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/<id>/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
``

  1. 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
``

  1. Confirm the CLI is authenticated inside the VM:

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

  1. 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/<pid>/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/<id>/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.

View original on GitHub ↗