# Implementando Basic Auth Para validar **todo o circuito com Basic Auth**, você precisa configurar três relações distintas: ```text Cliente de teste └─ Basic Auth A ─► Agent Gateway :8010 └─ Basic Auth B ─► Agent Backend :8000 └─ Basic Auth C ─► MCP Gateway :8300 ``` Há um detalhe importante: no pacote atual, a autenticação Basic já funciona para chamadas **de entrada**, mas os clientes internos ainda não enviam Basic Auth: * `Agent Gateway → Agent Backend` não envia credencial; * `Agent Backend → MCP Gateway` envia apenas Bearer Token. Portanto, para testar o circuito inteiro com Basic Auth, faça os dois pequenos ajustes de código descritos abaixo. --- # 1. Preparar o ambiente Considere que o ZIP foi extraído em: ```bash cd agent_framework_oci_authentication_v2_1 ``` Crie um único ambiente virtual para facilitar o teste: ```bash python -m venv .venv source .venv/bin/activate ``` No Windows PowerShell: ```powershell python -m venv .venv .\.venv\Scripts\Activate.ps1 ``` Instale o framework e as dependências dos três componentes: ```bash pip install -U pip pip install -e ./libs/agent_framework pip install \ -r ./Tuning-Performance/Authentication/agent_template_backend_authentication/requirements.txt \ -r ./apps/agent_gateway/requirements.txt \ -r ./apps/mcp_gateway/requirements.txt ``` Confirme a importação: ```bash python -c "from agent_framework.security import install_authentication; print('framework ok')" ``` --- # 2. Criar três pares de Client ID e Secret Use credenciais diferentes para cada trecho. Para teste local: | Fluxo | Client ID | Secret de teste | | ----------------------- | -------------------- | --------------------------- | | Cliente → Agent Gateway | `tia-test` | `TiaGateway-Test-2026!` | | Agent Gateway → Backend | `agent-gateway-test` | `GatewayBackend-Test-2026!` | | Backend → MCP Gateway | `agent-backend-test` | `BackendMcp-Test-2026!` | Esses valores são apenas para ambiente local. Não os reutilize em produção. ## Gerar os hashes O script está em: ```text Tuning-Performance/Authentication/ agent_template_backend_authentication/ scripts/generate_secret_hash.py ``` Execute: ```bash python Tuning-Performance/Authentication/agent_template_backend_authentication/scripts/generate_secret_hash.py \ --secret 'TiaGateway-Test-2026!' ``` Depois: ```bash python Tuning-Performance/Authentication/agent_template_backend_authentication/scripts/generate_secret_hash.py \ --secret 'GatewayBackend-Test-2026!' ``` E: ```bash python Tuning-Performance/Authentication/agent_template_backend_authentication/scripts/generate_secret_hash.py \ --secret 'BackendMcp-Test-2026!' ``` Você receberá três valores semelhantes a: ```text pbkdf2_sha256:310000:: ``` Guarde-os temporariamente: ```bash HASH_CLIENT_GATEWAY='pbkdf2_sha256:310000:...' HASH_GATEWAY_BACKEND='pbkdf2_sha256:310000:...' HASH_BACKEND_MCP='pbkdf2_sha256:310000:...' ``` O hash muda a cada execução porque o salt é aleatório. Isso é esperado. --- # 3. Configurar o Agent Gateway Entre no diretório: ```bash cd apps/agent_gateway ``` Copie o exemplo: ```bash cp .env.example .env ``` Adicione ao final do `.env`: ```env # Entrada: cliente/TIA -> Agent Gateway AGENT_GATEWAY_AUTH_ENABLED=true AGENT_GATEWAY_AUTH_MODE=basic AGENT_GATEWAY_AUTH_BASIC_CLIENT_ID=tia-test AGENT_GATEWAY_AUTH_BASIC_SECRET_HASH=COLE_AQUI_HASH_CLIENT_GATEWAY AGENT_GATEWAY_AUTH_BASIC_REALM=agent-gateway AGENT_GATEWAY_AUTH_PUBLIC_PATHS=/health,/docs,/openapi.json,/redoc AGENT_GATEWAY_AUTH_PUBLIC_PREFIXES= # Saída: Agent Gateway -> Agent Backend BACKEND_AUTH_MODE=basic BACKEND_AUTH_CLIENT_ID=agent-gateway-test BACKEND_AUTH_SECRET=GatewayBackend-Test-2026! ``` Não coloque aspas no `.env`: ```env BACKEND_AUTH_SECRET=GatewayBackend-Test-2026! ``` O arquivo de backends já aponta o backend Contas para: ```yaml contas: url: http://localhost:8000 ``` Arquivo: ```text apps/agent_gateway/config/backends.yaml ``` Para este teste, mantenha apenas o backend `contas` ou force o backend no payload. Caso contrário, pedidos sobre ofertas e suporte podem ser roteados para portas em que nenhum backend está rodando. --- # 4. Fazer o Agent Gateway enviar Basic Auth ao backend Abra: ```text libs/agent_framework/src/agent_framework/global_supervisor/client.py ``` Substitua a classe `BackendClient` por uma versão que aceite autenticação Basic. No início do arquivo, adicione: ```python import os ``` Altere o construtor: ```python class BackendClient: def __init__( self, timeout_seconds: float = 120.0, basic_client_id: str | None = None, basic_secret: str | None = None, ): self.timeout_seconds = timeout_seconds self.basic_client_id = basic_client_id self.basic_secret = basic_secret def _auth(self) -> httpx.BasicAuth | None: if self.basic_client_id and self.basic_secret: return httpx.BasicAuth( username=self.basic_client_id, password=self.basic_secret, ) return None ``` No método `call_message`, troque: ```python resp = await client.post(url, json=payload) ``` por: ```python resp = await client.post( url, json=payload, auth=self._auth(), ) ``` No método `health`, você pode manter `/health` público. Caso queira enviar autenticação também, use: ```python resp = await client.get(url, auth=self._auth()) ``` Agora abra: ```text apps/agent_gateway/app/main.py ``` Adicione: ```python import os ``` Troque: ```python backend_client = BackendClient( timeout_seconds=settings.BACKEND_TIMEOUT_SECONDS ) ``` por: ```python backend_client = BackendClient( timeout_seconds=settings.BACKEND_TIMEOUT_SECONDS, basic_client_id=os.getenv("BACKEND_AUTH_CLIENT_ID"), basic_secret=os.getenv("BACKEND_AUTH_SECRET"), ) ``` Isso implementa: ```text Agent Gateway → Agent Backend Authorization: Basic base64(agent-gateway-test:GatewayBackend-Test-2026!) ``` --- # 5. Configurar o Agent Backend autenticado Entre no diretório: ```bash cd Tuning-Performance/Authentication/agent_template_backend_authentication ``` Copie o exemplo: ```bash cp .env.example .env ``` Ajuste a seção de autenticação: ```env # Entrada: Agent Gateway -> Agent Backend AGENT_AUTH_ENABLED=true AGENT_AUTH_MODE=basic AGENT_AUTH_BASIC_CLIENT_ID=agent-gateway-test AGENT_AUTH_BASIC_SECRET_HASH=COLE_AQUI_HASH_GATEWAY_BACKEND AGENT_AUTH_BASIC_REALM=agent-contas AGENT_AUTH_PUBLIC_PATHS=/health,/docs,/openapi.json,/redoc AGENT_AUTH_PUBLIC_PREFIXES= ``` Para usar o MCP Gateway: ```env MCP_GATEWAY_ENABLED=true MCP_GATEWAY_URL=http://localhost:8300 MCP_GATEWAY_TIMEOUT_SECONDS=60 # Saída: Agent Backend -> MCP Gateway MCP_GATEWAY_AUTH_MODE=basic MCP_GATEWAY_BASIC_CLIENT_ID=agent-backend-test MCP_GATEWAY_BASIC_SECRET=BackendMcp-Test-2026! ``` Para evitar dependências externas durante o primeiro teste, configure também: ```env LLM_PROVIDER=mock ENABLE_LANGFUSE=false ENABLE_ANALYTICS=false SESSION_REPOSITORY_PROVIDER=memory MEMORY_REPOSITORY_PROVIDER=memory CHECKPOINT_REPOSITORY_PROVIDER=memory CACHE_PROVIDER=memory USAGE_REPOSITORY_PROVIDER=memory ``` Os nomes exatos de alguns providers podem depender do arquivo de configuração atual do framework. Caso o `.env.example` já contenha valores locais ou mock, preserve-os. --- # 6. Fazer o Backend enviar Basic Auth ao MCP Gateway Abra: ```text libs/agent_framework/src/agent_framework/gateways/mcp_gateway_client.py ``` Substitua a implementação por: ```python from __future__ import annotations import base64 from typing import Any import httpx class MCPGatewayClient: def __init__( self, base_url: str, token: str | None = None, timeout_seconds: int = 60, auth_mode: str | None = None, basic_client_id: str | None = None, basic_secret: str | None = None, ): self.base_url = base_url.rstrip("/") self.token = token self.timeout_seconds = timeout_seconds self.auth_mode = (auth_mode or "").strip().lower() self.basic_client_id = basic_client_id self.basic_secret = basic_secret def _headers(self) -> dict[str, str]: if ( self.auth_mode == "basic" and self.basic_client_id and self.basic_secret ): raw = f"{self.basic_client_id}:{self.basic_secret}".encode("utf-8") encoded = base64.b64encode(raw).decode("ascii") return {"Authorization": f"Basic {encoded}"} if self.token: return {"Authorization": f"Bearer {self.token}"} return {} async def list_tools(self) -> dict[str, Any]: async with httpx.AsyncClient( timeout=self.timeout_seconds ) as client: response = await client.get( f"{self.base_url}/v1/tools", headers=self._headers(), ) response.raise_for_status() return response.json() async def invoke_tool( self, *, tenant_id: str, agent_id: str, channel: str | None, tool_name: str, arguments: dict[str, Any] | None = None, business_context: dict[str, Any] | None = None, metadata: dict[str, Any] | None = None, ) -> dict[str, Any]: payload = { "tenant_id": tenant_id, "agent_id": agent_id, "channel": channel, "tool_name": tool_name, "arguments": arguments or {}, "business_context": business_context or {}, "metadata": metadata or {}, } async with httpx.AsyncClient( timeout=self.timeout_seconds ) as client: response = await client.post( f"{self.base_url}/v1/tools/{tool_name}/invoke", json=payload, headers=self._headers(), ) response.raise_for_status() return response.json() ``` Agora abra: ```text libs/agent_framework/src/agent_framework/mcp/tool_router.py ``` Localize: ```python MCPGatewayClient( base_url=getattr( settings, "MCP_GATEWAY_URL", "http://localhost:8300", ), token=getattr(settings, "MCP_GATEWAY_TOKEN", None), timeout_seconds=getattr( settings, "MCP_GATEWAY_TIMEOUT_SECONDS", settings.MCP_TOOL_TIMEOUT_SECONDS, ), ) ``` Altere para: ```python MCPGatewayClient( base_url=getattr( settings, "MCP_GATEWAY_URL", "http://localhost:8300", ), token=getattr(settings, "MCP_GATEWAY_TOKEN", None), timeout_seconds=getattr( settings, "MCP_GATEWAY_TIMEOUT_SECONDS", settings.MCP_TOOL_TIMEOUT_SECONDS, ), auth_mode=getattr( settings, "MCP_GATEWAY_AUTH_MODE", None, ), basic_client_id=getattr( settings, "MCP_GATEWAY_BASIC_CLIENT_ID", None, ), basic_secret=getattr( settings, "MCP_GATEWAY_BASIC_SECRET", None, ), ) ``` Adicione estes campos em: ```text libs/agent_framework/src/agent_framework/config/settings.py ``` Próximo das configurações existentes de MCP Gateway: ```python MCP_GATEWAY_AUTH_MODE: str | None = None MCP_GATEWAY_BASIC_CLIENT_ID: str | None = None MCP_GATEWAY_BASIC_SECRET: str | None = None ``` Há também uma factory local em: ```text Tuning-Performance/Authentication/ agent_template_backend_authentication/ app/mcp_gateway_client_factory.py ``` Ajuste para: ```python from __future__ import annotations import os from agent_framework.gateways import MCPGatewayClient def build_mcp_gateway_client() -> MCPGatewayClient | None: if os.getenv("MCP_GATEWAY_ENABLED", "true").lower() != "true": return None return MCPGatewayClient( base_url=os.getenv( "MCP_GATEWAY_URL", "http://localhost:8300", ), token=os.getenv("MCP_GATEWAY_TOKEN") or None, timeout_seconds=int( os.getenv("MCP_GATEWAY_TIMEOUT_SECONDS", "60") ), auth_mode=os.getenv("MCP_GATEWAY_AUTH_MODE"), basic_client_id=os.getenv( "MCP_GATEWAY_BASIC_CLIENT_ID" ), basic_secret=os.getenv( "MCP_GATEWAY_BASIC_SECRET" ), ) ``` --- # 7. Configurar o MCP Gateway Entre no diretório: ```bash cd apps/mcp_gateway ``` Crie `.env`: ```bash cp .env.example .env ``` Adicione: ```env # Entrada: Agent Backend -> MCP Gateway MCP_GATEWAY_AUTH_ENABLED=true MCP_GATEWAY_AUTH_MODE=basic MCP_GATEWAY_AUTH_BASIC_CLIENT_ID=agent-backend-test MCP_GATEWAY_AUTH_BASIC_SECRET_HASH=COLE_AQUI_HASH_BACKEND_MCP MCP_GATEWAY_AUTH_BASIC_REALM=mcp-gateway MCP_GATEWAY_AUTH_PUBLIC_PATHS=/health,/ready,/docs,/openapi.json,/redoc MCP_GATEWAY_AUTH_PUBLIC_PREFIXES= MCP_GATEWAY_CONFIG_PATH=config/mcp_gateway.yaml ``` ## Desabilitar o mecanismo Bearer legado O MCP Gateway ainda possui um segundo mecanismo antigo, configurado dentro de: ```text apps/mcp_gateway/config/mcp_gateway.yaml ``` Localize a seção: ```yaml auth: enabled: true ``` Altere para: ```yaml auth: enabled: false ``` Isso é necessário porque o novo middleware já faz a autenticação Basic. Caso o `auth_check()` legado continue habilitado, a requisição passará pelo Basic e depois será rejeitada por não possuir Bearer Token. --- # 8. Subir os componentes Use quatro terminais. ## Terminal 1 — MCP Servers O MCP Gateway precisa ter pelo menos um servidor MCP disponível para demonstrar uma chamada real. Na raiz do projeto: ```bash source .venv/bin/activate ``` Suba o servidor telecom: ```bash uvicorn mcp.servers.telecom_mcp_server.main:app \ --host 0.0.0.0 \ --port 8100 \ --reload ``` Em outro terminal, caso queira também o retail: ```bash uvicorn mcp.servers.retail_mcp_server.main:app \ --host 0.0.0.0 \ --port 8200 \ --reload ``` Confira as URLs configuradas em: ```text apps/mcp_gateway/config/mcp_gateway.yaml ``` Para execução local, devem apontar para: ```yaml url: http://localhost:8100 ``` e: ```yaml url: http://localhost:8200 ``` --- ## Terminal 2 — MCP Gateway ```bash cd apps/mcp_gateway source ../../.venv/bin/activate ``` Suba usando `--env-file`. Isso é importante porque o middleware lê variáveis com `os.getenv()`: ```bash uvicorn app.main:app \ --host 0.0.0.0 \ --port 8300 \ --reload \ --env-file .env ``` Teste a saúde pública: ```bash curl http://localhost:8300/health ``` Teste um endpoint protegido sem credencial: ```bash curl -i http://localhost:8300/v1/tools ``` Esperado: ```text HTTP/1.1 401 Unauthorized ``` Teste com Basic Auth: ```bash curl -i \ -u 'agent-backend-test:BackendMcp-Test-2026!' \ http://localhost:8300/v1/tools ``` Esperado: ```text HTTP/1.1 200 OK ``` --- ## Terminal 3 — Agent Backend ```bash cd Tuning-Performance/Authentication/agent_template_backend_authentication source ../../../.venv/bin/activate ``` Suba: ```bash uvicorn app.main:app \ --host 0.0.0.0 \ --port 8000 \ --reload \ --env-file .env ``` Teste saúde: ```bash curl http://localhost:8000/health ``` Teste endpoint protegido sem credencial: ```bash curl -i http://localhost:8000/agents ``` Esperado: ```text HTTP/1.1 401 Unauthorized ``` Teste com a credencial usada pelo Agent Gateway: ```bash curl -i \ -u 'agent-gateway-test:GatewayBackend-Test-2026!' \ http://localhost:8000/agents ``` Esperado: ```text HTTP/1.1 200 OK ``` Teste mensagem diretamente: ```bash curl -X POST http://localhost:8000/gateway/message \ -u 'agent-gateway-test:GatewayBackend-Test-2026!' \ -H 'Content-Type: application/json' \ -d '{ "channel": "web", "agent_id": "telecom_contas", "tenant_id": "default", "payload": { "text": "Quero consultar minha fatura", "session_id": "teste-backend-001", "user_id": "user-001", "customer_id": "12345", "message_id": "msg-001" } }' ``` --- ## Terminal 4 — Agent Gateway ```bash cd apps/agent_gateway source ../../.venv/bin/activate ``` Suba: ```bash uvicorn app.main:app \ --host 0.0.0.0 \ --port 8010 \ --reload \ --env-file .env ``` Teste saúde: ```bash curl http://localhost:8010/health ``` Teste endpoint protegido sem credencial: ```bash curl -i http://localhost:8010/backends ``` Esperado: ```text HTTP/1.1 401 Unauthorized ``` Teste com a credencial externa: ```bash curl -i \ -u 'tia-test:TiaGateway-Test-2026!' \ http://localhost:8010/backends ``` Esperado: ```text HTTP/1.1 200 OK ``` --- # 9. Validar o circuito completo Force o backend `contas` para evitar que o roteador selecione um backend não iniciado: ```bash curl -X POST http://localhost:8010/gateway/message \ -u 'tia-test:TiaGateway-Test-2026!' \ -H 'Content-Type: application/json' \ -d '{ "channel": "web", "backend_id": "contas", "tenant_id": "default", "agent_id": "telecom_contas", "session_id": "circuito-basic-001", "payload": { "text": "Quero consultar minha fatura", "session_id": "circuito-basic-001", "user_id": "user-001", "customer_id": "12345", "message_id": "msg-circuito-001" } }' ``` O circuito esperado é: ```text curl │ Basic tia-test ▼ Agent Gateway :8010 │ Basic agent-gateway-test ▼ Agent Backend :8000 │ Basic agent-backend-test ▼ MCP Gateway :8300 ▼ MCP Server :8100 ou :8200 ``` --- # 10. Como comprovar cada autenticação Faça testes negativos em cada trecho. ## Secret externo incorreto ```bash curl -i \ -u 'tia-test:senha-errada' \ http://localhost:8010/backends ``` Resultado esperado: ```text 401 Unauthorized ``` ## Secret do gateway para backend incorreto Altere temporariamente no `apps/agent_gateway/.env`: ```env BACKEND_AUTH_SECRET=senha-errada ``` Reinicie o Agent Gateway e envie uma mensagem. O gateway deverá retornar erro de backend, normalmente: ```text 502 Bad Gateway ``` O erro interno será originado por um: ```text 401 Unauthorized ``` do Agent Backend. ## Secret do backend para MCP incorreto Altere temporariamente: ```env MCP_GATEWAY_BASIC_SECRET=senha-errada ``` Reinicie o backend e execute uma frase que acione uma ferramenta MCP. O backend deverá registrar falha na chamada ao MCP Gateway com: ```text 401 Unauthorized ``` --- # 11. Verificação rápida de portas No Linux ou WSL: ```bash ss -lntp | grep -E ':8000|:8010|:8100|:8200|:8300' ``` No Windows PowerShell: ```powershell Get-NetTCPConnection -State Listen | Where-Object LocalPort -in 8000,8010,8100,8200,8300 | Sort-Object LocalPort ``` Você deverá ver: ```text 8000 Agent Backend 8010 Agent Gateway 8100 Telecom MCP Server 8200 Retail MCP Server 8300 MCP Gateway ``` ## Observação importante O segredo original precisa existir no componente cliente: ```text TIA ou curl: TiaGateway-Test-2026! Agent Gateway: GatewayBackend-Test-2026! Agent Backend: BackendMcp-Test-2026! ``` Os componentes servidores armazenam apenas os hashes: ```text Agent Gateway: hash de TiaGateway-Test-2026! Agent Backend: hash de GatewayBackend-Test-2026! MCP Gateway: hash de BackendMcp-Test-2026! ``` Em produção, os segredos originais e hashes devem vir de Vault ou Kubernetes Secret, não de arquivos `.env`.