Skip to content

JWT Authentication - Diagramas de Fluxo

🔄 Fluxo Completo: WebChat com JWT

sequenceDiagram
    participant User as 👤 Usuário<br/>(Autenticado no Site)
    participant Frontend as 🌐 Frontend<br/>(WebChat Widget)
    participant Adapter as 📡 WebChatAdapter
    participant Processor as ⚙️ ConversationProcessor
    participant JWTMgr as 🔐 JWTContextManager
    participant SessionSvc as 💾 SessionService
    participant Runner as 🤖 ADK Runner
    participant Tool as 🛠️ Tool (buscar_usuario)
    participant API as 🌍 API iFriend

    Note over User,Frontend: 1. Usuário Envia Mensagem
    User->>Frontend: "Quero reservar uma tour em Roma"
    Frontend->>Frontend: Obtém JWT do localStorage/cookie

    Note over Frontend,Adapter: 2. Request com JWT
    Frontend->>Adapter: POST /webchat/message<br/>Authorization: Bearer eyJhbG...

    Note over Adapter,Processor: 3. Parse & Create IncomingMessage
    Adapter->>Adapter: Extrai JWT do header/body
    Adapter->>Adapter: Cria IncomingMessage<br/>metadata.jwt_token = JWT
    Adapter->>Processor: process_message(IncomingMessage)

    Note over Processor,JWTMgr: 4. Decode & Validate JWT
    Processor->>JWTMgr: get_user_context(jwt_token)
    JWTMgr->>JWTMgr: Decodifica JWT
    JWTMgr->>JWTMgr: Valida assinatura
    JWTMgr->>JWTMgr: Valida expiração
    JWTMgr->>Processor: UserContext(user_id, email, roles, token)

    Note over Processor,SessionSvc: 5. Injeta JWT na Sessão
    Processor->>SessionSvc: set_jwt_context(session_id, jwt_context)
    SessionSvc->>SessionSvc: session.metadata.jwt_context = {...}
    SessionSvc->>Processor: OK

    Processor->>Processor: Configura ContextVar<br/>current_session_context

    Note over Processor,Runner: 6. Processa Mensagem
    Processor->>Runner: run_async(session_id, user_id, message)
    Runner->>Runner: Agente decide chamar tool

    Note over Runner,Tool: 7. Tool Executa com JWT Context
    Runner->>Tool: buscar_usuario_tool(email="user@example.com")
    Tool->>Tool: ctx = current_session_context.get()
    Tool->>SessionSvc: get_session_context(ctx)
    SessionSvc->>Tool: session.metadata.jwt_context
    Tool->>Tool: get_auth_headers(session_context)<br/>→ "Authorization: Bearer <JWT>"

    Note over Tool,API: 8. Chamada Autenticada
    Tool->>API: GET /users?userEmail=...<br/>Authorization: Bearer <JWT do usuário>
    API->>API: Valida JWT
    API->>API: Retorna dados do USUÁRIO REAL
    API->>Tool: {user: {...}}

    Note over Tool,User: 9. Resposta ao Usuário
    Tool->>Runner: Resultado da tool
    Runner->>Processor: Resposta do agente
    Processor->>Adapter: Envia resposta
    Adapter->>Frontend: JSON response
    Frontend->>User: "Encontrei seu perfil! Vamos à reserva..."

🔀 Decisão: Usar JWT ou Auth Default?

flowchart TD
    Start([Nova Mensagem<br/>do Usuário]) --> CheckJWT{JWT token<br/>presente no<br/>metadata?}

    CheckJWT -->|Sim| ValidateJWT[Validar JWT]
    CheckJWT -->|Não| UseDefault[Usar Auth Default]

    ValidateJWT --> IsValid{JWT válido<br/>e não expirado?}

    IsValid -->|Sim| DecodeJWT[Decodificar JWT<br/>Extrair claims]
    IsValid -->|Não| LogWarning[⚠️ Log: JWT inválido]

    LogWarning --> UseDefault

    DecodeJWT --> InjectContext[Injetar JWT Context<br/>na Sessão ADK]
    InjectContext --> ProcessMsg[Processar Mensagem<br/>com Context JWT]

    UseDefault --> LogDefault[ℹ️ Log: Usando auth default]
    LogDefault --> ProcessMsg2[Processar Mensagem<br/>com Auth Default]

    ProcessMsg --> ToolExec[Tool Execution]
    ProcessMsg2 --> ToolExec

    ToolExec --> CheckContext{Tem JWT<br/>no session<br/>context?}

    CheckContext -->|Sim| UseJWTAuth[get_auth_headers<br/>usa JWT]
    CheckContext -->|Não| UseDefaultAuth[get_auth_headers<br/>autentica c/ API_EMAIL/PASSWORD]

    UseJWTAuth --> CallAPI[Chamada API<br/>c/ credenciais do usuário]
    UseDefaultAuth --> CallAPI2[Chamada API<br/>c/ credenciais default]

    CallAPI --> Success([✅ Resposta<br/>personalizada])
    CallAPI2 --> Success2([✅ Resposta<br/>genérica])

    style Start fill:#e1f5fe
    style Success fill:#c8e6c9
    style Success2 fill:#fff9c4
    style LogWarning fill:#ffccbc
    style DecodeJWT fill:#b2dfdb
    style InjectContext fill:#b2dfdb

