Cloud sign-in: Claude signs in on the approve, no code to paste

Merged
TE
2d ago
+1100-97

Leo: "yeah that should be fine right? cuz man i dont wanna be liable for peoples' subscription tokns" β€” the Cloud sign-in should be one click plus the provider's approve page, with nothing else. #33014 made it one click, but Claude still needed a code pasted back. This removes the paste.

Spec: leo-workspace design/cloud.md (sign-in on the machine; we never hold a subscription token).

What changes

acpmux agent_login

  • claude auth login runs with BROWSER set to a shim in the login's private 0700 folder. The shim writes the automatic sign-in URL Claude asks to open to a 0600 file and opens nothing.
  • start answers it as autoUrl + callbackPort only when it is on an allowed sign-in host and its single redirect_uri is exactly http://localhost:<port>/callback. Otherwise the start is unchanged (manual URL + code).
  • A Claude finish with no code (only after an automatic start) waits for claude to exit on its own once its listener gets the approve. A pasted code still works as the fallback for the same login.

Host: a machine-bound sign-in tab

  • New browser.openIn target cmux-chat-machine: on the person's click (or the start's one-shot sign-in credit), the host opens the automatic page in a Chromium tab whose localhost is bound to the chat's Cloud machine over loopback-forward-v1.
  • The tab uses the person's normal browser store, so their claude.com session is used. Its non-loopback pages keep the .noLoopback guard; the redirect to localhost:<port>/callback reaches Claude's own listener on the machine.
  • cmux only carries the TCP bytes. It never reads or stores the code or the token. The binding is by page identity at adoption (it survives reroute and hibernation), capped at 64 entries.
  • A bound tab never reaches this Mac's localhost: a bound tab whose machine is gone gets a blank store.

Card

  • With autoUrl, Sign in to Claude opens the page on the machine and shows "Approve on the sign-in page; it finishes on its own." There is no code field.
  • "Paste a code instead" is a quiet link. The card falls back to the code page by itself when the host can't open the bound tab (a WebKit-only host, or a machine without loopback-forward-v1) and on older apps.

Risk

  • The OAuth code passes through a localhost URL in a browser tab, so browser history and tab records may hold it. It is single-use and PKCE-bound (useless without the verifier, which stays in claude on the machine).
  • Routing: only tabs adopted from this one open are bound. Other remote-tab routing is unchanged.

Tests

  • acpmux unit tests: auto URL parsing, and the shim's file modes and symlink refusal.
  • acpmux over-the-wire test: the fake claude calls $BROWSER. It covers approve, paste while waiting, restart while waiting, and a run with no listener.
  • Webview: cloud-signin-card.test.tsx covers the approve flow, the fallbacks, paste instead, and a mismatched port.
  • Swift: AgentPaneSignInPageTests covers callback-port parsing, and that the machine open happens only with a host opener and the person's click.

Agent session: agent session

πŸ€– Generated with Claude Code