Login Flow Improvements and Fallback Handling · Entire

Review: PR #1366 — login: default to browser sign-in, add --device fallback

Verdict: Approve. Solid PR — clean structure, good test coverage at both unit and integration levels, careful comments, and the security fundamentals (PKCE S256, loopback-only listener, URL scheme validation, token validation before persist) are all in place. Unit tests pass locally. Two real-world UX gaps worth considering before or shortly after merge.

What it does

entire login now defaults to the RFC 8252 loopback authorization-code flow with PKCE (via auth-go v0.5.0's authcode package) when an interactive terminal is present, falling back to the device-code flow otherwise. --device forces the old flow. Both flows converge on a shared persistLogin tail (validate → keyring → contexts.json).

Strengths

Issues worth considering

  1. SSH with a TTY gets a broken default (cmd/entire/cli/login.go:79). CanPromptInteractively() is true over ssh -t, so the browser flow is chosen — but the loopback listener binds 127.0.0.1 on the remote host, which the user's local browser can't reach. Even the printed fallback URL can't complete. The user's only recourse is Ctrl-C and --device. gh and gcloud detect this (e.g. SSH_CONNECTION/SSH_TTY env vars) and route to the code flow. Suggest adding an SSH check to shouldUseBrowserLogin, or at minimum mentioning --device in the "Waiting for sign-in..." context so a stuck user knows the escape hatch.

  2. Wait has no deadline (login.go:184). The device flow bounds waiting via expires_in (capped at 15 min); the browser flow waits on the command context, which has no timeout — if the user closes the browser tab without completing, entire login hangs until Ctrl-C. A context.WithTimeout around flow.Wait (5–15 min) would match the device flow's behavior and most peer CLIs.

Minor / non-blocking

Security notes

All good: PKCE with S256 (verified against prod discovery doc per the PR body), state round-tripped and validated by the authcode lib, openBrowser still rejects non-HTTP(S) URLs before the test guard, token iss/exp cross-checked before persisting, and the loopback redirect was verified registered server-side for any-port 127.0.0.1/callback. The full authorize URL (with PKCE challenge) deliberately isn't printed on the happy path — nice touch.