Entendendo Tokens JWT: Um Guia Completo
· 12 min de leitura
Índice
- O Que São JSON Web Tokens (JWT)?
- Estrutura e Anatomia Detalhada do JWT
- Criando e Utilizando JWTs na Prática
- Fluxo de Autenticação JWT Explicado
- Melhores Práticas de Segurança para Implementação de JWT
- JWT vs. Autenticação Baseada em Sessão
- Vantagens do JWT em Aplicações do Mundo Real
- Armadilhas Comuns do JWT e Como Evitá-las
- Ferramentas e Bibliotecas para Melhorar o Manuseio de JWT
- Testando e Depurando Implementações de JWT
- Perguntas Frequentes
- Artigos Relacionados
O Que São JSON Web Tokens (JWT)?
JSON Web Tokens (JWT) tornaram-se o padrão de fato para transmitir informações com segurança entre partes em aplicações web modernas. Definidos pela RFC 7519, os JWTs fornecem um método compacto e seguro para URL para representar reivindicações a serem transferidas entre duas partes.
Ao contrário da autenticação tradicional baseada em sessão, onde o servidor mantém o estado, os JWTs são autocontidos. Isso significa que o próprio token carrega todas as informações necessárias para verificar a identidade e permissões de um usuário. Essa natureza sem estado torna os JWTs particularmente valiosos em sistemas distribuídos, arquiteturas de microsserviços e aplicações móveis.
Os JWTs servem a dois propósitos principais em aplicações modernas:
- Autorização: Uma vez que um usuário faz login, cada solicitação subsequente inclui o JWT, permitindo que o usuário acesse rotas, serviços e recursos permitidos com esse token. Implementações de Single Sign-On (SSO) dependem fortemente de JWTs devido à sua pequena sobrecarga e capacidades entre domínios.
- Troca de Informações: JWTs fornecem uma maneira segura de transmitir informações entre partes. Como os JWTs podem ser assinados usando pares de chaves públicas/privadas, você pode verificar que os remetentes são quem afirmam ser e que o conteúdo não foi adulterado.
A beleza dos JWTs reside em sua simplicidade e versatilidade. Eles funcionam perfeitamente em diferentes linguagens de programação e plataformas, tornando-os ideais para ambientes heterogêneos onde seu frontend pode estar em React, seu backend em Node.js e seu aplicativo móvel em Swift ou Kotlin.
Dica profissional: Embora os JWTs sejam incrivelmente úteis, eles não são uma solução mágica para todos os cenários de autenticação. Entender quando usar JWTs versus sessões tradicionais é crucial para construir aplicações seguras e escaláveis.
Estrutura e Anatomia Detalhada do JWT
Um JWT consiste em três partes distintas separadas por pontos (.), formando uma estrutura que se parece com isto: xxxxx.yyyyy.zzzzz. Cada seção serve a um propósito específico e juntas criam um pacote de informações à prova de adulteração.
O Cabeçalho
O cabeçalho normalmente consiste em duas partes: o tipo de token (JWT) e o algoritmo de assinatura sendo usado, como HMAC SHA256 ou RSA. Essa informação diz à parte receptora como validar a assinatura do token.
{
"alg": "HS256",
"typ": "JWT"
}
O cabeçalho é então codificado em Base64Url para formar a primeira parte do JWT. Algoritmos comuns que você encontrará incluem:
- HS256 (HMAC com SHA-256): Algoritmo simétrico usando um segredo compartilhado
- RS256 (Assinatura RSA com SHA-256): Algoritmo assimétrico usando pares de chaves públicas/privadas
- ES256 (ECDSA com SHA-256): Algoritmo assimétrico usando criptografia de curva elíptica
A Carga Útil
A carga útil contém as reivindicações, que são declarações sobre uma entidade (normalmente o usuário) e metadados adicionais. As reivindicações são categorizadas em três tipos:
Reivindicações registradas: Estas são reivindicações predefinidas que não são obrigatórias, mas recomendadas para fornecer interoperabilidade. Elas incluem:
iss(emissor): Identifica quem emitiu o tokensub(assunto): Identifica o assunto do token (geralmente o ID do usuário)aud(audiência): Identifica os destinatários para os quais o JWT se destinaexp(tempo de expiração): Timestamp após o qual o JWT expiranbf(não antes): Timestamp antes do qual o JWT não deve ser aceitoiat(emitido em): Timestamp quando o JWT foi emitidojti(ID do JWT): Identificador único para o JWT
Reivindicações públicas: Estas são reivindicações personalizadas que você define para sua aplicação. Para evitar colisões, elas devem ser definidas no Registro IANA de JSON Web Token ou usar nomes resistentes a colisões (como URIs com namespace).
Reivindicações privadas: Reivindicações personalizadas criadas para compartilhar informações entre partes que concordam em usá-las. Estas não são reivindicações registradas nem públicas.
{
"sub": "1234567890",
"name": "John Doe",
"email": "[email protected]",
"role": "admin",
"iat": 1516239022,
"exp": 1516242622
}
A carga útil é então codificada em Base64Url para formar a segunda parte do JWT.
Dica rápida: Nunca armazene informações sensíveis como senhas ou números de cartão de crédito em cargas úteis JWT. Embora os JWTs sejam assinados, eles não são criptografados por padrão, o que significa que qualquer pessoa pode decodificar e ler a carga útil.
A Assinatura
A assinatura é criada pegando o cabeçalho codificado, a carga útil codificada, um segredo (para algoritmos HMAC) ou chave privada (para RSA/ECDSA), e assinando-os usando o algoritmo especificado no cabeçalho.
Por exemplo, se usar HMAC SHA256, a assinatura seria criada assim:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
A assinatura garante que o token não foi alterado. Se alguém mudar até mesmo um único caractere no cabeçalho ou carga útil, a verificação da assinatura falhará.
Exemplo Completo de JWT
Quando você junta todas as três partes, você obtém um JWT completo que se parece com isto:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Você pode decodificar e inspecionar qualquer JWT usando nossa Ferramenta de Decodificação JWT para ver seu cabeçalho, carga útil e verificar sua assinatura.
Criando e Utilizando JWTs na Prática
Criar JWTs é simples com as bibliotecas certas. Vamos explorar como gerar e usar JWTs em diferentes linguagens de programação e cenários.
Criando JWTs em Node.js
A biblioteca jsonwebtoken é a escolha mais popular para aplicações Node.js:
const jwt = require('jsonwebtoken');
// Criar um token
const payload = {
sub: user.id,
email: user.email,
role: user.role
};
const secret = process.env.JWT_SECRET;
const options = {
expiresIn: '1h',
issuer: 'myapp.com'
};
const token = jwt.sign(payload, secret, options);
// Verificar um token
try {
const decoded = jwt.verify(token, secret);
console.log(decoded);
} catch (error) {
console.error('Token inválido:', error.message);
}
Criando JWTs em Python
Desenvolvedores Python normalmente usam a biblioteca PyJWT:
import jwt
import datetime
# Criar um token
payload = {
'sub': user.id,
'email': user.email,
'role': user.role,
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1),
'iat': datetime.datetime.utcnow()
}
secret = os.environ.get('JWT_SECRET')
token = jwt.encode(payload, secret, algorithm='HS256')
# Verificar um token
try:
decoded = jwt.decode(token, secret, algorithms=['HS256'])
print(decoded)
except jwt.ExpiredSignatureError:
print('Token expirou')
except jwt.InvalidTokenError:
print('Token inválido')
Criando JWTs em Java
Para aplicações Java, a biblioteca java-jwt da Auth0 é amplamente usada:
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
// Criar um token
Algorithm algorithm = Algorithm.HMAC256(secret);
String token = JWT.create()
.withSubject(user.getId())
.withClaim("email", user.getEmail())
.withClaim("role", user.getRole())
.withExpiresAt(new Date(System.currentTimeMillis() + 3600000))
.withIssuer("myapp.com")
.sign(algorithm);
// Verificar um token
try {
DecodedJWT jwt = JWT.require(algorithm)
.withIssuer("myapp.com")
.build()
.verify(token);
} catch (Exception e) {
System.out.println("Token inválido: " + e.getMessage());
}
Melhores Práticas para Geração de Tokens
Ao criar JWTs, siga estas diretrizes para garantir segurança e confiabilidade:
- Use segredos fortes: Seu segredo JWT deve ter pelo menos 256 bits (32 caracteres) de dados aleatórios. Nunca codifique segredos diretamente no seu código-fonte.
- Defina tempos de expiração apropriados: Tokens de acesso devem ter vida curta (15 minutos a 1 hora), enquanto tokens de atualização podem durar mais (dias a semanas).
- Inclua apenas reivindicações necessárias: Mantenha sua carga útil enxuta para reduzir o tamanho do token e minimizar a exposição de informações.
- Use o algoritmo certo: Para a maioria das aplicações, HS256 é suficiente. Use RS256 quando precisar verificar tokens sem compartilhar segredos (como em microsserviços).
Dica profissional: Considere implementar um mecanismo de atualização de token usando tokens de atualização. Isso permite que você mantenha tokens de acesso de vida curta para segurança enquanto mantém uma boa experiência do usuário sem reautenticação frequente.
Fluxo de Autenticação JWT Explicado
Entender como os JWTs fluem através da sua aplicação é crucial para implementá-los corretamente. Vamos percorrer um fluxo de autenticação típico passo a passo.
Autenticação Inicial
- Usuário envia credenciais: O usuário envia seu nome de usuário e senha para o endpoint de autenticação (normalmente
POST /api/auth/login). - Servidor valida credenciais: O servidor verifica as credenciais no banco de dados, verificando se o hash da senha corresponde.
- Servidor gera JWT: Após validação bem-sucedida, o servidor cria um JWT contendo a identidade do usuário e reivindicações relevantes.
- Servidor retorna token: O JWT é enviado de volta ao cliente, normalmente no corpo da resposta. Algumas implementações também o definem como um cookie HTTP-only.
Solicitações Subsequentes
- Cliente inclui token: Para cada solicitação subsequente, o cliente inclui o JWT no cabeçalho Authorization:
Authorization: Bearer <token> - Servidor valida token: O servidor extrai o token, verifica sua assinatura e verifica sua expiração.
- Servidor processa solicitação: Se o token for válido, o servidor extrai as informações do usuário da carga útil e processa a solicitação de acordo.
- Servidor retorna resposta: Os dados solicitados ou resultado da operação são retornados ao cliente.
Fluxo de Atualização de Token
Quando o token de acesso expira, o fluxo de atualização entra em ação:
- Cliente detecta expiração: O cliente recebe uma resposta 401 Não Autorizado ou verifica a reivindicação
expdo token. - Cliente envia token de atualização: O cliente envia o token de atualização para um endpoint de atualização dedicado (
POST /api/auth/refresh). - Servidor valida token de atualização: O servidor verifica o token de atualização e verifica se foi revogado.
- Servidor emite novo token de acesso: Um novo token de acesso é gerado e retornado ao cliente.
- Cliente tenta novamente a solicitação original: O cliente usa o novo token de acesso para tentar novamente a solicitação que falhou.
Fluxo de Logout
Fazer logout com JWTs requer consideração especial, já que os tokens são sem estado:
- Cliente inicia logout: O usuário clica em logout, acionando uma solicitação para
POST /api/auth/logout. - Servidor invalida token de atualização: O servidor adiciona o token de atualização a uma lista de revogação ou o exclui do banco de dados.
- Cliente descarta tokens: O cliente remove tanto os tokens de acesso quanto de atualização do armazenamento.
- Cliente redireciona: O usuário é redirecionado para a página de login ou área pública.
| Tipo de Token | Vida Útil Típica | Local de Armazenamento | Propósito |
|---|---|---|---|
| Token de Acesso | 15 min - 1 hora | Memória ou sessionStorage | Autorizar solicitações de API |
| Token de Atualização | 7 dias - 30 dias | Cookie HTTP-only ou armazenamento seguro | Obter novos tokens de acesso |
| Token de ID | Mesmo que token de acesso | Memória | Informações de identidade do usuário (OpenID Connect) |
Dica rápida: Implemente atualização automática de token em sua aplicação cliente para lidar com a expiração de token de forma transparente. Isso evita que os usuários sejam desconectados inesperadamente