Syncing Auth State Across Tabs with Axios

This article explains how to manage and synchronize user authentication state across multiple browser tabs using the Axios HTTP client. Because Axios is purely a request library without native cross-tab awareness, synchronizing authentication tokens, logins, and logouts requires integrating Axios interceptors with browser-level APIs like the Storage Event, the Broadcast Channel API, or the Web Locks API.

The Role of Axios in Multi-Tab Authentication

Axios does not maintain state across browser tabs by itself. Instead, it serves as the operational layer that attaches authentication credentials (such as JWT bearer tokens) to outgoing requests and reacts to authentication failures (such as 401 Unauthorized responses).

To achieve cross-tab synchronization, developers use Axios request and response interceptors as the bridge between in-memory application state and browser-level communication channels.

Core Synchronization Mechanisms

Synchronizing authentication with Axios relies on pairing interceptors with one of several browser APIs.

1. The Storage Event Listener

When tokens are stored in localStorage, changes made in one tab trigger a storage event in all other open tabs of the same origin.

2. The Broadcast Channel API

The BroadcastChannel API allows direct, low-latency messaging between browser contexts (tabs, windows, iframes, and workers).

3. Synchronizing Token Refreshes with Web Locks

A common issue in multi-tab setups is the "refresh race condition," where multiple tabs make requests simultaneously with an expired token, causing each tab to trigger a separate refresh token request.

To resolve this with Axios:

  1. Catching the Expiry: An Axios response interceptor intercepts a 401 status code.
  2. Acquiring a Lock: The tab uses navigator.locks.request('auth_refresh_lock', ...) to ensure only one tab executes the refresh call.
  3. Execution: The leader tab uses Axios to request a new access token from the server.
  4. Broadcast & Retry: Once resolved, the leader updates storage, broadcasts the new token to waiting tabs, and retries the failed Axios request. The other tabs release their locks, read the newly issued token, and retry their pending Axios calls.

Dynamic Token Resolution in Axios Interceptors

To prevent tabs from sending stale tokens, Axios request interceptors should dynamically retrieve the token before every outgoing HTTP request rather than relying on a static default header configured at initialization:

axios.interceptors.request.use((config) => {
  // Always fetch the latest token from storage or current memory
  const token = localStorage.getItem('access_token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

By querying the updated storage value on each execution, Axios immediately inherits any credential updates performed by adjacent browser tabs.