Módulo JWT
O módulo JWT fornece funcionalidades completas para criação e validação de JSON Web Tokens (JWT), permitindo autenticação e autorização seguras em aplicações Phlow.
🚀 Funcionalidades
Características Principais
- ✅ Criação de tokens JWT: Geração de tokens com dados customizados
- ✅ Validação de tokens: Verificação automática de assinatura e expiração
- ✅ Secret configurável: Chave secreta definida por módulo
- ✅ Claims customizados: Suporte a dados arbitrários no payload
- ✅ Expiração automática: Configuração de TTL para tokens com validação rigorosa
- ✅ Algoritmo HS256: Padrão da indústria para assinatura
- ✅ Validação dupla: Biblioteca jsonwebtoken + validação manual de expiração
- ✅ Tratamento de erros: Respostas estruturadas para falhas
📋 Configuração
Configuração Básica
modules:
- name: "jwt_handler"
module: "jwt"
version: "0.0.1"
with:
secret: "minha-chave-secreta-super-segura"
expires_in: 3600 # 1 hora em segundos (opcional)
Configuração com Variáveis de Ambiente
# Secret via ambiente (mais seguro)
export JWT_SECRET="minha-chave-secreta-do-ambiente"
modules:
- name: "jwt_handler"
module: "jwt"
with:
secret: "{{ env.JWT_SECRET }}"
expires_in: 7200 # 2 horas
🔧 Parâmetros de Configuração
Configuração do Módulo (with)
secret
(string, obrigatório): Chave secreta para assinatura do JWTexpires_in
(integer, opcional): Tempo de expiração em segundos (padrão: 3600)
Entrada (input)
action
(string, obrigatório): Ação a executar ["create", "verify"]data
(object, opcional): Dados para incluir no token (apenas para "create")token
(string, opcional): Token para validação (apenas para "verify")
Saída (output)
Para ação "create":
token
(string): Token JWT geradoexpires_at
(string): Timestamp de expiração (ISO 8601)issued_at
(string): Timestamp de criação (ISO 8601)
Para ação "verify":
valid
(boolean): Se o token é válidodata
(object): Dados decodificados do token (se válido)error
(string): Mensagem de erro (se inválido)expired
(boolean): Se o token expirou
💻 Exemplos de Uso
Criação de Token
steps:
- name: "create_user_token"
use: "jwt_handler"
input:
action: "create"
data:
user_id: 123
email: "usuario@example.com"
roles: ["user", "admin"]
permissions: ["read", "write"]
Validação de Token
steps:
- name: "verify_token"
use: "jwt_handler"
input:
action: "verify"
token: "{{ $request.headers.authorization | replace('Bearer ', '') }}"
- name: "check_validation"
condition:
left: "{{ $verify_token.valid }}"
operator: "equals"
right: true
then:
return: "{{ $verify_token.data }}"
else:
return:
error: "Token inválido"
message: "{{ $verify_token.error }}"
Teste de Expiração de Token
name: jwt-expiration-test
version: 1.0.0
description: Demonstração de expiração automática de token JWT
modules:
- module: jwt
with:
secret: "minha-chave-secreta-super-segura"
- module: sleep
steps:
# Criar token com expiração de 1 segundo
- use: jwt
input:
action: create
data:
user_id: 12345
role: admin
expires_in: 1
# Aguardar 5 segundos (token expira durante este período)
- use: sleep
input:
seconds: 5
# Tentar verificar o token expirado
- use: jwt
input:
action: verify
token: !phs payload.token
# Validar que o token está expirado
- assert: !phs payload.valid
then:
return: "❌ Token ainda válido - Erro!"
else:
return: "✅ Token expirado corretamente - Sucesso!"
Resultado esperado:
{
"valid": false,
"expired": true,
"error": "Token has expired",
"data": null
}
🌐 Exemplo Completo - Sistema de Autenticação
name: "auth-system"
version: "1.0.0"
description: "Sistema de autenticação com JWT"
modules:
- name: "jwt_handler"
module: "jwt"
with:
secret: "{{ env.JWT_SECRET }}"
expires_in: 3600 # 1 hora
- name: "logger"
module: "log"
- name: "db"
module: "postgres"
with:
host: "localhost"
database: "auth_db"
user: "app_user"
password: "{{ env.DB_PASSWORD }}"
steps:
- name: "log_auth_attempt"
use: "logger"
input:
level: "info"
message: "Tentativa de autenticação para {{ $input.email }}"
- name: "validate_user"
use: "db"
input:
query: "SELECT id, email, password_hash, roles FROM users WHERE email = $1 AND active = true"
params: ["{{ $input.email }}"]
- name: "check_user_exists"
condition:
left: "{{ $validate_user.result.count }}"
operator: "greater_than"
right: 0
then:
# Usuário encontrado, verificar senha
name: "verify_password"
script: |
// Simular verificação de senha
let user = $validate_user.result.rows[0];
let passwordValid = $input.password === "senha123"; // Em produção, usar bcrypt
if (passwordValid) {
{
valid: true,
user: user
}
} else {
{
valid: false,
error: "Senha incorreta"
}
}
else:
return:
success: false
error: "Usuário não encontrado"
- name: "check_password"
condition:
left: "{{ $verify_password.valid }}"
operator: "equals"
right: true
then:
# Senha válida, criar token
use: "jwt_handler"
input:
action: "create"
data:
user_id: "{{ $verify_password.user.id }}"
email: "{{ $verify_password.user.email }}"
roles: "{{ $verify_password.user.roles }}"
auth_time: "{{ timestamp() }}"
else:
# Senha inválida
return:
success: false
error: "{{ $verify_password.error }}"
- name: "log_success"
use: "logger"
input:
level: "info"
message: "Login bem-sucedido para {{ $input.email }}"
- name: "return_token"
return:
success: true
token: "{{ $check_password.token }}"
expires_at: "{{ $check_password.expires_at }}"
user:
id: "{{ $verify_password.user.id }}"
email: "{{ $verify_password.user.email }}"
🔐 Middleware de Autenticação
name: "auth-middleware"
version: "1.0.0"
description: "Middleware para validação de JWT"
modules:
- name: "jwt_handler"
module: "jwt"
with:
secret: "{{ env.JWT_SECRET }}"
- name: "logger"
module: "log"
steps:
- name: "extract_token"
script: |
let authHeader = $input.headers.authorization;
if (!authHeader) {
{ error: "Token não fornecido" }
} else if (!authHeader.startsWith("Bearer ")) {
{ error: "Formato de token inválido" }
} else {
{ token: authHeader.replace("Bearer ", "") }
}
- name: "check_token_extraction"
condition:
left: "{{ $extract_token.error }}"
operator: "exists"
right: true
then:
return:
status_code: 401
body:
error: "Unauthorized"
message: "{{ $extract_token.error }}"
else:
# Token extraído com sucesso
use: "jwt_handler"
input:
action: "verify"
token: "{{ $extract_token.token }}"
- name: "validate_jwt"
condition:
left: "{{ $check_token_extraction.valid }}"
operator: "equals"
right: true
then:
# Token válido, continuar processamento
script: |
{
user: $check_token_extraction.data,
authenticated: true
}
else:
# Token inválido
condition:
left: "{{ $check_token_extraction.expired }}"
operator: "equals"
right: true
then:
return:
status_code: 401
body:
error: "Token Expired"
message: "Token expirou, faça login novamente"
else:
return:
status_code: 401
body:
error: "Invalid Token"
message: "{{ $check_token_extraction.error }}"
- name: "log_auth_success"
use: "logger"
input:
level: "debug"
message: "Usuário {{ $validate_jwt.user.email }} autenticado com sucesso"
- name: "return_user_context"
return:
user: "{{ $validate_jwt.user }}"
authenticated: true
🔍 Estrutura do Token JWT
Header
{
"alg": "HS256",
"typ": "JWT"
}
Payload (Claims)
{
"iat": 1640995200, // Issued At (timestamp)
"exp": 1640998800, // Expiration (timestamp)
"user_id": 123, // Dados customizados
"email": "user@example.com", // do parâmetro 'data'
"roles": ["user", "admin"]
}
🔧 Implementação Técnica
Validação Dupla de Expiração
O módulo implementa uma estratégia de validação dupla para garantir que tokens expirados sejam sempre detectados:
- Validação da biblioteca jsonwebtoken: Utiliza
validate_exp = true
- Validação manual adicional: Compara timestamp atual com
exp
claim
// Validação manual como backup
if current_timestamp > claims.exp {
return Ok(jwt_error_response("Token has expired", true));
}
Logging de Debug
O módulo fornece logging detalhado para debugging:
[DEBUG] Creating JWT token with data: {...}, expires_in: 1
[DEBUG] Token expiration time: 2025-01-01T10:00:01Z
[DEBUG] Verifying JWT token with value: eyJ0eXAi...
[DEBUG] Current timestamp: 1640998806
[DEBUG] Token claims - iat: 1640998800, exp: 1640998801, current: 1640998806
[WARN] Token manually detected as expired: 1640998806 > 1640998801
Gestão de Timestamps
- Criação:
iat
= timestamp atual,exp
= iat + expires_in - Validação: Compara timestamp atual com
exp
claim - Precisão: Utiliza chrono::Utc para timestamps UTC precisos
📊 Observabilidade
O módulo automaticamente gera spans do OpenTelemetry com os seguintes atributos:
Span Attributes
jwt.action
: "create" ou "verify"jwt.algorithm
: "HS256"jwt.valid
: true/false (para verify)jwt.expired
: true/false (para verify)jwt.user_id
: ID do usuário (se presente nos dados)jwt.expires_in
: Tempo de expiração em segundos
🛡️ Segurança
Boas Práticas
- Secret forte: Use chaves com pelo menos 256 bits
- Variáveis de ambiente: Nunca hardcode secrets
- TTL apropriado: Configure expiração adequada
- HTTPS obrigatório: Sempre use conexões seguras
- Rotação de chaves: Implemente rotação periódica
Exemplo de Secret Seguro
# Gerar secret seguro
export JWT_SECRET=$(openssl rand -base64 32)
🔧 Tratamento de Erros
Erros de Criação
{
"error": "Invalid data format",
"message": "Os dados devem ser um objeto válido"
}
Erros de Validação
{
"valid": false,
"error": "Token expired",
"expired": true,
"message": "O token expirou em 2024-01-01T10:00:00Z"
}
💡 Casos de Uso
- Autenticação de APIs: Validação de usuários em endpoints
- Single Sign-On (SSO): Tokens compartilhados entre serviços
- Autorização: Controle de acesso baseado em roles
- Sessões: Alternativa a cookies para SPAs
- Microserviços: Propagação de identidade entre serviços
🏷️ Tags
- jwt
- auth
- authentication
- authorization
- token
- security
Versão: 0.0.1
Autor: Philippe Assis <codephilippe@gmail.com>
Licença: MIT
Repositório: https://github.com/phlowdotdev/phlow