Implementando Refresh Token em Node.js (Express)

Node.js

Implementando Refresh Token em Node.js (Express)

Luiz Duarte
Escrito por Luiz Duarte em 22/07/2025
Junte-se a mais de 34 mil devs

Entre para minha lista e receba conteúdos exclusivos e com prioridade

Um dos tutoriais mais lidos aqui do blog é aquele em que ensino a implementar JSON Web Tokens (JWT), um mecanismo de autenticação muito popular em backends. O JWT permite de forma simples, fornecer o acesso a rotas protegidas do seu backend a um usuário que se autenticou com sucesso, bastando ele informar o token recebido no login em cada requisição subsequente.

No entanto, um grande problema com JWTs é a sua expiração. Se você definir um prazo muito longo, um token sequestrado pode ser usado pelo sequestrador para ficar usando o backend em seu nome por um longo tempo. Já se você definir um prazo muito curto, isso vai exigir que o usuário se reautentique na sua aplicação com muita frequência. É o velho dilema de segurança x UX.

Alguns devs optam por guardar as credenciais do usuário autenticado no browser, para poder re-autenticar ele automaticamente quando o token recebido expira, aí substituem o token e a experiência toda fica transparente. No entanto isso cria uma brecha de segurança já que além de guardar essas credenciais localmente, teremos de trafegar elas mais vezes do que o necessário pela rede, o que nunca é bom.

Mas e se existisse uma outra opção, que proporcionasse essa mesma experiência fluida, mas sem colocar as credenciais do usuário em risco?

Essa opção existe e se chama Refresh Token.

Se preferir, você pode assistir ao vídeo abaixo, lá pela metade eu começo a falar do refresh, mas assistir todo dará um entendimento mais completo.

#1 – Fluxo do Refresh Token

O Refresh Token é uma técnica auxiliar que serve para que o cliente possa solicitar ao servidor um novo token de autenticação quando o antigo expirar, sem a necessidade de que o usuário se envolva neste processo, e também sem precisar das credenciais dele. Mas como isso é possível?

Antes de implementar o Refresh Token é importante primeiro entender o fluxo como um todo e é isso que vamos fazer agora.

O usuário começa sem autenticação, ele bate com suas credenciais na rota de login, certo? Ao invés de devolver apenas um token pra ele, devolveremos dois:

  • accessToken: token JWT comum, com expiração curta (30 minutos, por exemplo);
  • refreshToken: refresh token, com expiração longa (60 minutos, por exemplo);

No lado do cliente, armazena-se ambos tokens e usa-se o accessToken como token de autenticação normalmente, sem qualquer diferença. Quando, uma das requisições autenticadas bater no backend e for recusada porque o token usado expirou, o cliente deve enviar uma chamada com o refreshToken para uma outra rota, específica para atualização de token.

Esta segunda rota faz a validação do refreshToken recebido, seu cancelamento, e a emissão de dois novos tokens pra ele, o access e o refresh, para que ele volte a usar o sistema normalmente. Caso o refresh usado seja inválido, aí não tem o que fazer, o usuário terá de providenciar novo login.

Por questões de experiência, não é raro o refresh ser acionado antes da expiração total do token atual, para que não interromper o fluxo de uso da aplicação. Ainda sobre UX, algumas aplicações pedem para o usuário repetir a operação, enquanto que outras fazem o reenvio automaticamente.

Por questões de segurança, a cada novo refresh gerado, o antigo sempre é invalidado, o que permite que mesmo que alguém sequestre o refresh token, ele só conseguirá usá-lo até que um novo login seja feito pelo usuário de verdade.

E por fim, enquanto que o access token costuma usar o padrão JWT, não existe um padrão definido para o refresh token, sendo que geralmente ele é gerado como faríamos com uma API Key, sem qualquer “conteúdo”, apenas uma string impossível de adivinhar mesmo e única a cada geração. Dada essa natureza, é comum que tenhamos de manter registro de todos refresh tokens gerados e em uso no lado do servidor, geralmente em um Redis ou MongoDB, para não onerar o banco principal e não deixar as requests lentas.

