fix(cli): prevent crashes and edge-case bugs in auth flows#46
Merged
Conversation
- Clamp non-positive device-code poll intervals so a negative server value no longer panics time.NewTicker - Join the browser-flow timer goroutine before returning to avoid a send-on-closed-channel panic - Fix slow_down backoff to grow the poll interval 1.5x per step instead of compounding super-exponentially - Strip trailing slashes from the server URL to avoid double-slash default endpoints - Reject a JWT payload of null instead of reporting it as an empty-but-valid claim set - Trim extra-claims flag keys so they override file entries as documented - Bound the callback port and fix an off-by-one in the human duration formatter - Adopt all refreshed token fields wholesale instead of a partial copy - Deduplicate duration config resolution into a shared resolver - Add regression tests for the negative interval and key trimming Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
This PR hardens the CLI’s OAuth authentication flows against malformed/malicious server responses and other edge cases that could previously cause crashes or incorrect behavior, and it introduces small refactors to reduce duplication while preserving behavior.
Changes:
- Prevents device-flow crashes by clamping non-positive polling intervals before creating tickers, and adjusts
slow_downbackoff growth to be linear (1.5× each step) rather than super-exponential. - Improves robustness and consistency across auth/config handling: trims trailing slashes on
SERVER_URL, deduplicates duration parsing logic, trims--extra-claimskeys, and rejects JWT payloads that decode to JSONnull. - Adds regression tests covering negative polling intervals and extra-claims key trimming/whitespace-only key rejection.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
device_flow.go |
Clamps server-provided poll interval to avoid time.NewTicker panics; revises slow_down backoff math. |
browser_flow.go |
Joins the timer-update goroutine via WaitGroup to avoid send-after-close panics on updates. |
config.go |
Validates callback port range, trims trailing slashes on ServerURL, trims extra-claims keys, and deduplicates duration parsing via parseDurationConfig. |
auth.go |
Copies refreshed token storage wholesale to avoid silently dropping fields on refresh. |
main.go |
Extracts a small useCached closure to reduce repeated assignments in cached-token paths. |
token_cmd.go |
Rejects JWT payloads that decode as JSON null to avoid treating malformed tokens as empty-but-valid claims. |
tui/styles.go |
Fixes a boundary condition so exactly-24-hour durations format as days/hours. |
polling_test.go |
Adds regression coverage ensuring negative device polling intervals don’t panic and return via context timeout. |
extra_claims_test.go |
Adds regression coverage for key whitespace trimming and whitespace-only key rejection. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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.
Summary
Fixes a set of latent crash and edge-case bugs across the OAuth flows, surfaced by a full-codebase review, plus two behavior-preserving simplifications. The standout is a server-driven
panicin the device flow (a negativeintervalreachestime.NewTicker, which panics and crashes the CLI). All changes are accompanied by a passing test suite and three new regression tests.AI Authorship
auth.go,browser_flow.go,config.go,device_flow.go,main.go,token_cmd.go,tui/styles.go,polling_test.go,extra_claims_test.goChange classification
Touches the OAuth device/browser auth flows, token refresh, and config resolution. A bug here affects every authentication.
Verification
go test ./...)httptestserversmake fmt,go build ./...,go vet ./...,make lint(0 issues),go test ./...— all green. The negative-interval test returns in 0.20s (confirming the clamp short-circuits the 5s poll), proving it no longer panics.Verifiability check
Security check (PR touches the OAuth server interface)
expires_in/intervaland anullJWT payload against malformed/malicious server responsesRisk & rollback
slow_downbackoff now grows 1.5×/step (was compounding) — timing-only, still capped at 60s. The duration-config dedup (parseDurationConfig) preserves the exact same returns/warnings (covered byTestRefreshThresholdConfig). The server-URL trailing-slash trim is strictly safer (a deployment relying on a literal trailing slash is normalized, not broken).fix(cli): prevent crashes and edge-case bugs in auth flows.Reviewer guide
device_flow.go— non-positiveintervalclamp (panic fix) and the rewrittenslow_downbackoff mathbrowser_flow.go— the timer goroutine is now joined (WaitGroup) before return; verify the LIFO defer order (close(done)thenWait) closes the send-on-closed-channel raceconfig.go—parseDurationConfigdedup, server-URL trim placement (after validation), andparseExtraClaimPairkey trimming viastrings.Cuttui/styles.go(>= 24off-by-one),token_cmd.go(null-payload guard),auth.go(*storage = *newStorage),main.go(useCachedclosure extraction), and the two test files.🤖 Generated with Claude Code