🏗️ Componentes da Arquitetura

graph TB
    subgraph "Frontend"
        WebUI[🌐 Web UI<br/>React/Vue/Angular]
        Widget[💬 WebChat Widget]
        Mobile[📱 Mobile App]
    end

    subgraph "Messaging Adapters"
        WebChatAdapter[📡 WebChatAdapter]
        SSEAdapter[⚡ SSEAdapter]
        WhatsAppAdapter[💬 WhatsAppAdapter]
        SlackAdapter[💼 SlackAdapter]
    end

    subgraph "JWT Processing Layer"
        JWTManager[🔐 JWTContextManager<br/>Decode & Validate]
        SessionHelper[💾 SessionContextHelper<br/>Store JWT Context]
        ContextVar[🔄 ContextVar<br/>Thread-safe Context]
    end

    subgraph "ADK Core"
        Processor[⚙️ ConversationProcessor]
        Runner[🤖 ADK Runner]
        SessionSvc[💾 Session Service<br/>Redis/CloudSQL]
        MemorySvc[🧠 Memory Service]
    end

    subgraph "Tools & Auth"
        AuthMgr[🔑 Enhanced Auth Manager]
        BookingTools[🎫 Booking Tools]
        PaymentTools[💳 Payment Tools]
        SearchTools[🔍 Search Tools]
    end

    subgraph "External Services"
        APIiFriend[🌍 API iFriend]
        Redis[(Redis<br/>JWT Lookup Cache)]
    end

    WebUI -->|JWT in header| WebChatAdapter
    Widget -->|JWT in header| WebChatAdapter
    Widget -->|JWT in header| SSEAdapter
    Mobile -->|Phone → lookup| WhatsAppAdapter

    WebChatAdapter --> Processor
    SSEAdapter --> Processor
    WhatsAppAdapter -->|Lookup JWT| Redis
    SlackAdapter -->|Lookup JWT| Redis
    Redis --> WhatsAppAdapter
    Redis --> SlackAdapter
    WhatsAppAdapter --> Processor
    SlackAdapter --> Processor

    Processor --> JWTManager
    JWTManager --> SessionHelper
    SessionHelper --> SessionSvc
    Processor --> ContextVar

    Processor --> Runner
    Runner --> SessionSvc
    Runner --> MemorySvc

    Runner --> BookingTools
    Runner --> PaymentTools
    Runner --> SearchTools

    BookingTools --> ContextVar
    PaymentTools --> ContextVar
    SearchTools --> ContextVar

    BookingTools --> AuthMgr
    PaymentTools --> AuthMgr
    SearchTools --> AuthMgr

    AuthMgr -->|JWT ou Default| APIiFriend

    style JWTManager fill:#ffecb3
    style SessionHelper fill:#ffecb3
    style ContextVar fill:#ffecb3
    style AuthMgr fill:#c5e1a5
    style Redis fill:#b3e5fc

📱 Fluxo WhatsApp: Autenticação One-Time

