fix(auth): replace navigatorLock with processLock as default browser lock#2235
Open
fix(auth): replace navigatorLock with processLock as default browser lock#2235
Conversation
@supabase/auth-js
@supabase/functions-js
@supabase/postgrest-js
@supabase/realtime-js
@supabase/storage-js
@supabase/supabase-js
commit: |
38f8d49 to
5d584f0
Compare
This was referenced Apr 9, 2026
5d584f0 to
1be080f
Compare
Merged
7 tasks
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.
Description
What changed?
Replaced
navigatorLock(Web Locks API) withprocessLock(in-process promise queue) as the default browser lock inGoTrueClient. Previously, any browser withnavigator.lockssupport would use the Web Locks API for cross-tab auth coordination. Now all environments useprocessLockby default, which serializes operations within a single tab/process without touching the Web Locks API.navigatorLockremains exported and available as an explicit opt-in:Why was this change needed?
navigator.lockscauses permanent authentication deadlocks in production when a lock is acquired but never released. Once a lock is orphaned, every subsequent auth call in that tab hangs indefinitely until the user closes the browser. Known triggers:localStorage.setItem()hanging due to quota exceeded or browser extension interferenceThe steal-based recovery added in #2106 and #2178 addressed the symptom but introduced new failure modes (double-write windows, cascade when stolen). This PR addresses the root cause by removing the Web Locks API from the default path entirely.
Cross-tab concurrent refresh races are now handled server-side by GoTrue's refresh token reuse detection. When two tabs refresh simultaneously, the server allows both via the
likelyNotSavedByClient(counterDifference == 1) andlikelyConcurrentRefreshes(within reuse interval) logic, returning valid tokens to both tabs without any client-side coordination.refresh_token_already_usedis only returned for genuinely stale tokens outside the reuse window, at which point the session is already server-side revoked and the existing sign-out behavior is correct.processLockstill provides within-tab serialization, which is needed to prevent races between operations in the same tab (e.g.signOutracing with an in-flight auto-refresh).Relates to: #2111, #936, #1594, #2013
Screenshots/Examples
N/A
Breaking changes
The default lock behavior changes, but no public API is removed or modified.
navigatorLockremains exported.processLockwas already exported. ThelockandlockAcquireTimeoutoptions continue to work as before.Checklist
<type>(<scope>): <description>npx nx formatto ensure consistent code formattingAdditional notes
The server-side behavior this relies on (
likelyNotSavedByClientcounter logic) is confirmed insupabase/authinternal/tokens/service.go. The reuse detection has been in production since the v2 refresh token algorithm rollout (Oct 2025).Try it out
You can try out this PR on
2.103.1-beta.0