Skip to content

fix(auth): replace navigatorLock with processLock as default browser lock#2235

Open
mandarini wants to merge 3 commits intomasterfrom
fix/auth-replace-navigator-lock
Open

fix(auth): replace navigatorLock with processLock as default browser lock#2235
mandarini wants to merge 3 commits intomasterfrom
fix/auth-replace-navigator-lock

Conversation

@mandarini
Copy link
Copy Markdown
Contributor

@mandarini mandarini commented Apr 8, 2026

Description

What changed?

Replaced navigatorLock (Web Locks API) with processLock (in-process promise queue) as the default browser lock in GoTrueClient. Previously, any browser with navigator.locks support would use the Web Locks API for cross-tab auth coordination. Now all environments use processLock by default, which serializes operations within a single tab/process without touching the Web Locks API.

navigatorLock remains exported and available as an explicit opt-in:

import { navigatorLock } from '@supabase/auth-js'

createClient(url, key, { auth: { lock: navigatorLock } })

Why was this change needed?

navigator.locks causes 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:

  • React Strict Mode double-mount/unmount interrupting a lock request mid-flight (affects all Next.js 13+ apps in dev mode by default)
  • HMR tearing down components while a lock is held
  • localStorage.setItem() hanging due to quota exceeded or browser extension interference
  • Android Chrome not releasing locks from previous sessions

The 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) and likelyConcurrentRefreshes (within reuse interval) logic, returning valid tokens to both tabs without any client-side coordination. refresh_token_already_used is 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.

processLock still provides within-tab serialization, which is needed to prevent races between operations in the same tab (e.g. signOut racing with an in-flight auto-refresh).

Relates to: #2111, #936, #1594, #2013

Screenshots/Examples

N/A

Breaking changes

  • This PR contains no breaking changes

The default lock behavior changes, but no public API is removed or modified. navigatorLock remains exported. processLock was already exported. The lock and lockAcquireTimeout options continue to work as before.

Checklist

  • I have read the Contributing Guidelines
  • My PR title follows the conventional commit format: <type>(<scope>): <description>
  • I have run npx nx format to ensure consistent code formatting
  • I have added tests for new functionality (if applicable)
  • I have updated documentation (if applicable)

Additional notes

The server-side behavior this relies on (likelyNotSavedByClient counter logic) is confirmed in supabase/auth internal/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

@mandarini mandarini requested review from a team as code owners April 8, 2026 10:48
@github-actions github-actions bot added the auth-js Related to the auth-js library. label Apr 8, 2026
@mandarini mandarini self-assigned this Apr 8, 2026
@mandarini mandarini marked this pull request as draft April 8, 2026 10:51
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 8, 2026

Open in StackBlitz

@supabase/auth-js

npm i https://pkg.pr.new/@supabase/auth-js@2235

@supabase/functions-js

npm i https://pkg.pr.new/@supabase/functions-js@2235

@supabase/postgrest-js

npm i https://pkg.pr.new/@supabase/postgrest-js@2235

@supabase/realtime-js

npm i https://pkg.pr.new/@supabase/realtime-js@2235

@supabase/storage-js

npm i https://pkg.pr.new/@supabase/storage-js@2235

@supabase/supabase-js

npm i https://pkg.pr.new/@supabase/supabase-js@2235

commit: 1be080f

@mandarini mandarini marked this pull request as ready for review April 8, 2026 11:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auth-js Related to the auth-js library. do-not-merge Do not merge this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant