Skip to content

feat(login): standardize all sign-ins on the device-code flow#995

Open
codyde wants to merge 1 commit into
masterfrom
cody/cli-device-code-default
Open

feat(login): standardize all sign-ins on the device-code flow#995
codyde wants to merge 1 commit into
masterfrom
cody/cli-device-code-default

Conversation

@codyde

@codyde codyde commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

What

railway login — and the implicit sign-in triggered by an unauthenticated railway up — now always use the OAuth device-code flow, instead of auto-opening a browser when a local display is reachable. The CLI prints a one-click sign-in link (plus a short code) that the human completes in a browser on any device.

Why

While reconciling agentic-signup dashboards, transport (browser vs device_code) turned out to be an environment/UX choice, orthogonal to who is signing in. Agent-vs-human is already tracked via caller on both transports, so transport was never the agent signal. Standardizing on one flow:

  • removes the display-detection branch (is_likely_headless) and the flaky open() fallback,
  • makes behavior identical across desktop, SSH, CI, and agent harnesses,
  • gives a single, consistent signup path to reason about and support.

Trade-off worth watching: browser was historically the higher-converting path for watched desktop sessions, and it's the bulk of current CLI signups. This PR is meant to try that trade-out — the existing cliAuthEventTrack telemetry (transport, outcome, transportReason, caller) lets us compare new-signup completion before/after.

Changes

  • exec_context::login_transport() always returns DeviceCode. It's the single policy function both explicit login and implicit up auth route through, so both are covered.
  • --browserless is now a no-op, kept for backward compatibility with scripts. It still differentiates telemetry (flag_browserless).
  • New transport_reason value default_device_code marks sessions that would previously have taken the browser path; env_ci / env_ssh / no_display / flag_browserless are still recorded so we can see how sessions would have routed under the old logic. (Passes the backend's ^[a-z_]{1,32}$ label validation.)
  • The browser machinery (browser_login + localhost callback server + success page) is retained as runtime-unreachable code so this is trivially reverted by restoring login_transport's body. The now-unconstructed AuthTransport::Browser variant is #[allow(dead_code)].
  • Updated the exec_context truth-table tests and the user-facing docstrings.

Testing

  • cargo test exec_context — 12/12 pass.
  • cargo check — clean, no warnings.

Revert

Restore the original login_transport body (if browserless || !self.browser_reachable { DeviceCode } else { Browser }) and the variant annotation; everything else is comments/tests.

🤖 Generated with Claude Code

`railway login` (and the implicit sign-in from an unauthenticated
`railway up`) now always use the OAuth device-code flow instead of
auto-opening a browser when a local display is reachable.

Transport was an environment/UX choice orthogonal to who is signing in
— agent vs human is tracked via `caller` on both paths — so routing
every sign-in through one transport removes the display-detection branch
and the flaky `open()` fallback, and makes behavior identical across
desktop, SSH, CI, and agent harnesses.

- `login_transport()` always returns `DeviceCode`; `--browserless` is
  now a no-op, kept for backward compatibility with scripts.
- New telemetry reason `default_device_code` marks sessions that would
  previously have taken the browser path; `env_ci`/`env_ssh`/
  `no_display`/`flag_browserless` are still recorded.
- The browser machinery (browser_login + localhost callback server) is
  retained as runtime-unreachable code so this can be reverted by
  restoring `login_transport`'s body; the now-unconstructed
  `AuthTransport::Browser` is `#[allow(dead_code)]`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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