Voltar para Artigos
seguranca7 min de leitura

Autenticação Invisível: A Arquitetura de Refresh Tokens

Evite que seu usuário seja deslogado a cada 15 minutos sem comprometer a segurança da aplicação. Aprenda a implementar o fluxo de Refresh Tokens e JWTs de curta duração.

12 de agosto de 2026

O JSON Web Token (JWT) tem um problema inerente de arquitetura (chamado Stateless): depois que você emite um JWT dizendo 'Esse é o Joãozinho', você não pode cancelar ou anular esse token até que ele expire por conta própria. Se um hacker roubar o JWT do Joãozinho que tem validade de 1 ano, ele terá acesso total à conta por 365 dias.

O Trade-off de Segurança

Para resolver o problema do roubo, a regra de ouro em segurança é gerar JWTs que expiram extremamente rápido (ex: 15 minutos). Mas, se fizermos isso, o usuário será deslogado da nossa plataforma de 15 em 15 minutos, o que destruiria a experiência (UX).

A Solução: Refresh Tokens

A arquitetura de Refresh Token separa o papel de Autenticação em duas chaves distintas:

  1. O Token Principal (Access Token): É um JWT comum. Dura apenas 15 minutos. Usado em todas as chamadas de API (no header Authorization: Bearer).
  2. O Refresh Token: É um código opaco (geralmente um UUID salvo no Banco de Dados). Dura 30 dias. É devolvido na hora do Login junto com o Access Token e, muitas vezes, é guardado de forma segura no Frontend (via HttpOnly Cookie).

O Fluxo Perfeito

O usuário navega normalmente com o seu JWT de 15 minutos. No minuto 16, ele clica no botão 'Meu Perfil'. O seu Backend recusa a requisição e devolve 401 Unauthorized (Token Expired).

O seu Frontend (usando Axios Interceptors) percebe o erro 401. Sem o usuário perceber (invisível na tela), o Frontend chama a rota /refresh-token enviando o código opaco de 30 dias que ele tinha guardado.

src/modules/users/services/RefreshTokenService.ts
export class RefreshTokenService {
  public async execute(token: string) {
    // 1. Busca no banco de dados se esse Refresh Token existe e não expirou
    const userToken = await userTokensRepository.findByToken(token);
    
    if (!userToken) throw new AppError('Refresh Token não encontrado', 401);
    
    // 2. Se o usuário deletou a própria conta ou o Admin baniu o usuário, 
    // a gente deleta o token do banco e nega a renovação!
    
    // 3. Gera um NOVO JWT com validade de 15 minutos
    const newToken = sign({}, process.env.JWT_SECRET, {
      subject: userToken.user_id,
      expiresIn: '15m'
    });
    
    // 4. (Opcional) Rotaciona o Refresh Token antigo apagando-o e gerando outro para mais 30 dias
    
    return { token: newToken };
  }
}

O Frontend recebe o novo JWT de 15 minutos, repete a chamada que tinha falhado (Meu Perfil) e a tela carrega normalmente. O usuário final não notou absolutamente nada, e a sua segurança arquitetural é de padrão bancário.

A maior vantagem disso: Se o celular do Joãozinho for roubado, o Admin entra no banco de dados e simplesmente APAGA o Refresh Token dele. Nos próximos 15 minutos (quando o JWT atual expirar), o Axios vai tentar renovar o token e o banco vai rejeitar. A sessão no celular roubado é encerrada permanentemente.