Repository navigation
fix(auth): stop random sign-outs with several tabs open (token mode) - #31
Merged
Merged
Conversation
Production runs Serverpod's token mode (no authCookie on Serverpod Cloud): every tab read the refresh token from shared storage and refreshed without coordination, so two tabs refreshing at once (laptop wake, tabs reloading together) reused a rotated refresh token and the server revoked the session. Every page load and app switch also forced a rotation. The apps now replace the JWT key provider on web in token mode: - the session lives in localStorage (wonky.auth.session), read fresh on every use and synced to other tabs through storage events; it is moved once from the old flutter_secure_storage so nobody is signed out; - a refresh runs under the cross-tab Web Lock and re-reads the session inside it, using another tab's fresh token instead of rotating again; - a page load checks the stored token instead of forcing a rotation; - switching apps and reloading wait for a refresh in flight. Development now matches production: authCookie and allowedOrigins are removed from development.yaml, the bundled config.json files set cookieAuth false, and the unused staging.yaml and production.yaml are deleted (Serverpod Cloud generates the config from its variables). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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
Users on wonky.work get signed out at random. Production runs Serverpod's token mode (
"cookieAuth": false: Serverpod Cloud has noauthCookie), where every tab reads the refresh token from shared browser storage and refreshes with no coordination between tabs. Refresh tokens are single-use, and the server revokes the session when a rotated one comes back. So two tabs refreshing at the same moment (laptop wake, tabs reloading together, tabs sharing the same expiry) sign the user out everywhere. Every page load and app switch also forced a rotation (ClientAuthSessionManager.initialize()), which made this more likely.Fix (client only, no Serverpod or server code changes)
On web in token mode, the apps replace Serverpod's JWT key provider (
SharedJwtAuthKeyProvider,packages/wonky_app/lib/src/auth/shared_session.dart):localStorage(wonky.auth.session) and read fresh on every use. Other tabs pick up sign-in, sign-out and rotations throughstorageevents. Existing sessions are moved once from the oldflutter_secure_storage, so nobody is signed out when this deploys.status.isSignedIn(). It rotates only when the token is about to expire, or once if the server rejects it.Desktop and cookie mode are unchanged.
Config
authCookieandallowedOriginsare removed, so local development matches production.config.json: set tocookieAuth: falsein every app.config/staging.yamlandconfig/production.yamlwere never used (Serverpod Cloud generates the config from its variables).specs/01§2.5 and §6,specs/13§4 and the board's GitHub README are updated.Testing
packages/wonky_app/test/auth/shared_session_test.dart. The key one simulates two tabs refreshing at once against a fake server that revokes reused tokens like Serverpod does. It fails with Serverpod's stock refresh; the new code rotates exactly once.wonky_appauth, bootstrap, shell and settings tests pass, as do the server config tests.dart analyzeis clean.Not covered
JwtAdmin.rotateRefreshToken), which should go upstream.flutter runapps on ports 8100–8104 now need a sign-in each, becauselocalStorageis per origin.🤖 Generated with Claude Code