La Web Locks API puede evitar que cinco pestañas abiertas saturen simultáneamente un servidor de autenticación con llamadas de refresh-token, salvando a los usuarios de cierres de sesión repentinos. Al coordinar las actualizaciones entre pestañas, una sola solicitud reemplaza la avalancha que normalmente provoca la anulación de la sesión cuando se utiliza Refresh Token Rotation.

La sobrecarga oculta en una sesión de múltiples pestañas

Una aplicación de página única (SPA) típica añade un interceptor de Axios que vigila una respuesta 401, cambia un flag booleano isRefreshing y pone en cola cualquier solicitud saliente hasta que llega un nuevo JWT. Probado en una sola pestaña, el flujo funciona a la perfección.

Abre la misma aplicación en cinco pestañas, deja que el token de acceso expire y las cinco pestañas detectarán el 401 en el mismo milisegundo. Cada pestaña piensa que debe actualizarse, por lo que cinco solicitudes de refresh-token idénticas compiten por llegar al servidor de autenticación. Con Refresh Token Rotation —una medida de seguridad que invalida el token de actualización anterior tan pronto como se emite uno nuevo— el servidor detecta la segunda solicitud como un ataque de repetición (replay attack), marca la sesión como comprometida y la revoca. El usuario es expulsado de todas las pestañas en un instante.

La causa raíz es el modelo de aislamiento de JavaScript. Una variable como isRefreshing vive solo en la pestaña que la estableció; las demás pestañas no tienen forma de saber que ya hay una actualización en curso. El resultado es un problema clásico de concurrencia, pero los "procesos" son pestañas del navegador en lugar de hilos (threads).

Por qué un bloqueo entre pestañas es la herramienta adecuada

Lo que necesitamos es una forma de que las pestañas se comuniquen entre sí sobre un recurso compartido; en este caso, el nuevo JWT. La Web Locks API, expuesta como navigator.locks, ofrece exactamente eso. Permite que los scripts soliciten un bloqueo con nombre que el navegador impone en todos los contextos pertenecientes al mismo origen. Si un bloqueo ya está ocupado, los demás solicitantes se ponen en cola hasta que el poseedor lo libera o el navegador lo aborta (por ejemplo, cuando la pestaña falla). Sin servidores externos, sin polling, solo coordinación nativa del navegador.

Implementación del flujo de actualización basado en bloqueos

  1. Detectar el 401 – El interceptor de Axios captura la respuesta no autorizada como antes.
  2. Solicitar un bloqueo exclusivo – La pestaña llama a navigator.locks.request('auth_token_refresh_lock', async lock => { … }). Solo una pestaña puede entrar en el callback a la vez.
  3. Verificar de nuevo antes de realizar la llamada de red – Dentro del bloqueo, lee una marca de tiempo (o el propio token) de localStorage. Si la marca de tiempo tiene menos de unos pocos segundos, otra pestaña ya ha actualizado el token; la pestaña actual se salta la llamada de red y simplemente lee el nuevo JWT del almacenamiento.
  4. Actualizar si es necesario – Si la marca de tiempo almacenada es antigua, envía la solicitud de actualización, guarda el nuevo token y la hora actual en localStorage, y luego libera el bloqueo al finalizar el callback.
  5. Reanudar las solicitudes en cola – Todas las demás pestañas que estaban esperando adquieren el bloqueo una tras otra, ven la marca de tiempo actualizada y terminan sin realizar otra solicitud.
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());
  });
}

El patrón garantiza que, independientemente de cuántas pestañas estén abiertas, solo una solicitud de actualización llegue al servidor.

Beneficios que puedes medir

  • Eficiencia de red – Una solicitud reemplaza a cinco, reduciendo drásticamente el ancho de banda y la carga del servidor.
  • Seguridad de la sesión – Con Refresh Token Rotation, el servidor solo ve un único uso del antiguo refresh token, por lo que nunca marca la sesión como comprometida.
  • Resiliencia – Si la pestaña que mantiene el bloqueo falla, el navegador libera automáticamente el bloqueo, evitando un interbloqueo (deadlock) que de otro modo detendría todas las pestañas.
  • Escalabilidad – Los usuarios pueden abrir docenas de pestañas sin riesgo de un cierre de sesión en cascada, ya que la coordinación se mantiene dentro del navegador.

La otra cara: soporte del navegador y alternativas

La Web Locks API es una característica relativamente nueva. Los navegadores modernos basados en Chromium y las versiones recientes de Firefox la implementan, pero los navegadores antiguos y Safari carecen de soporte nativo. En entornos donde la API no está disponible, los desarrolladores deben recurrir a una técnica menos fiable —como la difusión de un evento personalizado a través de localStorage o el uso de un shared worker— para aproximar la señalización entre pestañas. Esas soluciones alternativas carecen de la protección automática contra interbloqueos que proporciona navigator.locks, por lo que deben usarse con precaución.

Qué observar a continuación

  • Progreso de la estandarización – Siga de cerca la curva de adopción de la API; un soporte más amplio convertirá el enfoque basado en bloqueos en el estándar por defecto para cualquier coordinación entre pestañas.
  • Wrappers de librerías – Algunas utilidades de código abierto ya están abstrayendo el patrón de solicitud de bloqueo, lo que facilita su integración en los interceptores de Axios existentes.
  • Auditorías de seguridad – Si bien el bloqueo resuelve el problema de concurrencia, el endpoint de refresco aún debe aplicar una rotación de tokens y una limitación de tasa adecuadas, ya que una sola pestaña maliciosa aún podría inundar el servidor con solicitudes si se evade el bloqueo.

La conclusión es sencilla: trate un conjunto de pestañas abiertas como un sistema distribuido y bríndeles una primitiva de sincronización nativa. Al integrar la Web Locks API en el flujo de refresco de tokens, los desarrolladores eliminan la "trampa de tokens de la pestaña del navegador" y mantienen a los usuarios conectados, sin importar cuántas pestañas manejen.