Pular para conteúdo

TOKEN - Gerenciamento de Tokens JWT

O que é este Node?

O TOKEN é o node responsável por gerenciar tokens JWT (JSON Web Tokens) no Lumina Flow Builder. Ele permite gerar, verificar e decodificar tokens JWT para autenticação e autorização.

Por que este Node existe?

Tokens JWT são essenciais para autenticação stateless em sistemas modernos. O TOKEN existe para:

  1. Autenticação Stateless: Criar tokens auto-contidos que não requerem armazenamento em servidor
  2. Segurança de APIs: Proteger endpoints de API com tokens assinados criptograficamente
  3. Autorização: Incluir claims e permissões diretamente no token
  4. Expiração Automática: Definir tempo de vida dos tokens para maior segurança
  5. Portabilidade: Usar tokens que funcionam em diferentes sistemas e linguagens

Como funciona internamente?

Quando o TOKEN é executado, o sistema:

  1. Identifica operação: Determina se deve gerar, verificar ou decodificar token
  2. Operação Generate:
  3. Recebe payload (dados a incluir no token)
  4. Assina com secret usando algoritmo HS256
  5. Define tempo de expiração
  6. Retorna token JWT completo
  7. Operação Verify:
  8. Recebe token e secret
  9. Verifica assinatura criptográfica
  10. Valida expiração
  11. Retorna sucesso ou falha
  12. Operação Decode:
  13. Extrai header e payload do token
  14. NÃO verifica assinatura (apenas leitura)
  15. Retorna dados decodificados

Código interno (security-executor.service.ts:150-168):

private async executeToken(parameters: any, context: any): Promise<any> {
  const { operation, payload, secret, token, expiresIn } = parameters;

  this.logger.log(`🎫 TOKEN - Operation: ${operation}`);

  switch (operation) {
    case 'generate':
      return this.generateJWT(payload, secret, expiresIn);

    case 'verify':
      return this.verifyJWT(token, secret);

    case 'decode':
      return this.decodeJWT(token);

    default:
      throw new Error(`Unsupported token operation: ${operation}`);
  }
}

Quando você DEVE usar este Node?

Use TOKEN sempre que precisar de autenticação baseada em tokens JWT:

Casos de uso

  1. API Authentication: "Preciso gerar tokens para autenticar requisições de API"
  2. Single Sign-On: "Preciso criar token que funcione em múltiplos sistemas"
  3. Sessões sem Estado: "Preciso autenticar sem armazenar sessões no servidor"
  4. Autorização Granular: "Preciso incluir roles e permissões no token"
  5. Integração de Terceiros: "Preciso validar tokens de serviços externos"

Quando NÃO usar TOKEN

  • Dados Sensíveis: Use ENCRYPT ao invés de TOKEN (JWT é apenas codificado, não criptografado)
  • Autenticação de Dois Fatores: Use 2FA ao invés de TOKEN
  • OAuth Social Login: Use OAUTH ao invés de TOKEN direto

Parâmetros Detalhados

operation (string, obrigatório)

O que é: Define qual operação será executada com o token JWT.

Valores possíveis: - generate: Gera novo token JWT - verify: Verifica validade e assinatura de token - decode: Decodifica token sem verificar assinatura

Flow completo para testar (Generate):

