Entendendo Tokens JWT: Um Guia Completo

· 12 min de leitura

Índice

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:

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:

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:

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:

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

  1. 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).
  2. Servidor valida credenciais: O servidor verifica as credenciais no banco de dados, verificando se o hash da senha corresponde.
  3. Servidor gera JWT: Após validação bem-sucedida, o servidor cria um JWT contendo a identidade do usuário e reivindicações relevantes.
  4. 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

  1. Cliente inclui token: Para cada solicitação subsequente, o cliente inclui o JWT no cabeçalho Authorization: Authorization: Bearer <token>
  2. Servidor valida token: O servidor extrai o token, verifica sua assinatura e verifica sua expiração.
  3. 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.
  4. 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:

  1. Cliente detecta expiração: O cliente recebe uma resposta 401 Não Autorizado ou verifica a reivindicação exp do token.
  2. 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).
  3. Servidor valida token de atualização: O servidor verifica o token de atualização e verifica se foi revogado.
  4. Servidor emite novo token de acesso: Um novo token de acesso é gerado e retornado ao cliente.
  5. 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:

  1. Cliente inicia logout: O usuário clica em logout, acionando uma solicitação para POST /api/auth/logout.
  2. 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.
  3. Cliente descarta tokens: O cliente remove tanto os tokens de acesso quanto de atualização do armazenamento.
  4. 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

We use cookies for analytics. By continuing, you agree to our Privacy Policy.