sequenceDiagram
    participant User as 👤 Usuário
    participant WebUI as 🌐 Site iFriend
    participant Backend as 🖥️ Backend
    participant Redis as 💾 Redis
    participant WhatsApp as 💬 WhatsApp
    participant Adapter as 📡 WhatsAppAdapter

    Note over User,WebUI: Passo 1: Vinculação One-Time
    User->>WebUI: Login no site
    WebUI->>User: JWT token
    User->>WebUI: "Vincular WhatsApp"<br/>+5511999999999
    WebUI->>Backend: POST /whatsapp/link<br/>Authorization: Bearer <JWT><br/>{phone: "+5511999999999"}
    Backend->>Backend: Valida JWT
    Backend->>Redis: SET whatsapp:jwt:+5511999999999<br/>= JWT token<br/>EX 2592000 (30 dias)
    Redis->>Backend: OK
    Backend->>WebUI: ✅ WhatsApp vinculado
    WebUI->>User: "Agora você pode usar o WhatsApp!"

    Note over User,Adapter: Passo 2: Conversas Subsequentes (automático)
    User->>WhatsApp: "Quero reservar uma tour"
    WhatsApp->>Adapter: Webhook: new message
    Adapter->>Adapter: Extrai phone: +5511999999999
    Adapter->>Redis: GET whatsapp:jwt:+5511999999999
    Redis->>Adapter: JWT token
    Adapter->>Adapter: Adiciona JWT ao metadata
    Adapter->>Backend: process_message()<br/>metadata.jwt_token = JWT
    Note over Backend: Processa normalmente<br/>com autenticação do usuário
    Backend->>Adapter: Resposta
    Adapter->>WhatsApp: Send message
    WhatsApp->>User: "Ótimo! Vamos reservar..."

🔐 JWT Validation Flow

flowchart TD
    Start([JWT Token<br/>Recebido]) --> Parse[Parse JWT<br/>Header.Payload.Signature]

    Parse --> CheckFormat{Formato<br/>válido?}
    CheckFormat -->|Não| Error1[❌ JWT Malformed]
    CheckFormat -->|Sim| DecodeHeader[Decodifica Header<br/>alg, typ]

    DecodeHeader --> CheckAlg{Algoritmo<br/>suportado?}
    CheckAlg -->|Não| Error2[❌ Algorithm Not Allowed]
    CheckAlg -->|Sim| VerifySignature[Verifica Assinatura<br/>usando JWT_SECRET_KEY]

    VerifySignature --> SigValid{Assinatura<br/>válida?}
    SigValid -->|Não| Error3[❌ Invalid Signature]
    SigValid -->|Sim| DecodePayload[Decodifica Payload<br/>claims]

    DecodePayload --> CheckRequired{Claims<br/>obrigatórios<br/>presentes?}
    CheckRequired -->|Não| Error4[❌ Missing Required Claims<br/>sub, email, exp]
    CheckRequired -->|Sim| CheckExp{exp claim<br/>não expirado?}

    CheckExp -->|Expirado| Error5[❌ Token Expired]
    CheckExp -->|Válido| CheckIssuer{iss claim<br/>correto?}

    CheckIssuer -->|Não| Error6[❌ Invalid Issuer]
    CheckIssuer -->|Sim| CheckAudience{aud claim<br/>correto?}

    CheckAudience -->|Não| Error7[❌ Invalid Audience]
    CheckAudience -->|Sim| Success([✅ JWT Válido<br/>Extrai UserContext])

    Error1 --> Fallback[⚠️ Fallback:<br/>Usar Auth Default]
    Error2 --> Fallback
    Error3 --> Fallback
    Error4 --> Fallback
    Error5 --> Fallback
    Error6 --> Fallback
    Error7 --> Fallback

    Success --> InjectContext[Injeta Context<br/>na Sessão ADK]
    Fallback --> ProcessDefault[Processa sem JWT<br/>Auth Default]

    style Error1 fill:#ffcdd2
    style Error2 fill:#ffcdd2
    style Error3 fill:#ffcdd2
    style Error4 fill:#ffcdd2
    style Error5 fill:#ffcdd2
    style Error6 fill:#ffcdd2
    style Error7 fill:#ffcdd2
    style Success fill:#c8e6c9
    style Fallback fill:#fff9c4

🛠️ Tool Execution com JWT Context

