Autenticação JSON Web Token (JWT) em Node.js

Node.js

Autenticação JSON Web Token (JWT) em Node.js

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

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

Faz algum tempo que ensino aqui no blog a como fazer APIs em Node.js, uma vez que este é o cenário mais comum de uso com a plataforma.

Já ensinei como o HTTP funciona e a fazer APIs com MongoDB, MySQL e SQL Server. Já ensinei a como estruturar suas APIs em formato de micro serviços e como criar um API Gateway.

No entanto, pouco falei aqui sobre segurança em APIs, então hoje vamos falar de JSON Web Tokens como uma forma de garantir a autenticação e autorização de APIs de maneira bem simples e segura, sendo o JWT um padrão para segurança de APIs RESTful atualmente.

Veremos neste tutorial:

  1. JSON Web Tokens
  2. Estruturando a API
  3. Adicionando o JWT
  4. Autenticação
  5. Logout
  6. Autorização

Se preferir, pode assistir ao vídeo abaixo ao invés de ler o artigo.

Vamos lá!

Curso FullStack

#1 – JSON Web Tokens

JWT, resumidamente, é uma string de caracteres que, caso cliente e servidor estejam sob HTTPS, permite que somente o servidor que conhece o ‘segredo’ possa validar o conteúdo do token e assim confirmar a autenticidade do cliente. O token não é “criptografado”, mas “assinado”, de forma que só com o secret essa assinatura possa ser comprovada, o que impede que atacantes “criem” tokens por conta própria.

Em termos práticos, quando um usuário se autentica no sistema ou web API (com usuário e senha), o servidor gera um token com data de expiração pra ele. Durante as requisições seguintes do cliente, o JWT é enviado no cabeçalho da requisição e, caso esteja válido, a API irá permitir acesso aos recursos solicitados, sem a necessidade de se autenticar novamente.

O diagrama abaixo mostra este fluxo, passo-a-passo:

O conteúdo do JWT é um payload JSON que pode conter a informação que você desejar, que lhe permita mais tarde conceder autorização a determinados recursos para determinados usuários. Minimamente ele terá o ID do usuário autenticado ou da sessão (se estiver trabalhando com este conceito), mas pode conter muito mais do que isso, conforme a sua necessidade, embora guardar conteúdos “sensíveis” no seu interior não é uma boa ideia, pois como disse antes, ele não é criptografado.

#2 – Estruturando a API

Antes de começarmos esta API Node.js usando JWT vale ressaltar que o foco aqui é mostrar o funcionamento do JWT e não o funcionamento de uma API real. Caso você já possua uma web API, pule esta seção. Caso contrário, use a API fake abaixo, que vamos mockar os dados retornados pela API e as credenciais de autenticação inicial para ir logo para a geração e posterior verificação dos tokens.

Salve o seguinte código JavaScript em um arquivo index.js na raiz do seu projeto:

Com esse JS em mãos, vamos instalar algumas dependências na nossa aplicação para fazê-la funcionar:

Rode a API com “node index” e ao acessar localhost:3000 deve listar apenas uma mensagem de OK e ao acessar o caminho /clientes no navegador, deve listar um array JSON como abaixo.

API fake funcionando

Isso mostra que a API está funcionando em ambas as rotas e sem segurança, afinal, não tivemos de nos autenticar para fazer os GETs que fizemos.

#3 – Adicionando o JWT

Agora, vamos instalar duas novas dependências para incrementar o nosso projeto, permitindo adicionar autenticação via JWT:

A saber:

  • jsonwebtoken: pacote que implementa o protocolo JSON Web Token;
  • dotenv-safe: pacote para gerenciar facilmente variáveis de ambiente, não é obrigatório para JWT, mas uma boa prática para configurações em geral;

Vamos começar usando o dotenv-safe, criando dois arquivos. Primeiro, o arquivo .env.example, com o template de variáveis de ambiente que vamos precisar:

E depois, o arquivo .env, com os valores à sua escolha:

Este JWT_SECRET será utilizado pela biblioteca jsonwebtoken para assinar o token de modo que somente o servidor consiga validá-lo, então é de bom tom que seja um segredo forte, o que coloquei acima é apenas para exemplo. Já o JWT_EXPIRES é a validade do seu token, em segundos, sendo que defini uma validade bem curta para facilitar os testes.