Dito isso, vamos falar da implementação de refresh token.

Curso Beholder
Curso Beholder

#2 – Emitindo Refresh Tokens

No tutorial anterior sobre tokens de autenticação, ensinei como implementar o JWT em um backend Express. Continuaremos exatamente este mesmo projeto, que você pode implementar conforme ensinado ou então simplesmente pegar os fontes.

Para geração dos refresh tokens eu vou usar UUIDs, então precisa instalar no seu projeto o respectivo pacote.

E depois importar no topo do arquivo.

O refresh token possui um tempo de expiração diferente do access token, tendo de ser obrigatoriamente maior. Crie uma variável no .env.example e no .env pra essa informação, sendo que diferente do JWT_EXPIRES, a REFRESH_EXPIRES deve ser em milissegundos. Vou trabalhar com 5 minutos para o access e 10 minutos para o refresh, apenas para facilitar os testes.

Agora vamos criar uma função que gera e armazena refresh tokens para os usuários. Usarei um objeto em memória para armazenar os refresh tokens válidos de forma que possamos consultá-los rapidamente, mas como citei antes, soluções profissionais usariam uma solução NoSQL auxiliar.

Aqui usei o uuidv4 para gerar uma string única e difícil de adivinhar pra gente. Guardo ela no objeto de controle junto do id do usuário e faço uma varredura para garantir que não temos outro refresh token válido para o mesmo usuário (o que seria uma brecha de segurança). Por fim, defino um timer para limpar ela da memória, servindo como expiração do refresh token e retorno o mesmo.

Agora vamos mexer na rota de autenticação (login), para que ela gere e retorne um refresh token para o usuário junto do access token.

Abaixo um exemplo de teste no Postman.

No lado do cliente, ambos tokens devem ser armazenados e você pode testar que o access token funciona normalmente para chamar rotas privadas, como GET /clientes.

Curso Web23
Curso Web23

#3 – Usando Refresh Tokens

Agora que já temos como emitir os refresh tokens, vamos criar uma rota nova no nosso backend que servirá para, com um refresh token, emitir um novo par de tokens para o usuário. Ela é muito parecida com a rota de login, mas mais simples (com um pouco de criatividade tenho certeza que você consegue criar uma função auxiliar para diminuir o código repetido).

Agora no seu novo teste, primeiro você tem de fazer um login e pegar o refresh token, aí usa ele em um novo teste de POST /refresh para ver se funciona para gerar um novo par. Experimente testar várias vezes com o mesmo refresh token, para garantir que ele não está sendo aceito em mais de uma requisição.

Outra segurança comum é somente aceitar requisições vindas com uma Origin específica (do seu frontend, por exemplo). Opcionalmente você pode pedir que o access token antigo seja enviado junto dessa requisição de refresh, para que ele seja incluído na blacklist de access tokens.

E já que falamos em blacklist, podemos ajustar nosso logout para que ele expire também o refresh token associado ao usuário.

Aqui fiz uma lógica bem espartana e parecida com a que usamos na generateRefreshToken, mas usando o userId armazenado no token de acesso, que decodificamos dentro do verifyJWT e guardamos em res.locals. Assim garantimos que não apenas o token de acesso será invalidado, como o refresh token também.

Obviamente é possível criar muitas variações, mas a base do refresh token é essa aí e agora você pode implementá-la em seus projetos. Lembrando que a experiência no frontend varia bastante de acordo como a UX pretendida e tecnologias utilizadas. Caso use Axios, uma dica é usar os Interceptors para tratar os erros de autenticação e chamadas de refresh.

Até a próxima!

Curso Node.js e MongoDB

TAGS:

Olá, tudo bem?

O que você achou deste conteúdo? Conte nos comentários.

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *