fix: forward Claude guided login verification code#1678
fix: forward Claude guided login verification code#1678simple-agent-manager[bot] wants to merge 12 commits into
Conversation
The Claude Code prompt treats one large stdin chunk as a paste and absorbs an inline trailing carriage return: realistic ~100-char codes were typed into the field but never submitted, so the guided login sat in 'exchanging' until the session TTL (reproduced against claude v2.1.220; 21-char test codes submit, which is why staging verification passed). Write the code, then send Enter as a separate write after a settle delay. Also fail visibly instead of stalling: any post-forward 'OAuth error:' screen is terminal (the previous pattern required a 'status code 4xx' wording that 401/state-mismatch/network failures never print), and a bounded exchange deadline reports 'exchange_timeout' distinctly through the DO when the CLI produces no recognizable outcome. Both knobs are env-configurable (CLAUDE_SETUP_ENTER_DELAY_MS, CLAUDE_SETUP_EXCHANGE_TIMEOUT_MS). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Post-verification fix: real codes never submitted inside the CLI (commit adc7c4f)Raphaël's real-subscription E2E failed: the modal sat on "Completing sign-in…" until the 15-min TTL (staging session Root cause (reproduced locally against Changes:
Staging verification (run 30197296704, deployed): session Follow-ups noted (not blocking): DO-side watchdog for Still do not merge — awaiting Raphaël's real-subscription code-paste E2E on staging. |
…etail The driver flattened every post-forward 'OAuth error:' render into 'Claude rejected the verification code', discarding the CLI line that distinguishes an incomplete paste (missing #state half — instant local failure), a server rejection (status-code wording), and a sandbox network failure. Reproduced each wording live against claude v2.1.220; renders arrive with characters dropped by Ink redraws, so classification tolerates that mangling. - driver: extract the last OAuth error line after a settle window (CLAUDE_SETUP_REJECTION_SETTLE_MS, default 400ms), redact token-like runs, classify into code_incomplete / code_rejected / exchange_network_error, and publish a bounded detail field alongside the failure state - DO: map the new failure classes to accurate guidance and append the sanitized detail as '[CLI: ...]' (printable ASCII, capped, sk-ant redacted); the driver's free-form error field is still never surfaced - modal: block a claude-code paste missing its '#' half before burning the setup session, with copy-the-entire-code guidance Verified end-to-end against the real CLI: no-# paste -> code_incomplete with the CLI's own 'full code was copied' advice; full-format fake code -> code_rejected with 'status code 400' detail. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…low-up Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Follow-up: real-code failure diagnosed — error detail is no longer discarded (
|



Summary
exchangingstate across DO/D1/UI, preserve server-side token capture/encrypted save/teardown, and keep one-active-session uniqueness through an additive index migrationAlarm candidate volume remains one session per DO. Each tick adds one sandbox state-file read before the existing credential-file check; worst case is bounded by one configured capture poll per active session and TTL teardown.
Validation
pnpm lint(0 errors; repository baseline warnings)pnpm typecheckpnpm buildStaging Verification (REQUIRED for all code changes — merge-blocking)
c3505f311Staging Verification Evidence
Deployment: https://github.com/raphaeltm/simple-agent-manager/actions/runs/30193502104 (success). Authenticated staging Playwright session
01KYEQ1PNJVAADQPMXMMG4FX1Vreachedwaiting_for_userwith a trusted Claude URL in 12.5s and no browser token;garbage#rejected-codetransitioned toexchanging, then the real CLI rejection surfaced as sanitizedcode_rejectedin 5.0s. Cleanup returned 200 and read-only D1 verification found zero active setup-session rows. Local component/visual audits passed at 375x667 and 1280x800. The successful real-subscription exchange remains Raphaël’s explicit manual gate.UI Compliance Checklist (Required for UI changes)
.codex/tmp/playwright-screenshots/End-to-End Verification (Required for multi-component changes)
Data Flow Trace
AgentCredentialConnectModal.handleSubmitVerificationCode→submitAgentCredentialSetupVerificationCode→ ownedPOST /:id/verification-code→submitSetupSessionVerificationCode→CredentialSetupSession.submitVerificationCode→ sandboxverification-code.txt→runClaudeSetupTokenPTY stdin → CLI OAuth exchange → server-onlyclaude-oauth-token.txt→attemptCapture→saveAgentCredentialForUser→ teardown.Untested Gaps
A successful real Claude subscription exchange cannot be automated without Raphaël's account. Staging verifies the complete no-account path, including rejected-code failure and cleanup; Raphaël will perform the final fresh-code success test.
Post-Mortem (Required for bug fix PRs)
What broke
Guided Claude login displayed the authorization URL but could never complete; it hung until TTL. The follow-up branch then asked users for a final token the browser never displays.
Root cause
PR #1671 launched
claude setup-tokenwith stdin ignored. Validation stopped at URL display, and the later fix modeled an imagined browser-token flow instead of the documented container flow.Class of bug
Flow shipped with a completion step that could not physically complete; mocks stopped before the real cross-boundary exchange.
Why it wasn't caught
There was no exact-stdin regression or full route-to-sandbox/state-file sequence, and staging did not exercise token capture.
Process fix included in this PR
Driver exact-byte regression, DO failure-fast tests, route/DO boundary coverage, component behavior, and two-viewport Playwright audit. The durable task records the incident and manual provider gate.
Post-mortem file
tasks/active/2026-07-26-claude-guided-verification-code.mdSpecialist Review Evidence (Required for agent-authored PRs)
needs-human-reviewlabel added and merge deferred to humanExceptions (If any)
Agent Preflight (Required)
Classification
External References
Reviewed the official documentation for Claude authentication (
https://code.claude.com/docs/en/authentication) and anthropics/claude-code issues #47773/#47699 via reviewed SAM idea 01KYEHTF6BA3ZPTN2RBRYBH462.Codebase Impact Analysis
apps/api/scripts/claude-setup-token.mjsand the sandbox image input contract;apps/api/src/durable-objects/credential-setup-session/plus its route/service and D1 index;apps/web/src/components/CodexConnectModal.tsxand API client; API unit/vertical-boundary tests and web component/Playwright tests.Documentation & Specs
No public docs page needs a change because this corrects an existing guided-login flow without adding configuration. The reviewed contract and manual gate are synchronized in
tasks/active/2026-07-26-claude-guided-verification-code.md, component copy, and behavioral tests.Constitution & Risk Check
Checked Principle XI and credential-boundary rules. The browser receives/submits only short-lived authorization material; the OAuth token remains server-side. Paths are fixed protocol filenames under a validated per-session home; session timing remains env-configured.