Para que esse arquivo de variáveis de ambiente seja carregado assim que a aplicação iniciar, adicione a seguinte linha logo no início do arquivo index.js da sua API, aproveitando para inserir também as linhas dos novos pacotes que vamos trabalhar:

Isso deixa nossa API minimamente preparada para de fato lidar com a autenticação e autorização.

#4 – Autenticação

Caso você não saiba a diferença, autenticação é você provar que você é você mesmo. Já autorização é você provar que possui permissão para fazer ou ver o que você está tentando.

Antes de gerar o JWT é necessário que o usuário passe por uma autenticação tradicional, geralmente com usuário e senha. Essa informação fornecida é validada junto a uma base de dados e somente caso ela esteja ok é que geramos o JWT para ele.

Assim, vamos criar uma nova rota /login que vai receber um usuário e senha hipotético e, caso esteja ok, retornará um JWT para o cliente:

Aqui temos o seguinte cenário: o cliente posta na URL /login um user e um password, que simulo uma ida ao banco meramente verificando se user é igual a luiz e se password é igual a 123. Estando ok, o banco me retornaria o ID deste usuário, que simulei com uma constante. Poderia trazer outras informações também, como perfil de acesso, algo bem comum neste tipo de token.

Além do payload, é passado o JWT_SECRET, que está armazenado em uma variável de ambiente como citado antes. Por fim, adicionei uma expiração de 5 minutos para este token (com JWT_EXPIRES), o que quer dizer que o usuário autenticado poderá fazer suas requisições por 5 minutos antes do sistema ou Web API pedir que ele se autentique novamente.

Caso o user e password não coincidam, será devolvido um erro 401 ao usuário (Unauthorized, como ensinado aqui).

Mas será que está funcionando?

Para testar, eu costumo usar o Postman, que ensino no vídeo abaixo.

O teste é bem simples, suba novamente o backend, depois crie uma requisição POST no Postman, apontada para http://localhost:3000/login e no corpo dela informe um JSON com user e password. Teste tanto com credenciais válidas, e terá um JSON com o token no retorno, quanto com credenciais inválidas, recebendo um 401.

Esse token gerado deve ser armazenado pelo usuário pois em requisições subsequentes, a rotas privadas, ele deve informá-lo no cabeçalho Authorization, geralmente usando o formato Bearer xxxx, onde xxxx é o seu token, veja abaixo um exemplo.

#5 – Logout

Agora que aprendemos como fazer o login, temos de aprender também como fazer o logout, isto é, o processo de invalidar um token previamente gerado para que ele não possa mais ser usado porque o usuário deseja encerrar sua sessão. Para isso, precisamos criar primeiro um mecanismo para guardar os tokens inválidos, sendo que não é comum usar o banco de dados pois são objetos temporários (depois de expirado pode excluir o token). Neste exemplo eu usarei um objeto em memória, mas poderia ser o Redis ou ainda uma capped collection no MongoDB.

No index.js, adicione o seguinte código:

Quando a rota de logout for chamada, eu pego o token no cabeçalho, removo o “Bearer ” no início, guardo o token na minha blacklist como true e crio um timer para fazer a limpeza dele em x tempo, onde x é o prazo de validade dele (em segundos) x1000, já que o setTimeout trabalha com ms. Por fim, devolvo um sucesso sem token pra ele. Mais tarde, durante a autorização, vamos cruzar também os dados dessa blacklist para ver se um token é válido ou não.

Faça um teste preliminar do logout, só pra ver se a rota está devolvendo o sucesso, pois o teste final só poderemos fazer logo mais, quando tivermos implementado a autorização na aplicação.

Livro Node.js
Livro Node.js

#6 – Autorização

Uma vez autenticado, ou seja, com um token em mãos, cada requisição subsequente deve incluir essa credencial no cabeçalho. Como a verificação desse token é algo muito recorrente, diversas rotas do backend vão precisar, vamos criar um middleware de verificação em nosso index.js, com o intuito de, dada uma requisição que está chegando, a gente verifica se ela possui um JWT válido.

