Skip to content

feat(auth): accept a pasted redirect URL to sign in from a headless machine - #513

Draft
wyattjoh wants to merge 1 commit into
mainfrom
wyattjoh/auth-paste-back-login
Draft

wyattjoh wants to merge 1 commit into
mainfrom
wyattjoh/auth-paste-back-login

Conversation

@wyattjoh

@wyattjoh wyattjoh commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

What

clerk auth login can now finish on a machine without a browser. In an interactive terminal it shows a paste prompt next to the usual wait, so you can sign in on another device and paste back the URL your browser lands on.

Why

Login is an OAuth redirect to a local callback server on 127.0.0.1. Over SSH, or on any box without a GUI, you can open the printed URL on your laptop, but the final redirect then goes to the laptop's 127.0.0.1, fails to load, and the CLI waits until it times out. SSH port forwarding is the only workaround, and it's awkward because the callback port is random on every run.

How

  • The local callback server and the paste prompt race each other, and whichever delivers a code first wins. The loser is shut down: the prompt is aborted, or the server is stopped.
  • Only the full redirect URL is accepted, and it goes through the same validation as the loopback redirect. The state check refuses a URL from someone else's sign-in, so nobody can trick you into finishing their login and signing into their account (RFC 6749 §10.12). A wrong or stale URL re-prompts. A denied consent (error=) ends the login, as it does on the loopback path.
  • Nothing changes on the server side. The token exchange still uses the loopback redirect_uri, which Clerk already accepts on any port (RFC 8252 §7.3), and the code is useless without the PKCE verifier that never leaves the process (RFC 7636 §4.6). The pasted URL is never logged.
  • The paste prompt appears only in human mode with a TTY stdin. Agents, pipes, and CI keep the loopback-only wait.
  • stop() on the callback server now rejects the pending wait. Login carries on in the same process when the paste wins, and an open wait would have pinned the human-wait counter, making every later Ctrl-C exit 0. .claude/rules/interrupts.md is updated to match.
  • Device authorization (RFC 8628) was considered and not used. It is phishable by design: an attacker starts the flow and gets a victim to enter the code (RFC 8628 §5.4). It would also need the grant and a verification page configured on the CLI's OAuth app.
  • Accepted trade-off: when the loopback redirect wins, the aborted prompt's last frame stays on screen above "Completing authentication".

…achine

clerk auth login now races the loopback callback against a paste prompt in
interactive terminals. Signing in on another device leaves the browser on a
failed 127.0.0.1 redirect; pasting that URL completes the login. The pasted
URL passes the same state check as the loopback redirect, and the code is
still bound to the PKCE verifier held by the CLI.
@coderabbitai

coderabbitai Bot commented Oct 2, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Comment @coderabbitai help to get the list of available commands.

@changeset-bot

changeset-bot Bot commented Oct 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 913a1c3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
clerk Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant