fix(auth): make browser OAuth login survive real-world callback conditions#3280
Open
honbou wants to merge 1 commit into
Open
fix(auth): make browser OAuth login survive real-world callback conditions#3280honbou wants to merge 1 commit into
honbou wants to merge 1 commit into
Conversation
…tions The browser login flow failed on almost every headless/VM setup for four independent reasons, each of which aborted a login that had otherwise succeeded on Google's side: - The callback listener bound IPv4 loopback only. Browsers that resolve "localhost" to ::1 (Safari on macOS) could not reach it, so the redirect ended in "cannot connect to server". Bind both loopback families on the same port; IPv6 is best-effort. - Any request with a mismatched state pushed a fatal error onto the result channel, so a stale tab replaying an older callback killed the login in flight and invalidated the fresh authorization code. Reject such requests with 400 and keep waiting for the real callback. - The manual-paste reader treated stdin EOF as "manual input canceled". Under systemd, a pipe, or nohup that fires immediately, ending the login before the user could open the URL. Ignore empty reads. - The five minute timeout is not enough when the URL has to be moved to another machine and a tunnel set up. Default to 15 minutes, overridable via PICOCLAW_OAUTH_TIMEOUT. Adds regression tests for all four. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
honbou seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
picoclaw auth login --provider <oauth-provider>fails on almost every headless / remote setup, and each failure happens after the user has already approved consent — the authorization code is burned and the whole flow has to restart.Four independent causes, all found while authenticating Antigravity on a remote VM (related: #3274, #3278):
1. Callback listener binds IPv4 loopback only
listenOAuthCallbackbinds127.0.0.1only. Browsers that resolvelocalhostto::1first — Safari on macOS does — get connection refused, so the redirect ends in "cannot connect to server" even though the login succeeded on the provider's side. This also breaks the standardssh -Lworkaround unless the user happens to forward the right family.2. A stale callback kills the login in flight
Any request with a mismatched
statepushes a fatal error onto the result channel:So an old browser tab replaying a previous callback (or a prefetch, or a port scan) aborts the current login. In practice this is easy to hit: retry the login, an old tab reloads, and the fresh session dies with
login failed: state mismatch— invalidating the code the user just obtained.The state check is CSRF protection for the request; it should reject that request, not the session.
3.
manual input canceledfires immediately without a TTYThe manual-paste goroutine treats stdin EOF as an explicit cancel:
Under systemd, a pipe, or
nohup,ReadStringreturns EOF instantly, so the login aborts before the user can even open the URL — which is exactly the headless case the manual-paste path exists to serve.4. Five-minute timeout is too short for the headless path
The message tells the user to complete login in a local browser and paste the redirect URL back. Moving the URL to another machine and setting up a tunnel routinely takes longer than five minutes.
Changes
400and keep waiting for the real one.PICOCLAW_OAUTH_TIMEOUT(anytime.ParseDurationvalue).No config, CLI, or provider changes; behaviour is unchanged for a normal desktop login that succeeds on the first try.
Tests
Four regression tests in
pkg/auth/oauth_callback_test.go, one per bug — dual-family reachability (skips where there is no IPv6 loopback), stale callback followed by a successful real callback, empty-stdin login reaching the timeout instead of cancelling, and the timeout override.go test ./pkg/auth/passes.Verification
Built and deployed on the VM where the original failures occurred;
picoclaw auth login --provider antigravitynow completes through anssh -L 51121:localhost:51121tunnel without any of the four failure modes.