Paste into login OAuth code field is broken (works fine in main chat prompt, same terminal)
Summary
The single-line input field on the OAuth login screen ("Paste code here if prompted >") silently rejects pasted input. Typing works, but pasting from the clipboard inserts nothing (or only a few stray characters). The same terminals can paste into Claude Code's main chat prompt without issue, so this looks like a bug specific to the login prompt's input widget rather than a general TUI/terminal compatibility issue.
This blocks completion of the OAuth login flow on any host where the only way to get a long auth code from a browser into the terminal is via clipboard.
Reproduction
- On a fresh machine (no existing
~/.claude/.credentials.json), runclaude - Choose 1. Claude account with subscription · Pro, Max, Team, or Enterprise
- Browser doesn't open, copy the printed
https://claude.com/cai/oauth/authorize?...URL into a browser - Authorize in browser → get redirected to
https://platform.claude.com/oauth/callback?code=... - Copy the code from the callback page (or the full
code#stateblob, depending on flow) - Try to paste it into the
Paste code here if prompted >field in the terminal
Expected: The pasted code appears in the input field, Enter submits it, login completes.
Actual: Nothing visible appears in the input field. Pressing Enter does nothing, or submits an empty value, or the prompt re-shows. Login cannot complete via this path.
Workaround that proves it's not an OAuth/network problem: typing one character at a time works (but is impractical for ~100-char codes). Generating a long-lived token via claude setup-token on a machine where the login flow does work, then exporting it as CLAUDE_CODE_OAUTH_TOKEN on the broken host, completely bypasses the login screen and Claude Code starts normally — confirming the OAuth credentials are valid; the input widget on the login screen is the only blocker.
Evidence it's the login widget, not the terminal
Pasting a long string (e.g. a code block or a URL) into the main chat prompt of an already-logged-in Claude Code session works fine in the exact same terminal session that just failed at the login prompt. Same Ink runtime, same stdin, same terminal — different input component.
Tested environments
All affected:
| Terminal | Host | Result |
|---|---|---|
| Warp v0.x (latest) | macOS 15.7.1 → SSH → Ubuntu 24.04.4 | paste fails on login screen, works in main chat prompt |
| Apple Terminal | macOS 15.7.1 → SSH → Ubuntu 24.04.4 | same |
| TigerVNC viewer → tigervnc-server on Ubuntu 24.04.4, native xterm | direct on the Ubuntu host, no SSH | same |
Versions
- Claude Code (Linux server, where login fails): 2.1.105
- Claude Code (macOS, where login works fine): 2.1.107
- Node.js: v24.14.1
- OS: Ubuntu 24.04.4 LTS, kernel 6.8.0-107-generic
- macOS: 15.7.1 (24G231)
Hypothesis
Modern terminals send pasted text wrapped in bracketed paste escape sequences:
\x1b[200~<pasted text>\x1b[201~
Raw-mode TUI apps must explicitly handle these escape markers to distinguish paste from typed input. Claude Code's main chat prompt clearly handles them correctly. The login OAuth-code input widget appears to be a separate component that does not, so each character of the bracketed-paste payload is processed as an individual keystroke and either:
- the leading
\x1b[200~is interpreted as escape-then-command-keys and discarded - the input reader has length/character validation that rejects the burst
- per-keystroke re-renders are racing with the input buffer and dropping characters
Confirming this would be straightforward by enabling debug logging on the login widget's keystroke handler and observing what arrives during a paste.
Workaround for users
Skip the login flow entirely:
# On a working machine
claude setup-token
# copy the printed sk-ant-oat01-... token
# On the affected machine
echo 'export CLAUDE_CODE_OAUTH_TOKEN="sk-ant-oat01-..."' >> ~/.profile
. ~/.profile
claude # opens directly into the chat TUI, no login screen
This is the path I'm using on a headless Ubuntu server where the login paste is unrecoverable. It works perfectly — claude recognizes the env var, the existing OAuth credentials work, and the broken login widget is never touched. So the underlying auth path is fine; only the on-screen paste step is broken.
Suggested fix
The OAuth login input widget should:
- Enable bracketed paste reception explicitly (
process.stdinwith bracketed-paste escape detection) - Buffer characters between
\x1b[200~and\x1b[201~markers as a single atomic input - Insert the buffered string into the field state in one update rather than per-character
Or simpler: reuse whatever input widget powers the post-login chat prompt, since that one already handles paste correctly.
Why this matters
CLAUDE_CODE_OAUTH_TOKEN is documented but obscure. New users on a fresh machine — especially ones provisioning a remote dev environment, a headless server, or any environment where a graphical browser callback can't reach localhost directly — will hit the OAuth code-paste path as the default flow, can't complete it, and have no obvious next step. Fixing the input widget makes the documented "happy path" actually work.
Happy to test a fix on the affected hosts and confirm if helpful.
This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