{
  "name": "Teste TOKEN - Generate",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "token_1",
      "type": "token",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Gerar Token",
        "parameters": {
          "operation": "generate",
          "payload": {
            "userId": "12345",
            "username": "jose.roberto",
            "role": "admin"
          },
          "secret": "meu-secret-super-seguro",
          "expiresIn": "1h"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Mostrar Token",
        "parameters": {
          "message": "Token gerado: {{token_1.token}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "token_1" },
    { "source": "token_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Gera um token JWT. Deve retornar token no formato eyJhbGc...

payload (object, obrigatório para generate)

O que é: Dados que serão incluídos no token JWT. Pode conter qualquer informação JSON.

Dados comuns: userId, username, email, role, permissions

Flow completo para testar:

{
  "name": "Teste TOKEN - Payload",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "User ID",
        "parameters": {
          "message": "Digite o user ID:",
          "variableName": "userId"
        }
      }
    },
    {
      "id": "input_2",
      "type": "input",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Username",
        "parameters": {
          "message": "Digite o username:",
          "variableName": "username"
        }
      }
    },
    {
      "id": "token_1",
      "type": "token",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Gerar Token",
        "parameters": {
          "operation": "generate",
          "payload": {
            "userId": "{{userId}}",
            "username": "{{username}}"
          },
          "secret": "meu-secret"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Sucesso",
        "parameters": {
          "message": "Token criado para {{username}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1100, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "input_2" },
    { "source": "input_2", "target": "token_1" },
    { "source": "token_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Digite userId e username. O token gerado conterá esses dados.

secret (string, obrigatório para generate e verify)

O que é: Chave secreta usada para assinar e verificar tokens JWT. DEVE ser mantida em segredo.

Flow completo para testar:

{
  "name": "Teste TOKEN - Secret",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "variable_1",
      "type": "variable",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Secret",
        "parameters": {
          "name": "jwtSecret",
          "value": "minha-chave-secreta-super-segura-123"
        }
      }
    },
    {
      "id": "token_1",
      "type": "token",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Gerar",
        "parameters": {
          "operation": "generate",
          "payload": { "user": "teste" },
          "secret": "{{jwtSecret}}"
        }
      }
    },
    {
      "id": "token_2",
      "type": "token",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Verificar",
        "parameters": {
          "operation": "verify",
          "token": "{{token_1.token}}",
          "secret": "{{jwtSecret}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Resultado",
        "parameters": {
          "message": "Token válido: {{token_2.valid}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1100, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "variable_1" },
    { "source": "variable_1", "target": "token_1" },
    { "source": "token_1", "target": "token_2" },
    { "source": "token_2", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Gera e verifica token com mesmo secret. Deve retornar valid: true.

token (string, obrigatório para verify e decode)

O que é: Token JWT a ser verificado ou decodificado.

Flow completo para testar:

{
  "name": "Teste TOKEN - Verify",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "token_1",
      "type": "token",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Gerar Token",
        "parameters": {
          "operation": "generate",
          "payload": { "userId": "123" },
          "secret": "meu-secret"
        }
      }
    },
    {
      "id": "token_2",
      "type": "token",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Verificar Token",
        "parameters": {
          "operation": "verify",
          "token": "{{token_1.token}}",
          "secret": "meu-secret"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Status",
        "parameters": {
          "message": "Válido: {{token_2.valid}}, User: {{token_2.payload.userId}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "token_1" },
    { "source": "token_1", "target": "token_2" },
    { "source": "token_2", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Gera e verifica token. Deve retornar valid: true e payload.

expiresIn (string, opcional)

O que é: Tempo de expiração do token.

Padrão: "1h"

Valores suportados: "1h", "24h", "7d", "30d", "1y"

Flow completo para testar:

{
  "name": "Teste TOKEN - ExpiresIn",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "token_1",
      "type": "token",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Token Curto",
        "parameters": {
          "operation": "generate",
          "payload": { "type": "temporary" },
          "secret": "secret",
          "expiresIn": "5m"
        }
      }
    },
    {
      "id": "token_2",
      "type": "token",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Token Longo",
        "parameters": {
          "operation": "generate",
          "payload": { "type": "permanent" },
          "secret": "secret",
          "expiresIn": "30d"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Expirações",
        "parameters": {
          "message": "Temp expira: {{token_1.expiresAt}}\nPerm expira: {{token_2.expiresAt}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "token_1" },
    { "source": "start_1", "target": "token_2" },
    { "source": "token_1", "target": "message_1" },
    { "source": "token_2", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Gera tokens com diferentes expirações. Deve mostrar datas diferentes.

Parâmetros

Campo Tipo Obrigatório Descrição
operation string Sim Operação: generate, verify, decode
payload object Condicional Dados do token (obrigatório para generate)
secret string Condicional Secret para assinar/verificar (obrigatório para generate/verify)
token string Condicional Token JWT (obrigatório para verify/decode)
expiresIn string Não Tempo de expiração (padrão: 1h)

Exemplo 1: Sistema Completo de Autenticação JWT

Objetivo: Demonstrar geração, verificação e uso de tokens JWT

JSON para Importar

{
  "name": "Sistema JWT Completo",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Login",
        "parameters": {
          "message": "Digite seu username:",
          "variableName": "username"
        }
      }
    },
    {
      "id": "token_1",
      "type": "token",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Gerar Token",
        "parameters": {
          "operation": "generate",
          "payload": {
            "username": "{{username}}",
            "role": "user",
            "permissions": ["read", "write"]
          },
          "secret": "jwt-secret-key-123",
          "expiresIn": "24h"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Token Gerado",
        "parameters": {
          "message": "Token JWT criado! Expira em: {{token_1.expiresAt}}"
        }
      }
    },
    {
      "id": "input_2",
      "type": "input",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Fazer Requisição",
        "parameters": {
          "message": "Digite 'api' para fazer requisição:",
          "variableName": "action"
        }
      }
    },
    {
      "id": "token_2",
      "type": "token",
      "position": { "x": 1100, "y": 100 },
      "data": {
        "label": "Validar Token",
        "parameters": {
          "operation": "verify",
          "token": "{{token_1.token}}",
          "secret": "jwt-secret-key-123"
        }
      }
    },
    {
      "id": "condition_1",
      "type": "condition",
      "position": { "x": 1300, "y": 100 },
      "data": {
        "label": "Token Válido?",
        "parameters": {
          "condition": "{{token_2.valid}} == true"
        }
      }
    },
    {
      "id": "message_2",
      "type": "message",
      "position": { "x": 1500, "y": 50 },
      "data": {
        "label": "Acesso Permitido",
        "parameters": {
          "message": "Requisição autorizada para {{token_2.payload.username}}"
        }
      }
    },
    {
      "id": "message_3",
      "type": "message",
      "position": { "x": 1500, "y": 150 },
      "data": {
        "label": "Acesso Negado",
        "parameters": {
          "message": "Token inválido ou expirado!"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "token_1" },
    { "source": "token_1", "target": "message_1" },
    { "source": "message_1", "target": "input_2" },
    { "source": "input_2", "target": "token_2" },
    { "source": "token_2", "target": "condition_1" },
    { "source": "condition_1", "target": "message_2", "label": "true" },
    { "source": "condition_1", "target": "message_3", "label": "false" },
    { "source": "message_2", "target": "end_1" },
    { "source": "message_3", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: Digite seu username:
Usuário: jose.roberto
Sistema: Token JWT criado! Expira em: 2025-01-16T10:30:00.000Z
Sistema: Digite 'api' para fazer requisição:
Usuário: api
Sistema: Requisição autorizada para jose.roberto

Exemplo 2: Decodificar Token sem Verificar

Objetivo: Demonstrar leitura de dados do token sem validar assinatura

JSON para Importar

{
  "name": "Decodificar Token JWT",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "token_1",
      "type": "token",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Gerar Token",
        "parameters": {
          "operation": "generate",
          "payload": {
            "userId": "12345",
            "username": "jose.roberto",
            "role": "admin",
            "email": "jose@example.com"
          },
          "secret": "meu-secret"
        }
      }
    },
    {
      "id": "token_2",
      "type": "token",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Decodificar",
        "parameters": {
          "operation": "decode",
          "token": "{{token_1.token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Dados Extraídos",
        "parameters": {
          "message": "User: {{token_2.payload.username}}\nRole: {{token_2.payload.role}}\nEmail: {{token_2.payload.email}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "token_1" },
    { "source": "token_1", "target": "token_2" },
    { "source": "token_2", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: User: jose.roberto
Role: admin
Email: jose@example.com

Exemplo 3: Autorização Baseada em Roles

Objetivo: Demonstrar controle de acesso usando claims do token

JSON para Importar

{
  "name": "Autorização por Roles no Token",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Selecionar Role",
        "parameters": {
          "message": "Digite seu role (admin/user/guest):",
          "variableName": "userRole"
        }
      }
    },
    {
      "id": "token_1",
      "type": "token",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Criar Token",
        "parameters": {
          "operation": "generate",
          "payload": {
            "username": "usuario",
            "role": "{{userRole}}"
          },
          "secret": "secret-key"
        }
      }
    },
    {
      "id": "token_2",
      "type": "token",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Verificar Token",
        "parameters": {
          "operation": "verify",
          "token": "{{token_1.token}}",
          "secret": "secret-key"
        }
      }
    },
    {
      "id": "condition_1",
      "type": "condition",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "É Admin?",
        "parameters": {
          "condition": "{{token_2.payload.role}} == 'admin'"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 1100, "y": 50 },
      "data": {
        "label": "Admin",
        "parameters": {
          "message": "Acesso total concedido (Admin)"
        }
      }
    },
    {
      "id": "message_2",
      "type": "message",
      "position": { "x": 1100, "y": 150 },
      "data": {
        "label": "Outros",
        "parameters": {
          "message": "Acesso limitado (Role: {{token_2.payload.role}})"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1300, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "token_1" },
    { "source": "token_1", "target": "token_2" },
    { "source": "token_2", "target": "condition_1" },
    { "source": "condition_1", "target": "message_1", "label": "true" },
    { "source": "condition_1", "target": "message_2", "label": "false" },
    { "source": "message_1", "target": "end_1" },
    { "source": "message_2", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: Digite seu role (admin/user/guest):
Usuário: admin
Sistema: Acesso total concedido (Admin)

Resposta do Node

Generate:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expiresAt": "2025-01-15T11:30:00.000Z",
  "payload": {
    "userId": "12345",
    "username": "jose.roberto"
  }
}

Verify (válido):

{
  "success": true,
  "valid": true,
  "payload": {
    "userId": "12345",
    "username": "jose.roberto",
    "iat": 1705317000,
    "exp": 1705320600
  },
  "timestamp": "2025-01-15T10:30:00.000Z"
}

Decode:

{
  "success": true,
  "header": {
    "alg": "HS256",
    "typ": "JWT"
  },
  "payload": {
    "userId": "12345",
    "username": "jose.roberto",
    "iat": 1705317000,
    "exp": 1705320600
  },
  "timestamp": "2025-01-15T10:30:00.000Z"
}

Boas Práticas

SIM:

  • Use tokens JWT para APIs stateless
  • Defina expiração apropriada (1h para tokens de acesso)
  • Inclua apenas dados necessários no payload
  • Use secret forte e armazenado em variável de ambiente
  • Verifique assinatura antes de confiar no token
  • Implemente refresh tokens para sessões longas

NÃO:

  • Não inclua dados sensíveis no payload (JWT é apenas codificado)
  • Não use tokens sem expiração
  • Não compartilhe secret entre sistemas diferentes
  • Não confie em tokens sem verificação
  • Não use secrets curtos ou previsíveis
  • Não armazene tokens em localStorage (use httpOnly cookies)

Dicas

💡 Dica 1: JWT não é criptografado, apenas codificado. Qualquer um pode ler o payload sem a chave

💡 Dica 2: Use operation "decode" quando só precisa ler dados, "verify" quando precisa validar autenticidade

💡 Dica 3: Combine TOKEN com CONDITION para criar fluxos de autorização baseados em roles e permissões

💡 Dica 4: Para máxima segurança, use tokens de curta duração (5-15min) com refresh tokens

💡 Dica 5: Inclua timestamp ou nonce no payload para prevenir replay attacks

Próximo Node

AUTH - Autenticação e gerenciamento de sessão → 2FA - Autenticação de dois fatores → OAUTH - OAuth 2.0 flow