fix(auth): apply session User-Agent binding uniformly across auth surfaces - #2340
Conversation
…faces /auth/status and /auth/me validated sessions without the User-Agent the API middleware checks, so a session whose UA hash stopped matching (a browser auto-update rotates the UA string) read authenticated on status while every /api/* call returned 401. The SPA's LoginGate treats that contradiction as session-expired, re-checks status, gets authenticated, remounts the shell, and loops - the PWA refresh loop observed on the beta.46 deployment. The chat, canvas, terminal and web-chat WebSocket handlers had the inverse hole: they accepted a cookie the APIs reject. All six call sites now pass the request's User-Agent, so the stolen- cookie binding check gives one answer everywhere. Sessions created without a UA hash continue to validate regardless, unchanged.
|
ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing |
|
Warning Review limit reached
Next review available in: 37 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Files Reviewed (7 files)
Reviewed by step-3.7-flash · Input: 83.8K · Output: 18.4K · Cached: 1.4M |
Root cause of tonight's PWA refresh loop on the Pi (beta.46), fixed at the class level.
Mechanism: sessions store a SHA-256 hash of the login User-Agent as a stolen-cookie check. The API middleware verifies it on every request;
/auth/statusand/auth/medid not pass the UA, and the chat/canvas/terminal/web-chat WebSocket handlers did not either. When a browser auto-update rotated the UA string, the session became: authenticated per/auth/status, 401 per every/api/*call. LoginGate's session-expired handler re-checks status, sees authenticated, remounts the shell, the API barrage 401s again - a remount loop every few seconds. The WebSocket side is the same hole inverted: the most sensitive surfaces (terminal PTY) accepted a cookie the APIs reject.Fix: all six call sites pass the request/websocket User-Agent, so the binding check gives one answer everywhere. UA-less (legacy/script) sessions still validate regardless - semantics unchanged.
Proof: two new route-level tests (login under UA A, query under UA B) FAIL on unfixed
routes/auth.py(run demonstrated red before the fix was applied) and pass with it;tests/test_auth.py+ both channel-hub suites: 180 passed.Ops note: the live loop on the Pi was cleared by revoking the stale sessions (backup kept at
data/.auth_sessions.bak-ua-loop-*); this PR prevents recurrence and lands with the next release train.