Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Refresh Tokens no Node.js

Atualizado em: 6 de outubro de 2026

Estação de trabalho usada no desenvolvimento de aplicações Node.js

Refresh tokens permitem renovar access tokens sem exigir login completo a cada poucos minutos. Eles devem ser tratados como credenciais de longa duração: armazenados com segurança, rotacionados a cada uso, revogados no logout e protegidos contra replay.

Um bom desenho separa access token curto, usado nas APIs, de refresh token opaco, usado apenas no endpoint de renovação.

Gerando um token opaco

import crypto from 'node:crypto';

function createRefreshToken() {
  return crypto.randomBytes(48).toString('base64url');
}

function hashToken(token) {
  return crypto.createHash('sha256').update(token).digest('hex');
}

Armazene somente o hash no banco. Se o banco vazar, os valores não podem ser usados diretamente.

Registro da sessão

await sessions.insert({
  id: crypto.randomUUID(),
  userId: user.id,
  tokenHash: hashToken(refreshToken),
  familyId: crypto.randomUUID(),
  expiresAt,
  createdAt: new Date(),
  revokedAt: null,
});

O familyId conecta tokens gerados pela mesma sessão e permite revogar toda a cadeia em caso de replay.

res.cookie('__Host-refresh', refreshToken, {
  httpOnly: true,
  secure: true,
  sameSite: 'strict',
  path: '/auth/refresh',
  maxAge: 1000 * 60 * 60 * 24 * 30,
});

Em aplicações realmente cross-site, SameSite pode precisar de none. Nesse caso, exija validação de Origin e proteção CSRF.

Rotação a cada uso

Quando um token válido é apresentado, marque-o como consumido e gere outro na mesma transação:

await database.transaction(async (tx) => {
  const session = await tx.sessions.findByTokenHash(hashToken(token), {
    forUpdate: true,
  });

  validateSession(session);

  await tx.sessions.markRotated(session.id, new Date());

  const nextToken = createRefreshToken();
  await tx.sessions.insert({
    userId: session.userId,
    tokenHash: hashToken(nextToken),
    familyId: session.familyId,
    parentId: session.id,
    expiresAt: session.expiresAt,
  });

  return nextToken;
});

A operação precisa ser atômica para impedir duas renovações simultâneas com o mesmo token.

Detecção de replay

Se um token já rotacionado aparecer novamente, ele pode ter sido copiado. Revogue toda a família:

if (session.rotatedAt) {
  await sessions.revokeFamily(session.familyId, 'refresh_token_reuse');
  throw new AuthenticationError('Sessão revogada');
}

O usuário precisará autenticar novamente. Registre o evento sem guardar o token.

Concorrência legítima

Duas abas podem tentar renovar ao mesmo tempo. Uma tolerância curta ou mecanismo de resultado reutilizável pode reduzir falsos positivos, mas amplia a janela de replay. Avalie o risco e mantenha a lógica simples sempre que possível.

Expiração absoluta e ociosa

Use dois limites:

  • expiração absoluta da sessão;
  • expiração por inatividade.

Rotacionar não deve renovar indefinidamente o limite absoluto, a menos que a política de negócio determine.

Endpoint de refresh

app.post('/auth/refresh', validateOrigin, async (req, res) => {
  const token = req.cookies['__Host-refresh'];
  if (!token) {
    res.status(401).json({ error: 'missing_refresh_token' });
    return;
  }

  const result = await rotateRefreshToken(token);

  setRefreshCookie(res, result.refreshToken);
  res.set('Cache-Control', 'no-store');
  res.json({ accessToken: result.accessToken });
});

Não aceite refresh token na query string. Limite body, frequência e tempo de processamento.

Access token curto

O endpoint deve emitir access token com validade curta, issuer e audience corretos. Não reutilize o refresh token como Bearer token de API.

Logout da sessão atual

await sessions.revokeByTokenHash(hashToken(token), 'logout');
res.clearCookie('__Host-refresh', {
  secure: true,
  sameSite: 'strict',
  path: '/auth/refresh',
});

Limpar o cookie sem revogar o servidor deixa uma cópia roubada válida.

Logout de todos os dispositivos

Revogue todas as famílias do usuário. Isso é útil após troca de senha, suspeita de invasão ou solicitação explícita.

Lista de sessões

Permita que o usuário veja dispositivos e revogue sessões. Armazene apenas metadados mínimos: data, último uso, nome aproximado do dispositivo e IP truncado quando permitido pela política de privacidade.

Vinculação ao dispositivo

User-Agent e IP mudam e podem gerar bloqueios indevidos. Use-os como sinal de risco, não como única prova. Fingerprinting agressivo pode violar privacidade.

MFA e elevação de privilégio

Uma sessão criada antes do MFA não deve receber privilégios elevados automaticamente. Registre nível de autenticação e exija step-up para operações críticas.

Troca de senha

Após troca ou recuperação de senha, revogue sessões antigas conforme a política. Se o usuário suspeita de invasão, a revogação global deve ser padrão.

Armazenamento em aplicativo móvel

Use armazenamento seguro da plataforma, como Keychain ou Keystore. Não grave tokens em arquivos, logs, backups não protegidos ou preferências comuns.

JWT como refresh token

É possível, mas um token opaco facilita revogação, rotação e redução de dados. Se usar JWT, ainda mantenha estado da sessão para detectar replay.

Rate limiting

Limite por sessão, usuário e IP. Muitas falhas podem indicar token expirado, aplicativo antigo ou ataque. Não bloqueie uma conta inteira por uma única origem sem considerar negação de serviço.

CSRF

Quando o refresh token está em cookie, valide Origin, use SameSite e considere token CSRF. CORS sozinho não impede envio cross-site.

Cache

Respostas de login e refresh devem incluir Cache-Control: no-store. Verifique proxies e CDNs para garantir que tokens não sejam armazenados.

Logs e observabilidade

Registre ID da sessão, usuário, resultado, reason code e request ID. Nunca registre token, cookie ou Authorization. Monitore replays, famílias revogadas, falhas e taxa de rotação.

Erros comuns

  • refresh token sem rotação;
  • armazenar token em texto puro no banco;
  • não detectar reutilização;
  • validade ilimitada;
  • cookie sem Secure ou HttpOnly;
  • não revogar no logout;
  • renovação não atômica;
  • registrar tokens;
  • usar refresh token nas APIs;
  • ignorar CSRF.

Testes

Teste token válido, expirado, revogado, rotacionado, reutilizado, concorrência, família revogada, logout, troca de senha, cookie ausente e Origin inválida.

Fluxo recomendado

  1. gere token opaco aleatório;
  2. armazene hash;
  3. envie em cookie seguro;
  4. rotacione atomicamente;
  5. detecte replay;
  6. revogue a família;
  7. use expiração absoluta;
  8. proteja refresh com CSRF;
  9. redija logs;
  10. permita revogação pelo usuário.

Combine refresh tokens com JWT no Node.js, Cookies Seguros, CSRF, Idempotency Keys e Secret Management.

Consulte o BCP de segurança OAuth e o guia de sessões da OWASP.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita