Skip to content

feat: Replace local login server with OAuth 2.0 Device Authorization Grant#12170

Draft
anthonyshew wants to merge 6 commits intomainfrom
shew/stop-login-server
Draft

feat: Replace local login server with OAuth 2.0 Device Authorization Grant#12170
anthonyshew wants to merge 6 commits intomainfrom
shew/stop-login-server

Conversation

@anthonyshew
Copy link
Copy Markdown
Contributor

@anthonyshew anthonyshew commented Mar 5, 2026

Summary

For Vercel logins only, replaces the axum-based localhost HTTP callback server with the OAuth 2.0 Device Authorization Grant (RFC 8628). Instead of spawning a local server and redirecting the browser back to 127.0.0.1:9789, the user visits a URL and enters a code directly in the browser.

Non-Vercel logins (self-hosted remote caches) are unchanged in behavior — they still use the localhost redirect flow with the same URL patterns and the same configurable callback port. The only difference is the implementation: a simple one-shot TcpListener instead of axum.

Why: The localhost server approach is fragile for Vercel logins (port conflicts, firewall rules, WSL networking, SSH sessions, containers). The device flow works everywhere — including headless environments — with no open ports required.

Non-Vercel users

No behavioral change. The TURBO_SSO_LOGIN_CALLBACK_PORT env var and sso_login_callback_port config option are preserved and continue to work for non-Vercel login/SSO flows.

Breaking Changes

  • LoginServer trait removed — tests using MockLoginServer need to be updated
  • login() and sso_login() now return (Token, Option<TokenSet>) instead of Token

How to Test

cargo test -p turborepo-auth         # 65 tests pass
cargo build -p turborepo             # Build the CLI
./target/debug/turbo login           # Vercel: device flow in browser
./target/debug/turbo login --sso-team <team>  # Vercel SSO

Non-Vercel login can be tested by configuring a loginUrl that doesn't contain vercel.com — it will use the old localhost redirect flow with the same URL patterns.

@anthonyshew anthonyshew requested a review from a team as a code owner March 5, 2026 20:40
@anthonyshew anthonyshew requested review from tknickman and removed request for a team March 5, 2026 20:40
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
examples-basic-web Ready Ready Preview, Comment, Open in v0 Mar 11, 2026 0:57am
examples-designsystem-docs Ready Ready Preview, Comment, Open in v0 Mar 11, 2026 0:57am
examples-gatsby-web Ready Ready Preview, Comment, Open in v0 Mar 11, 2026 0:57am
examples-kitchensink-blog Ready Ready Preview, Comment, Open in v0 Mar 11, 2026 0:57am
examples-nonmonorepo Ready Ready Preview, Comment, Open in v0 Mar 11, 2026 0:57am
examples-svelte-web Ready Ready Preview, Comment, Open in v0 Mar 11, 2026 0:57am
examples-tailwind-web Ready Ready Preview, Comment, Open in v0 Mar 11, 2026 0:57am
examples-vite-web Ready Ready Preview, Comment, Open in v0 Mar 11, 2026 0:57am
turbo-site Ready Ready Preview, Comment, Open in v0 Mar 11, 2026 0:57am
turborepo-agents Ready Ready Preview, Comment, Open in v0 Mar 11, 2026 0:57am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
turborepo-test-coverage Skipped Skipped Open in v0 Mar 11, 2026 0:57am

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 5, 2026

Coverage Report

Metric Coverage
Lines 85.17%
Functions 81.43%
Branches 0.00%

View full report

@anthonyshew anthonyshew marked this pull request as ready for review March 5, 2026 21:10
@anthonyshew anthonyshew marked this pull request as draft March 5, 2026 21:11
…Grant (RFC 8628)

Replace the axum-based localhost HTTP server login flow with the OAuth 2.0
Device Authorization Grant (RFC 8628). The user now visits a URL and enters
a code in the browser instead of relying on a localhost redirect.

- Add device_flow module implementing RFC 8628 (discover, device auth,
  token polling, introspection)
- Remove login_server.rs, axum/axum-server/async-trait/anyhow dependencies
- Remove TURBO_SSO_LOGIN_CALLBACK_PORT env var and sso_login_callback_port config
- SSO flow still uses a one-shot TcpListener for redirect, now with
  spawn_blocking, bounded reads, timeouts, and CSRF state validation
- Write OAuth tokens to both Vercel CLI auth.json and turbo config.json
- Custom Debug impl on TokenSet to redact secrets
- Validate OIDC discovery endpoint origins against issuer domain
- Derive OIDC issuer from login_url to support self-hosted deployments
@vercel vercel bot temporarily deployed to Preview – turborepo-test-coverage March 5, 2026 21:31 Inactive
@vercel vercel bot temporarily deployed to Preview – turborepo-test-coverage March 5, 2026 21:33 Inactive
Copy link
Copy Markdown

@AAorris AAorris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One line change recommended: Display user_code on its own in the log.

- Display user_code during device flow per RFC 8628 §3.3 MUST requirement
- Loop listener.accept in login/SSO redirects to handle browser preflight
  and favicon requests instead of consuming the single-shot listener
- Deduplicate is_vercel into auth/mod.rs
- Add subdomain validation test proving ends_with check is correct
- Add CSPRNG note on rand::random() usage for CSRF state generation
@anthonyshew anthonyshew force-pushed the shew/stop-login-server branch from 5b94cb5 to 4efe178 Compare March 11, 2026 12:56
@anthonyshew anthonyshew marked this pull request as ready for review March 11, 2026 13:11
@anthonyshew anthonyshew marked this pull request as draft March 11, 2026 13:11
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.

2 participants