flowchart TD
    Start([Tool Chamada<br/>buscar_usuario_tool]) --> GetContext[Obtém ContextVar<br/>current_session_context]

    GetContext --> HasContext{ContextVar<br/>presente?}

    HasContext -->|Não| UseDefault1[⚠️ Sem contexto<br/>usa auth default]
    HasContext -->|Sim| GetSession[Busca Session no<br/>SessionService]

    GetSession --> SessionFound{Sessão<br/>encontrada?}

    SessionFound -->|Não| UseDefault2[⚠️ Sessão não encontrada<br/>usa auth default]
    SessionFound -->|Sim| CheckJWTContext{session.metadata<br/>tem jwt_context?}

    CheckJWTContext -->|Não| UseDefault3[ℹ️ Sem JWT context<br/>usa auth default]
    CheckJWTContext -->|Sim| ExtractJWT[Extrai JWT token<br/>do jwt_context]

    ExtractJWT --> CheckExpiry{Token ainda<br/>válido?}

    CheckExpiry -->|Expirado| UseDefault4[⚠️ Token expirado<br/>usa auth default]
    CheckExpiry -->|Válido| UseJWT[✅ Usa JWT token<br/>Authorization: Bearer JWT]

    UseDefault1 --> AuthDefault[get_auth_headers<br/>autentica com<br/>API_EMAIL/PASSWORD]
    UseDefault2 --> AuthDefault
    UseDefault3 --> AuthDefault
    UseDefault4 --> AuthDefault

    UseJWT --> AuthJWT[get_auth_headers<br/>passa JWT token]

    AuthDefault --> GetToken[Autentica na API<br/>POST /authentication_token]
    GetToken --> CallAPI1[GET /users<br/>Authorization: Bearer DEFAULT_TOKEN]

    AuthJWT --> CallAPI2[GET /users<br/>Authorization: Bearer USER_JWT_TOKEN]

    CallAPI1 --> Response1([Resposta com<br/>dados do usuário default])
    CallAPI2 --> Response2([Resposta com<br/>dados do usuário real])

    style UseDefault1 fill:#fff9c4
    style UseDefault2 fill:#fff9c4
    style UseDefault3 fill:#fff9c4
    style UseDefault4 fill:#fff9c4
    style UseJWT fill:#c8e6c9
    style Response2 fill:#e1f5fe

🔄 Session Context Lifecycle

stateDiagram-v2
    [*] --> NoSession: Primeira mensagem do usuário

    NoSession --> SessionCreated: create_session()

    SessionCreated --> NoJWT: Mensagem sem JWT
    SessionCreated --> JWTReceived: Mensagem com JWT

    NoJWT --> JWTReceived: Próxima mensagem com JWT
    JWTReceived --> NoJWT: JWT expirou/inválido

    state NoJWT {
        [*] --> DefaultAuth
        DefaultAuth --> ProcessingDefault: Processa com auth default
        ProcessingDefault --> [*]
    }

    state JWTReceived {
        [*] --> ValidateJWT
        ValidateJWT --> InvalidJWT: Validação falhou
        ValidateJWT --> ValidJWT: Validação OK

        InvalidJWT --> FallbackDefault: Volta para auth default

        ValidJWT --> InjectContext: set_jwt_context()
        InjectContext --> ProcessingJWT: Processa com JWT
        ProcessingJWT --> [*]
    }

    NoJWT --> SessionExpired: TTL expirado
    JWTReceived --> SessionExpired: TTL expirado

    SessionExpired --> [*]: Sessão deletada

📊 Performance & Scalability

graph LR
    subgraph "Load Balancer"
        LB[⚖️ Load Balancer]
    end

    subgraph "App Servers"
        App1[🖥️ App Server 1]
        App2[🖥️ App Server 2]
        App3[🖥️ App Server 3]
    end

    subgraph "Session Layer"
        Redis1[(Redis Primary<br/>Session + JWT Lookup)]
        Redis2[(Redis Replica)]
    end

    subgraph "Memory Layer"
        CloudSQL[(CloudSQL<br/>Memory Service)]
        Firestore[(Firestore<br/>Backup)]
    end

    subgraph "External"
        API[🌍 API iFriend]
    end

    LB --> App1
    LB --> App2
    LB --> App3

    App1 --> Redis1
    App2 --> Redis1
    App3 --> Redis1

    Redis1 -.Replication.-> Redis2

    App1 --> CloudSQL
    App2 --> CloudSQL
    App3 --> CloudSQL

    App1 -.Fallback.-> Firestore
    App2 -.Fallback.-> Firestore
    App3 -.Fallback.-> Firestore

    App1 --> API
    App2 --> API
    App3 --> API

    style Redis1 fill:#b3e5fc
    style Redis2 fill:#b3e5fc
    style CloudSQL fill:#c5cae9
    style Firestore fill:#d1c4e9

Última atualização: 13 de fevereiro de 2026