The Web Locks API can stop five open tabs from simultaneously hammering an auth server with refresh-token calls, saving users from sudden logouts. By coordinating refreshes across tabs, a single request replaces the flood that normally triggers a session-kill when Refresh Token Rotation is in use.

The hidden overload in a multi-tab session

A typical single-page app adds an Axios interceptor that watches for a 401 response, flips a Boolean isRefreshing flag, and queues any outgoing requests until a new JWT arrives. Tested in one tab, the flow works flawlessly.

Open the same app in five tabs, let the access token expire, and all five tabs notice the 401 at the same millisecond. Each tab thinks it must refresh, so five identical refresh-token requests race the auth server. With Refresh Token Rotation—a security measure that invalidates the previous refresh token as soon as a new one is issued—the server sees the second request as a replay attack, flags the session as compromised, and revokes it. The user is logged out of every tab in an instant.

The root cause is JavaScript’s isolation model. A variable such as isRefreshing lives only in the tab that set it; other tabs have no way to know a refresh is already in progress. The result is a classic concurrency problem, but the “processes” are browser tabs rather than threads.

Why a cross-tab lock is the right tool

What we need is a way for tabs to talk to each other about a shared resource—in this case, the fresh JWT. The Web Locks API, exposed as navigator.locks, gives exactly that. It lets scripts request a named lock that the browser enforces across all contexts belonging to the same origin. If a lock is already held, other callers are queued until the holder releases it or the browser aborts it (for example, when the tab crashes). No external server, no polling, just native browser coordination.

Implementing the lock-based refresh flow

  1. Detect the 401 – The Axios interceptor catches the unauthorized response as before.
  2. Ask for an exclusive lock – The tab calls navigator.locks.request('auth_token_refresh_lock', async lock => { … }). Only one tab can enter the callback at a time.
  3. Double-check before hitting the network – Inside the lock, read a timestamp (or the token itself) from localStorage. If the timestamp is less than a few seconds old, another tab has already refreshed the token; the current tab skips the network call and simply reads the new JWT from storage.
  4. Refresh if needed – If the stored timestamp is stale, send the refresh request, store the new token and the current time in localStorage, then release the lock by returning from the callback.
  5. Resume queued requests – All other tabs that were waiting acquire the lock one after another, see the fresh timestamp, and finish without making another request.
async function refreshIfNeeded() {
  await navigator.locks.request('auth_token_refresh_lock', async lock => {
    const lastRefresh = Number(localStorage.getItem('token_refreshed_at') || 0);
    const now = Date.now();
    if (now - lastRefresh < 5_000) return; // another tab already refreshed

    const newToken = await callRefreshEndpoint(); // actual network call
    localStorage.setItem('jwt', newToken);
    localStorage.setItem('token_refreshed_at', now.toString());
  });
}

The pattern guarantees that, regardless of how many tabs are open, only one refresh request reaches the server.

Benefits you can measure

  • Network efficiency – One request replaces five, cutting bandwidth and server load dramatically.
  • Session safety – With Refresh Token Rotation, the server sees only a single use of the old refresh token, so it never flags the session as compromised.
  • Resilience – If the tab holding the lock crashes, the browser automatically releases the lock, preventing a deadlock that would otherwise stall all tabs.
  • Scalability – Users can open dozens of tabs without risking a cascade logout, because the coordination stays within the browser.

The flip side: browser support and fallbacks

The Web Locks API is a relatively new feature. Modern Chromium-based browsers and recent versions of Firefox implement it, but older browsers and Safari lack native support. In environments where the API is unavailable, developers must fall back to a less reliable technique—such as broadcasting a custom event via localStorage or using a shared worker—to approximate cross-tab signaling. Those workarounds lack the automatic dead-lock protection that navigator.locks provides, so they should be used with caution.

What to watch next

  • Standardisation progress – Keep an eye on the API’s adoption curve; broader support will make the lock-based approach the default for any cross-tab coordination.
  • Library wrappers – A few open-source utilities are already abstracting the lock request pattern, making it easier to plug into existing Axios interceptors.
  • Security audits – While the lock solves the concurrency issue, the refresh endpoint must still enforce proper token rotation and rate limiting, as a single malicious tab could still flood the server with requests if the lock is bypassed.

The takeaway is simple: treat a set of open tabs as a distributed system and give them a native synchronization primitive. By wiring the Web Locks API into the token-refresh flow, developers eliminate the “browser tab token trap” and keep users logged in, no matter how many tabs they juggle.