A Web Locks API pode impedir que cinco abas abertas sobrecarreguem simultaneamente um servidor de autenticação com chamadas de refresh-token, poupando os usuários de logouts repentinos. Ao coordenar as atualizações entre as abas, uma única requisição substitui a enxurrada que normalmente aciona o encerramento da sessão quando o Refresh Token Rotation está em uso.
A sobrecarga oculta em uma sessão de múltiplas abas
Um aplicativo de página única (SPA) típico adiciona um interceptor do Axios que monitora uma resposta 401, altera uma flag booleana isRefreshing e coloca em fila quaisquer requisições de saída até que um novo JWT chegue. Testado em uma única aba, o fluxo funciona perfeitamente.
Abra o mesmo aplicativo em cinco abas, deixe o token de acesso expirar e todas as cinco abas notarão o 401 no mesmo milissegundo. Cada aba pensa que deve atualizar, então cinco requisições de refresh-token idênticas competem pelo servidor de autenticação. Com o Refresh Token Rotation — uma medida de segurança que invalida o refresh token anterior assim que um novo é emitido — o servidor vê a segunda requisição como um ataque de replay, marca a sessão como comprometida e a revoga. O usuário é desconectado de todas as abas instantaneamente.
A causa raiz é o modelo de isolamento do JavaScript. Uma variável como isRefreshing vive apenas na aba que a definiu; outras abas não têm como saber que uma atualização já está em andamento. O resultado é um problema clássico de concorrência, mas os "processos" são abas do navegador em vez de threads.
Por que um lock entre abas é a ferramenta certa
O que precisamos é de uma maneira para que as abas se comuniquem sobre um recurso compartilhado — neste caso, o JWT atualizado. A Web Locks API, exposta como navigator.locks, oferece exatamente isso. Ela permite que scripts solicitem um lock nomeado que o navegador impõe em todos os contextos pertencentes à mesma origem. Se um lock já estiver ocupado, outros chamadores são colocados em fila até que o detentor o libere ou o navegador o interrompa (por exemplo, quando a aba trava). Sem servidor externo, sem polling, apenas coordenação nativa do navegador.
Implementando o fluxo de atualização baseado em lock
- Detectar o 401 – O interceptor do Axios captura a resposta não autorizada como antes.
- Solicitar um lock exclusivo – A aba chama
navigator.locks.request('auth_token_refresh_lock', async lock => { … }). Apenas uma aba pode entrar no callback por vez. - Verificar novamente antes de acessar a rede – Dentro do lock, leia um timestamp (ou o próprio token) do
localStorage. Se o timestamp tiver menos de alguns segundos, outra aba já atualizou o token; a aba atual pula a chamada de rede e simplesmente lê o novo JWT do armazenamento. - Atualizar se necessário – Se o timestamp armazenado estiver expirado, envie a requisição de refresh, armazene o novo token e a hora atual no
localStoragee, em seguida, libere o lock retornando do callback. - Retomar as requisições em fila – Todas as outras abas que estavam esperando adquirem o lock uma após a outra, veem o timestamp atualizado e finalizam sem fazer outra requisição.
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());
});
}
O padrão garante que, independentemente de quantas abas estejam abertas, apenas uma requisição de refresh chegará ao servidor.
Benefícios que você pode medir
- Eficiência de rede – Uma requisição substitui cinco, reduzindo drasticamente a largura de banda e a carga do servidor.
- Segurança da sessão – Com o Refresh Token Rotation, o servidor vê apenas um único uso do antigo refresh token, portanto, nunca marca a sessão como comprometida.
- Resiliência – Se a aba que detém o lock travar, o navegador libera o lock automaticamente, evitando um deadlock que, de outra forma, travaria todas as abas.
- Escalabilidade – Os usuários podem abrir dezenas de abas sem o risco de um logout em cascata, pois a coordenação permanece dentro do navegador.
O outro lado: suporte do navegador e fallbacks
A Web Locks API é um recurso relativamente novo. Navegadores modernos baseados em Chromium e versões recentes do Firefox a implementam, mas navegadores mais antigos e o Safari carecem de suporte nativo. Em ambientes onde a API não está disponível, os desenvolvedores devem recorrer a uma técnica menos confiável — como a transmissão de um evento personalizado via localStorage ou o uso de um shared worker — para aproximar o sinal de comunicação entre abas. Essas soluções alternativas carecem da proteção automática contra deadlock que o navigator.locks oferece, portanto, devem ser usadas com cautela.
O que observar a seguir
- Progresso da padronização – Fique de olho na curva de adoção da API; um suporte mais amplo tornará a abordagem baseada em locks o padrão para qualquer coordenação entre abas.
- Wrappers de biblioteca – Alguns utilitários de código aberto já estão abstraindo o padrão de requisição de lock, facilitando a integração com interceptadores do Axios existentes.
- Auditorias de segurança – Embora o lock resolva o problema de concorrência, o endpoint de refresh ainda deve impor a rotação adequada de tokens e o rate limiting, pois uma única aba maliciosa ainda poderia inundar o servidor com requisições se o lock for contornado.
A conclusão é simples: trate um conjunto de abas abertas como um sistema distribuído e forneça a elas uma primitiva de sincronização nativa. Ao integrar a Web Locks API ao fluxo de atualização de token, os desenvolvedores eliminam a “armadilha do token em abas do navegador” e mantêm os usuários logados, não importa com quantas abas eles lidem.
