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.
6 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Trick is to connect on a device that have the access to a browser and then copy credentials.json into the one that can't connect
You can even ask Claude to do it for you if you have access through ssh
Had to install VS Code just for that (pasting in VS Code WSL2 terminal somehow works)
Duplicate of https://github.com/anthropics/claude-code/issues/47699
Duplicate of #47669 — same bug: paste into the
/login"Paste code here" prompt is silently rejected (likely bracketed-paste handling). Closing in favor of that issue; please subscribe there for updates.This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.