Em uma frase
Um JSON Web Token (JWT) é uma forma compacta e segura para URLs de representar "claims" (declarações) a serem transferidas entre duas partes, tipicamente usado para autenticação e autorização de uma maneira que pode ser verificada e confiável.
O problema que ele resolve
Nos tempos de outrora — digamos, no início dos anos 2000 — se você fizesse login em um site, o servidor criaria uma "sessão" para você. Era como um pequeno arquivo no servidor que dizia: "O usuário 123 está logado e colocou um frango de borracha no carrinho de compras". O servidor daria ao seu navegador um cookie minúsculo com um ID de sessão, tipo um ticket de chapelaria. Em cada requisição seguinte, seu navegador apresentava o ticket, o servidor o procurava, encontrava seu arquivo e se lembrava de quem você era.
Isso funcionava bem para um único servidor monolítico. Mas aí a web explodiu. Ganhamos microsserviços, single-page applications (SPAs) e aplicativos móveis, todos conversando com o mesmo backend. Agora, sua requisição de login pode ir para o Servidor A, mas sua próxima requisição para buscar seu perfil pode ir para o Servidor B. Como o Servidor B sabe sobre o arquivo de sessão no Servidor A?
Você poderia forçar um usuário a sempre falar com o mesmo servidor ("sticky sessions"), mas isso é um gargalo. Você poderia criar um banco de dados de sessão centralizado (como o Redis) que todos os servidores compartilham, mas isso é mais uma peça de infraestrutura para gerenciar e outro ponto de falha.
O problema central é a necessidade de guardar estado (statefulness). O servidor tem que se lembrar de você.
Os JWTs (pronuncia-se "jóts") viraram essa ideia de cabeça para baixo. E se o usuário pudesse carregar sua própria prova de identidade, como um passaporte? O próprio token conteria toda a informação que o servidor precisa: quem é o usuário, o que ele tem permissão para fazer e quando seu acesso expira. O servidor não precisa se lembrar de nada entre as requisições. Isso é autenticação stateless, e é a chave para construir sistemas distribuídos e escaláveis. O servidor só precisa verificar se o passaporte (o JWT) é válido e não foi falsificado.
Como funciona por debaixo dos panos
Um JWT não é um amontoado indecifrável de caracteres. É uma string muito específica e estruturada, feita de três partes separadas por pontos (.).
xxxxx.yyyyy.zzzzz
Vamos analisar cada parte.
O Header (A Etiqueta de "Tipo")
A primeira parte é o header. É um objeto JSON simples que contém metadados sobre o próprio token, principalmente o algoritmo de assinatura usado e o tipo do token.
{
"alg": "HS256",
"typ": "JWT"
}
alg: O algoritmo de assinatura.HS256significa que este token é assinado com HMAC-SHA256, um algoritmo simétrico (mais sobre isso em um instante). Outras opções comuns incluemRS256(usando um par de chaves pública/privada RSA).typ: O tipo do token. Para JWTs, é simplesmente "JWT".
Este JSON é então codificado em Base64Url para produzir a primeira parte do token. Base64 é um esquema de codificação, não é criptografia. Ele apenas transforma dados binários em uma string de texto que é segura para transmitir pela web. Pense nisso como escrever "ISTO É UM CARTÃO POSTAL" no verso de um cartão postal — qualquer um que o interceptar pode lê-lo.
O Payload (O Departamento de "Claims")
A segunda parte é o payload. Essa é a parte boa. É outro objeto JSON que contém as "claims", que são declarações sobre o usuário (o "subject") e outros dados úteis.
{
"sub": "10987-23456-98765",
"name": "Grace Hopper",
"admin": true,
"iat": 1516239022,
"exp": 1516242622
}
As claims vêm em três sabores:
- Claims Registradas: São um conjunto de claims predefinidas e recomendadas para fornecer interoperabilidade. Elas não são obrigatórias, mas são super úteis.
| Claim | Nome | Descrição |
|---|---|---|
iss |
Issuer (Emissor) | Quem emitiu o token (ex: https://api.meusitelegal.com). |
sub |
Subject (Assunto) | O usuário ou entidade sobre a qual o token se refere (ex: um ID de usuário). |
aud |
Audience (Público-alvo) | Para quem o token se destina (ex: https://api.meusitelegal.com). |
exp |
Expiration Time | Quando o token expira. Um timestamp numérico Unix (segundos desde a epoch). |
iat |
Issued At | Quando o token foi emitido. Também um timestamp Unix. |
- Claims Públicas: São claims personalizadas que você cria, mas para evitar colisões de nomes, elas devem ser definidas no registro IANA JSON Web Token Claims ou ser uma URI que contenha um namespace resistente a colisões.
- Claims Privadas: São as claims personalizadas mais comuns, criadas para compartilhar informações entre partes que concordam em usá-las (como
admin: trueem nosso exemplo). É aqui que você coloca os dados específicos da sua aplicação.
Assim como o header, todo o JSON do payload é codificado em Base64Url para formar a segunda parte do JWT. Novamente, isso não é criptografado. Nunca coloque informações sensíveis como senhas no payload.
A Assinatura (O Lacre Inviolável)
Esta é a parte que fornece a segurança. A assinatura é usada para verificar se o remetente do JWT é quem diz ser e para garantir que a mensagem não foi alterada no caminho.
Ela é criada pegando o header codificado, o payload codificado, uma chave secreta e passando-os pelo algoritmo especificado no header. Para o nosso exemplo com HS256, o processo se parece com isto:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
seu-segredo-de-256-bits
)
O pulo do gato: um segredo é usado, que apenas o servidor conhece. Quando o servidor recebe um JWT, ele executa novamente exatamente este mesmo cálculo com o header e o payload que recebeu. Se a assinatura que ele gera corresponder à assinatura no token, o servidor sabe duas coisas:
- Autenticidade: O token foi criado por alguém que conhece a chave secreta (ou seja, o próprio servidor).
- Integridade: O header e o payload não foram adulterados. Se um invasor mudasse
"admin": falsepara"admin": trueno payload, a assinatura não corresponderia mais.
Essa assinatura é o selo holográfico inviolável do nosso passaporte.
Histórias do mundo real
O Labirinto dos Microsserviços
Uma empresa de e-commerce em rápido crescimento, a "ScaleFast", decidiu dividir seu gigantesco backend monolítico em uma frota de microsserviços: um para usuários, um para pedidos, um para estoque, etc. O sistema antigo usava uma sessão do lado do servidor. Mas no novo mundo, como o OrderService sabe que uma requisição realmente veio de um usuário logado, sem ter que chamar o UserService a cada requisição? Isso seria lento e anularia o propósito do desacoplamento.
A solução foi o JWT. Quando um usuário faz login, o novo AuthService emite um JWT contendo o userId e suas roles (funções). O navegador do usuário então inclui este JWT no header Authorization de cada requisição para outros microsserviços. O OrderService e o InventoryService não precisam falar com o AuthService; eles só precisam conhecer a chave secreta compartilhada. Eles podem verificar independentemente a assinatura do JWT, confiar no userId dentro dele e processar a requisição.
Lição: JWTs são a lingua franca da autenticação em microsserviços, permitindo que os serviços sejam stateless e verificáveis de forma independente.
A Saga da Single-Page App
Um desenvolvedor chamado Alex estava construindo um dashboard bonitão em React. O frontend era uma Single-Page Application (SPA) servida de um host estático, e conversava com uma API de backend separada. Alex estava quebrando a cabeça com a autenticação old-school baseada em cookies, enfrentando um pesadelo de problemas com Cross-Origin Resource Sharing (CORS) porque o frontend e o backend estavam em domínios diferentes.
A equipe mudou para JWT. Agora, depois que um usuário faz login com seu nome de usuário e senha, a API retorna um JWT. O app React de Alex armazena esse token na memória e o anexa a cada chamada de API: Authorization: Bearer <o-jwt>. O backend da API é stateless; ele apenas verifica o bearer token em cada requisição recebida. Chega de dores de cabeça com cookies e CORS.
Lição: JWTs fornecem uma credencial limpa e portátil que funciona lindamente para desacoplar aplicações de frontend modernas de APIs de backend.
Erros e armadilhas comuns
- Colocar dados sensíveis no payload. Pare! O payload é codificado em Base64Url, que é trivialmente reversível. Ele não é criptografado. Qualquer um que colocar as mãos no token pode ler o payload. Trate-o como um cartão postal, não como uma carta selada.
- Esquecer de verificar a assinatura. Qual é o sentido dos recursos de segurança de um passaporte se o agente da fronteira não os verifica? Apenas decodificar o payload e confiar em seu conteúdo sem verificar a assinatura é uma vulnerabilidade de segurança catastrófica. Um invasor poderia forjar qualquer payload que quisesse.
- Confiar cegamente no header
alg. Uma famosa vulnerabilidade do passado envolvia invasores criando um token e alterando o header para{"alg": "none"}. Algumas bibliotecas mal configuradas viam "none" e "verificavam" a assinatura, bem, não fazendo nada, aceitando o token forjado como válido. Sempre faça seu servidor impor um algoritmo específico e esperado (ex:HS256). - Vazar sua chave secreta simétrica. Para algoritmos HMAC como o
HS256, a chave secreta são as chaves do reino. Se ela vazar, qualquer um pode forjar tokens para qualquer usuário com quaisquer permissões. Proteja-a como se fosse uma senha. - Não definir uma claim de expiração (
exp). Um token que vive para sempre é um risco enorme. Se ele for comprometido, um invasor pode usá-lo indefinidamente. Sempre defina um tempo de expiração razoavelmente curto e use um mecanismo de refresh token para sessões mais longas.
Por que isso deve estar no seu radar
Você deve pensar em "JWT" sempre que estiver lidando com autenticação ou autorização em um ambiente distribuído.
- Você está construindo uma API para uma Single-Page App (SPA) ou cliente móvel.
- Você está projetando uma arquitetura de microsserviços onde os serviços precisam confiar nas requisições uns dos outros.
- Você precisa de autenticação stateless que possa escalar horizontalmente sem um armazenamento de sessão compartilhado.
- Você está implementando fluxos de autorização de uso único, como links de redefinição de senha ou verificação de e-mail, onde um token autocontido e expirável é a solução perfeita.
É o padrão moderno para representar claims de forma segura, e entender suas forças — e fraquezas — é inegociável para o desenvolvedor de hoje.
Para ir mais fundo
- RFC 7519: A especificação oficial para JSON Web Token (JWT). A fonte da verdade.
- jwt.io: Um recurso fantástico com um depurador ao vivo e uma lista de bibliotecas para quase todas as linguagens.
- OWASP JWT Cheat Sheet: Um guia essencial para as melhores práticas de segurança e armadilhas do uso de JWTs (os conselhos são agnósticos de linguagem).
- MDN Web Docs: Authorization header: Aprenda sobre o esquema de autenticação
Bearercomumente usado para transmitir JWTs. - Wikipedia: JSON Web Token: Uma boa visão geral de alto nível do conceito e sua história.