Rotação de token de atualização JWT: padrão seguro para sistemas reais

A maioria dos tutoriais JWT param em "usar um token de atualização para sessões de longa duração". Eles raramente explicam o que acontece quando o token de atualização é roubado. Um token de atualização estático — que nunca muda — dá ao invasor o mesmo acesso persistente que um cookie de sessão roubado. Pior ainda, não há como detectar o roubo.
Rotação de token de atualização resolve isso emitindo um novo token de atualização a cada uso. Se um token antigo for reproduzido, toda a sessão será revogada. Este artigo aborda o padrão de implementação usado por Auth0, Okta e outros provedores de identidade sérios.
Por que os tokens de atualização estática falham
Um token de atualização estático tem um valor fixo para todo o tempo de vida da sessão (geralmente mais de 30 dias). Problemas:
- O roubo é silencioso — se um invasor roubar o token de atualização, ele poderá gerar novos tokens de acesso indefinidamente sem que o usuário saiba
- Sem detecção de repetição — o mesmo token pode ser usado repetidamente em locais diferentes
- A revogação é grosseira — para invalidar um token roubado, muitas vezes você precisa invalidar todas as sessões do usuário
A solução é tratar cada token de atualização como de uso único.
O modelo de rotação
Etapa 1: Login — Crie uma família de tokens
Quando o usuário autenticar, gere um family_id (UUID) que agrupe todos os tokens nesta sessão:
{ family_id: "f47ac10b-58cc-4372-a567-0e02b2c3d479", user_id: "user_123", refresh_token_hash: sha256(refresh_token), created_at: "2026-03-28T10:00:00Z", expires_at: "2026-04-27T10:00:00Z", used: false
}Armazene este registro no lado do servidor. Nunca armazene tokens de atualização em localStorage — use httpOnly cookies ou armazenamento nativo seguro.
Etapa 2: Atualização do token — Girar
Quando o cliente apresenta o token de atualização:
- Procure o hash do token no banco de dados
- Verifique se pertence a uma família ativa e não está marcado como
used - Marque como
usado: verdadeiro - Emitir um token de atualização new (novo valor aleatório, mesmo
family_id) - Emitir um novo token de acesso
- Armazene o novo hash do token de atualização
Etapa 3: detecção de repetição
Se um token de atualização marcado como usado: true for apresentado novamente, isso significa:
- Um invasor está reproduzindo um token roubado ou
- Um cliente legítimo está tentando novamente após uma falha de rede
A resposta segura: revogar todos os tokens da família. Isso força o usuário a fazer login novamente. É melhor incomodar um usuário legítimo uma vez do que permitir que um invasor mantenha o acesso.
// Repetição detectada — opção nuclear
aguarde db.query ( 'DELETE FROM refresh_tokens WHERE family_id = $1', [famíliaId]
);Esquema de banco de dados
Uma tabela de token de atualização mínima:
CREATE TABLE atualização_tokens ( id UUID CHAVE PRIMÁRIA PADRÃO gen_random_uuid(), family_id UUID NÃO NULO, user_id UUID NOT NULL REFERÊNCIAS usuários(id), token_hash TEXTO NÃO NULO ÚNICO, usado BOOLEAN PADRÃO FALSO, criado_em TIMESTAMPTZ DEFAULT agora(), expira_at TIMESTAMPTZ NÃO NULO, substituído_por REFERÊNCIAS UUID update_tokens(id)
); CRIAR ÍNDICE idx_refresh_family ON refrescante_tokens(family_id);
CRIAR ÍNDICE idx_refresh_user ON update_tokens(user_id);A coluna replaced_by cria uma cadeia que você pode seguir para fins de auditoria.
Tratamento de solicitações simultâneas
Em aplicativos reais, várias chamadas de API podem acionar uma atualização simultaneamente. Se a Chamada A girar o token enquanto a Chamada B ainda tiver o antigo, a Chamada B acionará a detecção de repetição – desconectando o usuário inesperadamente.
Padrão do período de carência
Permitir que o token de atualização anterior permaneça válido por um curto período (5 a 10 segundos) após a rotação:
const GRACE_PERIOD_MS = 10_000; if (token.usado) { const decorrido = Date.now() - token.rotated_at; se (decorrido < GRACE_PERIOD_MS) { // Within grace period — return the already-issued new tokens return getLatestTokensForFamily(token.family_id); } // Outside grace period — replay attack await revokeFamily(token.family_id); throw new UnauthorizedError('token_replayed');
}Monitoramento e Alertas
Rastreie estes sinais na produção:
- Repetir eventos por hora — um pico indica um ataque ativo ou um bug do lado do cliente
- Revogações familiares — altas taxas podem indicar roubo de token ou um cliente mal configurado
- Taxa de atualização por usuário — taxas anormalmente altas sugerem coleta de token
- Anomalias geográficas — atualização de um país diferente do login original
Token de atualização vs token de acesso: referência rápida
| Propriedade | Token de acesso | Token de atualização |
|---|---|---|
| Vida útil | 5–15 minutos | 7–30 dias |
| Format | JWT (independente) | String opaco (recomendado) |
| Armazenamento | Memória (variável JS) | httpSomente cookie |
| Enviado para | servidores API | Apenas servidor de autenticação |
| Rotação | Não necessário | A cada uso |
Para bugs de validação de reivindicação de tempo que frequentemente interagem com fluxos de atualização, consulte JWT exp/iat/nbf bugs comuns.
FAQ
Como devo lidar com solicitações de atualização simultâneas?
Use um curto período de carência (5 a 10 segundos) onde o token de atualização anterior ainda seja aceito. Isso lida com condições de corrida quando várias chamadas de API acionam uma atualização simultaneamente. Após o período de carência, apenas o token mais recente será válido.
Os tokens de atualização devem ser JWT ou strings opacas?
Strings opacos são geralmente mais seguros para tokens de atualização. Os JWTs carregam dados de carga útil que aumentam a superfície de ataque, e os tokens de atualização não precisam ser independentes, pois o servidor sempre os procura no banco de dados de qualquer maneira.
Por quanto tempo as sessões de atualização devem durar?
7–30 dias é o normal. Aplicativos de alta segurança (bancos, saúde) devem durar de 1 a 7 dias. Os aplicativos de consumo podem durar até 90 dias com rotação. Sempre combine sessões longas com impressão digital do dispositivo e detecção de anomalias.
Ferramentas e artigos relacionados
- Decodificador JWT — inspeciona tokens e verifica reivindicações de tempo
- Erros de segurança do JWT — armadilhas comuns do JWT além dos tokens de atualização
- JWT Time-Claim Bugs — distorção do relógio e problemas de ordem de validação
- Guia 2FA — fortalecer a autenticação além dos tokens