Um middleware nada mais é do que uma função que espera req, res e next, como uma rota comum do Express.

Aqui eu obtive o token a partir do cabeçalho authorization, que se não existir já gera um erro logo de primeira (403, Forbidden). Caso exista, depois eu removo o “Bearer ” que é comum ficar no início desse tipo de cabeçalho, mas que não faz parte do token em si.

Aí verificamos se esse token está em nossa blacklist. Se ele estiver, retornamos erro, caso contrário verificamos a autenticidade desse token usando a função verify, usando a variável de ambiente com o JWT_SECRET. Caso ele não consiga verificar o token, outro erro.

Em seguida guardamos o token decodificado em res.locals, o que permite que a gente consiga pegar as informações dele mais tarde, dentro do código das rotas privadas. Para que o fluxo siga seu caminho, agora é hora de chamarmos a função next que passa para o próximo estágio de execução das funções no pipeline de middlewares do Express.

Ok, entendi que esta função atuará como um middleware, mas como usaremos a mesma?

Basta inserirmos sua referência nas rotas privadas como a GET /clientes que já existia em nossa API:

Assim, antes de responder os GETs de clientes, a API vai criar essa camada intermediária de autorização baseada em JWT, que obviamente vai bloquear requisições que não estejam e autorizadas, conforme as suas regras para tal.

O resultado, tentando chamar a rota /clientes sem estar autenticado é esse:

JWT não informado

Note que eu não disse para colocar esse middleware de segurança na chamada GET / pois vamos deixar ela pública, sempre acessível mesmo a usuários anônimos.

Mas voltando à nossa rota de clientes, para que seja possível acessá-la o client da API deve primeiro obter um token se autenticando com um usuário válido na rota POST de login. Aí você pega o token e usa ele no cabeçalho Authorization como já mostrado antes.

Na aplicação que for consumir a sua web API, deverá ser coletado esse token gerado e todas as requisições aos endpoints protegidos devem ser feitas passando o mesmo no header da requisição. Como este token está programado para expirar 5 minutos após a sua criação, as requisições GET /clientes podem ser feitas usando o mesmo durante este tempo, sem novo login. Mas assim que ele expirar, receberemos como retorno um erro.

Um último ajuste é incluir este middleware na rota de logout também, para que somente usuários devidamente autenticados consigam chamá-la.

E um último teste válido é o de gerar o token (login), invalidar o token (logout) e tentar usá-lo para GET /clientes. O esperado é que não funcione, pois ao invalidá-lo com o logout, ele entrará para a blacklist.

Bacana, não?!

Abordo uma maneira ainda mais segura de ter seu JWT neste artigo, caso esteja trabalhando com microservices e compartilhando token entre eles, mas não queira compartilhar secrets.

Se quiser conhecer outras formas de deixar suas Web APIs seguras, lei este artigo aqui.

E, para mais uma dica de segurança com Node.js, assista ao vídeo abaixo:

Um abraço e até mais!

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 *

4 Replies to “Autenticação JSON Web Token (JWT) em Node.js”

Thiago Peluque

Sei que é um post de 3 anos atrás porém tentei seguir e quando ele vai validar o Token, ele apresenta um erro

(node:40877) UnhandledPromiseRejectionWarning: #
(node:40877) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)

Já tentei de todas as formas validar isso porém sem sucesso. Ele apresenta isso bem no next()

Alguém tem idéia do que seria??

Luiz Duarte

Esse erro indica que uma função assíncrona no seu projeto disparou um erro não tratado. Experimente usar try/catch para capturar os erros ou pelo menos use um console.log para tentar descobrir em que parte da chamada ele deu o erro.

Você citou que seria no next, então dá uma olhada em qual seria a próxima função de middleware que foi chamada pois é nela o problema. Outra dica é dar uma olhada nos fontes da lição no GitHub, para ver se não deixou escapar nada, formulário ao final do post.

Zoltan Caputo

Excelente professor! Vários tutoriais sensacionais. Gostaria de ter conhecido antes de ter feito outros bons cursos. Vale demais iniciante começar com Luiztools…

Luiz Duarte

Fico feliz que tenha gostado dos conteúdos Zoltan!