kb.erickguedes.com
JSON: Formato e Manipulação

JWT e Boas Práticas JSON

Aula 4 de 4

JWT — JSON Web Token

JWT é um padrão aberto (RFC 7519) para transmissão segura de informações entre partes como um objeto JSON.

Estrutura do JWT

Um JWT é composto por três partes codificadas em Base64URL separadas por pontos:

HEADER.PAYLOAD.SIGNATURE
// HEADER
{
  "alg": "HS256",
  "typ": "JWT"
}

// PAYLOAD (claims registradas)
{
  "sub": "1234567890",
  "name": "João Silva",
  "iat": 1516239022,
  "exp": 1516242622,
  "iss": "https://auth.exemplo.com",
  "aud": ["https://api.exemplo.com"]
}

// SIGNATURE (HMAC-SHA256)
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret_key
)

Geração e Validação

Node.js com jsonwebtoken

const jwt = require('jsonwebtoken');

const SECRET = process.env.JWT_SECRET || 'minha-chave-secreta';

// Gerar token
const token = jwt.sign(
  {
    sub: 'user-123',
    name: 'Maria Costa',
    role: 'admin'
  },
  SECRET,
  {
    expiresIn: '1h',
    issuer: 'https://auth.exemplo.com',
    audience: 'https://api.exemplo.com'
  }
);
console.log('Token:', token);

// Validar e decodificar
try {
  const decoded = jwt.verify(token, SECRET, {
    issuer: 'https://auth.exemplo.com',
    audience: 'https://api.exemplo.com'
  });
  console.log('Válido!', decoded);
} catch (err) {
  console.error('Inválido:', err.message);
}

Python com PyJWT

import jwt
from datetime import datetime, timedelta

SECRET = "minha-chave-secreta"

# Gerar token
payload = {
    "sub": "user-123",
    "name": "Maria Costa",
    "role": "admin",
    "iat": datetime.utcnow(),
    "exp": datetime.utcnow() + timedelta(hours=1),
    "iss": "https://auth.exemplo.com",
    "aud": "https://api.exemplo.com"
}
token = jwt.encode(payload, SECRET, algorithm="HS256")
print(f"Token: {token}")

# Validar
try:
    decoded = jwt.decode(
        token,
        SECRET,
        algorithms=["HS256"],
        audience="https://api.exemplo.com",
        issuer="https://auth.exemplo.com"
    )
    print(f"Válido! Usuário: {decoded['name']}, Role: {decoded['role']}")
except jwt.ExpiredSignatureError:
    print("Token expirado")
except jwt.InvalidAudienceError:
    print("Audience inválida")
except jwt.InvalidTokenError as e:
    print(f"Token inválido: {e}")

Segurança: Vulnerabilidades Comuns

Ataque alg=none

# VULNERÁVEL: aceitar algoritmo none
token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiJ9."

# SEGURO: forçar lista de algoritmos
try:
    decoded = jwt.decode(token, SECRET, algorithms=["HS256"])
except:
    print("Token inválido: algoritmo não permitido")

Refresh Tokens

const jwt = require('jsonwebtoken');

const ACCESS_SECRET = process.env.ACCESS_SECRET || 'access-secret';
const REFRESH_SECRET = process.env.REFRESH_SECRET || 'refresh-secret';

function generateTokens(userId) {
  // Access token: curta duração
  const accessToken = jwt.sign(
    { sub: userId, type: 'access' },
    ACCESS_SECRET,
    { expiresIn: '15m' }
  );

  // Refresh token: longa duração
  const refreshToken = jwt.sign(
    { sub: userId, type: 'refresh' },
    REFRESH_SECRET,
    { expiresIn: '7d' }
  );

  return { accessToken, refreshToken };
}

function refreshAccessToken(refreshToken) {
  try {
    const decoded = jwt.verify(refreshToken, REFRESH_SECRET);
    if (decoded.type !== 'refresh') throw new Error('Tipo inválido');

    // Em produção: verificar se refresh token não foi revogado (blacklist/DB)

    return jwt.sign(
      { sub: decoded.sub, type: 'access' },
      ACCESS_SECRET,
      { expiresIn: '15m' }
    );
  } catch (err) {
    throw new Error('Refresh token inválido ou expirado');
  }
}

JSON vs Protobuf: Performance

Protocol Buffers (protobuf) é uma alternativa binária ao JSON para alta performance.

# Comparação de tamanho
echo "JSON: dados.json"
python -c "
import json, sys
dados = {'usuarios': [{'id': i, 'nome': f'Usuario{i}', 'email': f'user{i}@exemplo.com'} for i in range(1000)]}
with open('dados.json', 'w') as f: json.dump(dados, f)
print(f'{sys.getsizeof(json.dumps(dados))} bytes em memória')
"
# Teste de performance JSON vs Protobuf
python -c "
import json, time, sys

dados = {'usuarios': [{'id': i, 'nome': f'User{i}', 'email': f'user{i}@test.com'} for i in range(10000)]}

# Serialização JSON
start = time.time()
for _ in range(100):
    s = json.dumps(dados)
json_time = time.time() - start

# Desserialização JSON
start = time.time()
for _ in range(100):
    json.loads(s)
json_load = time.time() - start

print(f'JSON serialize: {json_time:.2f}s, deserialize: {json_load:.2f}s')
print(f'Tamanho: {len(s)} bytes')
"

Lab: Implementação JWT Completa

# 1. Gerar chave secreta
SECRET=$(python -c "import secrets; print(secrets.token_hex(32))")
echo "SECRET=$SECRET"

# 2. Gerar JWT com Python
cat << 'EOF' > jwt-gen.py
import jwt
import json
from datetime import datetime, timedelta

SECRET = "$SECRET"

payload = {
    "sub": "user-001",
    "name": "Admin Sistema",
    "role": "admin",
    "permissions": ["read:users", "write:users", "delete:users"],
    "iat": datetime.utcnow(),
    "exp": datetime.utcnow() + timedelta(minutes=30),
    "iss": "https://auth.kb.exemplo"
}

token = jwt.encode(payload, SECRET, algorithm="HS256")
print(f"TOKEN: {token}")

# Decodificar sem validar (apenas para debug)
header = jwt.get_unverified_header(token)
decoded = jwt.decode(token, options={"verify_signature": False})
print(f"\nHEADER: {json.dumps(header, indent=2)}")
print(f"PAYLOAD: {json.dumps(decoded, indent=2, default=str)}")
EOF

python jwt-gen.py

# 3. Pipeline: validar JWT em API
cat << 'EOF' > jwt-validate.py
import jwt
import sys

SECRET = "$SECRET"

def validate_token(token):
    try:
        decoded = jwt.decode(
            token, SECRET,
            algorithms=["HS256"],
            issuer="https://auth.kb.exemplo"
        )
        return {"valid": True, "user": decoded.get("name"), "role": decoded.get("role")}
    except jwt.ExpiredSignatureError:
        return {"valid": False, "error": "Token expirado"}
    except jwt.InvalidIssuerError:
        return {"valid": False, "error": "Issuer inválido"}
    except jwt.InvalidTokenError as e:
        return {"valid": False, "error": str(e)}

# Simular requisição
token = sys.argv[1] if len(sys.argv) > 1 else ""
result = validate_token(token)
print(json.dumps(result, indent=2))
EOF

python jwt-validate.py "SEU_TOKEN_AQUI"

JWT é o padrão de autenticação stateless mais adotado na web — mas a segurança depende de implementação correta: algoritmo forçado, expiration, e secrets fortes.