fix(auth): stop spurious sign-out on refresh (auth-lock deadlock)#116
Merged
Conversation
…esh sign-out
The auth bootstrap awaited supabase.rpc('has_role') inside the
onAuthStateChange callback. supabase-js holds the GoTrue cross-tab Web Lock
(navigator.locks) for the duration of that callback, so awaiting another
auth-dependent call inside it deadlocks token refresh on reload — the SDK
then signs the user out. Downstream, useSubscription clears the subscription
when user goes null, collapsing the plan to "free" and hiding the paid plan
card. The symptom only cleared on a full browser restart because the
contended Web Lock survives page reloads.
Set session/user state synchronously in the callback and defer the role
lookup via setTimeout(0), so no Supabase call is ever awaited while the lock
is held.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
dovesdataviewer | cd26362 | Commit Preview URL Branch Preview URL |
Jun 02 2026, 02:05 AM |
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
Coverage SummaryLines: 36.91% (2583/6997) · Statements: 36% · Functions: 30.95% · Branches: 37.52% Per-file coverage
|
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.
What
The auth bootstrap awaited
supabase.rpc('has_role')inside theonAuthStateChangecallback. supabase-js v2 holds the GoTrue cross-tab Web Lock (navigator.locks) for the duration of that callback, so awaiting another auth-dependent call inside it deadlocks token refresh on reload — the SDK then signs the user out.This fixes two symptoms that were actually one bug:
has_roleRPC is holding it → refresh hangs → SDK emitsSIGNED_OUT→useris wiped.usergoesnull,useSubscriptionclears the subscription → effective tier falls back tofree→ thePlanSection/ paidPricingCardscollapse to the free view.Why it looked like a caching issue
nullsession — no deadlock.Fix
src/contexts/AuthContext.tsx: setsession/userstate synchronously in theonAuthStateChangecallback and defer the admin-role RPC viasetTimeout(0), so no Supabase call is ever awaited while the auth lock is held. Added a guard comment to prevent reintroduction.The other
onAuthStateChangelisteners were audited and are already safe (autoSync.tsvoids its reconcile;AuthCallback.tsxonly navigates synchronously).Testing
npm run lint✓npm run typecheck✓npm run test:run— 801 passed ✓npm run build✓No automated regression test: the bug lives in a React context
useEffect, the repo has no React render test infra (vitest env isnode, no testing-library), andcontexts/**is excluded from coverage. Standing that up was judged disproportionate for this fix — happy to add it as a follow-up if desired.Follow-ups (not in this PR)
useStripePricesonly re-fetches on connectivity change, not sign-in/out (mostly moot once the spurious logout is gone).supabase/client.tsomitsstorageKey/detectSessionInUrl— defaults are fine but worth pinning if multiple Supabase projects ever share an origin.https://claude.ai/code/session_01R4MvBAJSBCs13thbkZEXTS
Generated by Claude Code