auth: manual/no-browser paste mode for Fjord OIDC login (--manual) + branded callback page #225
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/224-manual-fjord-login"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #224. On an SSO/OIDC deployment (production),
fj auth login --fjordcaptures the sign-in redirect on a127.0.0.1loopback listener. That only works when the browser is on the same machine asfj: sign in from an iPad or against a remote server and the redirect to127.0.0.1:47017/callbackcan't reach the listener, so sign-in can't complete. (Confirmed live: an iPad redirect failed to load but thecodewas still copyable from Safari's address bar.)This adds
--manual(alias--no-browser) to keep the whole Authorization Code + PKCE flow and change only how the code is obtained: instead of binding a listener, fj prints the authorize URL, the user signs in on any device, and pastes the redirected URL (or the bare code) back. No platform or Paragon changes:fj-cliis already registered with the loopback redirect, so manual mode pins the first registered URI (http://127.0.0.1:47017/callback) for the exact-match token exchange.This is the interim path; OAuth device flow (separate work) is the durable replacement.
What changed
--manual/--no-browseronfj auth login(Fjord mode only).login_fjord_oidcsplits into loopback vs manual code acquisition sharing PKCE, the token exchange, and persistence.src/fjord/oidc.rs::parse_pasted_callback): a full redirected URL, just itscode=…&state=…query, or a bare code. The returnedstateis CSRF-checked when present (PastedCode::check_state); a bare code has no state to check and relies on the PKCE verifier (held only by this process) plus the code's single use and short TTL.127.0.0.1page, which is expected.write_response→render_callback_page), previously a bare<h1>fj</h1>. Self-contained HTML: inline styles and the inlined Fjord mark (the page is served off the loopback with no network, so no external asset would load), light/dark aware viaprefers-color-scheme, palette mirrored from the fjord-platform design tokens. Success / failure / state-mismatch / not-found variants. Manual mode never reaches this page (it binds no listener); it's for the loopback flow.Not covered / notes
/oauth/authorize+/oauth/tokenfront door; nothing server-side changes.Checks
cargo fmt --all -- --checkcargo clippy --all-targets -- -D warnings(clean)cargo test(666 pass, 2 ignored; new unit tests cover URL/query/bare-code parsing, empty/error/codeless rejection, the state CSRF-check, a mocked manual exchange end-to-end, and branded-page invariants)Forseti review
No blocking findings from the lead reviewer.
No inline findings.
rasterstate/fj#225f5adddd6c1b9sha256:e569f57a3d955968a8e70cfbc231c30ebec597e99d76f24e215054b06327c7e4openai:gpt-5.5+anthropic:claude-haiku-4-5-2025100100GITHUB_TOKEN1405b8a0e06d