Quando você faz login em um aplicativo moderno de página única (como React ou Vue) ou em um aplicativo móvel, o servidor precisa de uma maneira de lembrar quem você é. Tradicionalmente, isso era feito armazenando um “ID de sessão” em um enorme banco de dados no servidor e colocando um cookie no seu navegador. Cada vez que você clicava em um botão, o servidor precisava procurar esse ID em seu banco de dados. Isso é chamado de autenticação com estado.
No entanto, na era dos microsserviços e do dimensionamento da nuvem, os bancos de dados tornaram-se um gargalo. Para resolver isso, os desenvolvedores adotaram a autenticação sem estado por meio de JSON Web Tokens (JWT). Com o JWT, o servidor não precisa lembrar quem você é — seu navegador informa ao servidor exatamente quem você é e usa criptografia para provar isso.
A anatomia de um JWT
Se você inspecionar o tráfego de rede após fazer login em um aplicativo moderno, provavelmente verá um cabeçalho “Autorização: Portador” seguido por uma sequência longa e de aparência aleatória de caracteres separados por dois pontos. Isso é um JWT.
Um JWT consiste exatamente em três partes: Header.Payload.Signature.
1. O cabeçalho
A primeira parte é um objeto JSON codificado em Base64URL que simplesmente descreve o token. Geralmente contém duas propriedades: o tipo de token (JWT) e o algoritmo de assinatura usado (como HMAC SHA256 ou RSA).
2. A carga útil (reivindicações)
A parte do meio também é um objeto JSON codificado em Base64URL. É aqui que residem os dados reais. Esses dados são chamados de “reivindicações”. Por exemplo, pode conter seu ID de usuário, sua função (por exemplo, "Administrador") e um carimbo de data/hora de expiração. Como essa carga está anexada a cada solicitação, o servidor sabe instantaneamente quem você é, sem consultar um banco de dados.
AVISO CRÍTICO: a carga útil é meramente codificada, não criptografada. Qualquer pessoa que intercepte um JWT pode facilmente decodificá-lo e ler a carga útil. Nunca armazene senhas, números de previdência social ou dados confidenciais dentro de uma carga JWT.
3. A assinatura
Se alguém puder ler e editar a carga útil, o que impede um usuário mal-intencionado de mudar sua função de “Usuário” para “Administrador”? A resposta é a assinatura.
Para criar a assinatura, o servidor pega o cabeçalho, a carga útil e uma chave secreta altamente segura (conhecida apenas pelo servidor) e os executa por meio de um algoritmo criptográfico (como SHA256). O hash resultante se torna a assinatura.
Quando o servidor recebe um token do cliente, ele recalcula a assinatura usando sua chave secreta. Se o usuário adulterou a carga útil (mesmo alterando uma única letra), a assinatura recalculada não corresponderá à assinatura do token e o servidor rejeitará instantaneamente a solicitação como fraudulenta.
Inspecione tokens com segurança
Precisa ler o payload de um JWT para depurar seu aplicativo? Use nosso decodificador JWT off-line para inspecionar as reivindicações instantaneamente, sem enviar seu token confidencial a um servidor remoto.
Abra o decodificador JWTPor que os microsserviços adoram JWTs
Imagine uma empresa como a Netflix. Eles têm um servidor de autenticação, um servidor de streaming de vídeo e um servidor de cobrança. Se usassem sessões tradicionais, cada servidor teria que se comunicar constantemente com um banco de dados central para verificar se um usuário está logado.
Com JWTs, o servidor de autenticação assina o token usando uma chave privada. O usuário então passa esse token diretamente para o servidor de vídeo. Como o servidor de vídeo possui a chave pública, ele pode verificar a assinatura de forma independente. O servidor de vídeo sabe exatamente quem é o usuário, sem nunca falar com o servidor de autenticação ou com um banco de dados. Isso permite que a infraestrutura seja dimensionada infinitamente sem gargalos.
O lado negro: invalidação de token
JWTs não são perfeitos. A sua maior força (ser apátrida) é também a sua maior fraqueza. Como o servidor não mantém um registro de tokens ativos, você não pode facilmente desconectar um usuário ou invalidar um token específico antes que ele expire.
Se um hacker roubar o JWT de um usuário, o hacker terá acesso total até que o carimbo de data/hora de expiração do token acabe. Para mitigar esse risco, os engenheiros de segurança usam um sistema de dois tokens:
- Tokens de acesso: JWTs de curta duração (por exemplo, 15 minutos) usados para solicitações de API.
- Tokens de atualização: tokens com estado de longa duração armazenados de forma segura, usados estritamente para solicitar novos tokens de acesso. Se uma conta for comprometida, o servidor revogará o Token de Atualização e o Token de Acesso do hacker morrerá naturalmente em 15 minutos.
Perguntas frequentes (FAQ)
Onde devo armazenar um JWT no frontend?
Armazenar JWTs em localStorage os torna vulneráveis a ataques Cross-Site Scripting (XSS). O local mais seguro para armazenar um JWT em um navegador da web é dentro de um cookie HttpOnly, que impede que o JavaScript o acesse.
O que acontece se a chave secreta do meu servidor vazar?
Catástrofe. Se um hacker obtiver sua chave secreta HMAC ou chave privada RSA, ele poderá gerar JWTs válidos com qualquer carga útil que desejar. Eles poderiam criar tokens com privilégios de "Super Admin" e seu servidor os aceitaria como válidos. Você deve girar suas chaves imediatamente.
Os JWTs são mais rápidos que os cookies de sessão?
Não necessariamente. Os JWTs são significativamente maiores em tamanho de arquivo do que um ID de sessão de 32 caracteres, o que significa que consomem mais largura de banda da rede em cada solicitação. Sua vantagem de velocidade vem inteiramente de ignorar pesquisas de banco de dados no back-end.