20 KiB
Implementando Basic Auth
Para validar todo o circuito com Basic Auth, você precisa configurar três relações distintas:
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 Backendnão envia credencial;Agent Backend → MCP Gatewayenvia 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:
cd agent_framework_oci_authentication_v2_1
Crie um único ambiente virtual para facilitar o teste:
python -m venv .venv
source .venv/bin/activate
No Windows PowerShell:
python -m venv .venv
.\.venv\Scripts\Activate.ps1
Instale o framework e as dependências dos três componentes:
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:
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:
Tuning-Performance/Authentication/
agent_template_backend_authentication/
scripts/generate_secret_hash.py
Execute:
python Tuning-Performance/Authentication/agent_template_backend_authentication/scripts/generate_secret_hash.py \
--secret 'TiaGateway-Test-2026!'
Depois:
python Tuning-Performance/Authentication/agent_template_backend_authentication/scripts/generate_secret_hash.py \
--secret 'GatewayBackend-Test-2026!'
E:
python Tuning-Performance/Authentication/agent_template_backend_authentication/scripts/generate_secret_hash.py \
--secret 'BackendMcp-Test-2026!'
Você receberá três valores semelhantes a:
pbkdf2_sha256:310000:<salt>:<digest>
Guarde-os temporariamente:
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:
cd apps/agent_gateway
Copie o exemplo:
cp .env.example .env
Adicione ao final do .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:
BACKEND_AUTH_SECRET=GatewayBackend-Test-2026!
O arquivo de backends já aponta o backend Contas para:
contas:
url: http://localhost:8000
Arquivo:
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:
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:
import os
Altere o construtor:
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:
resp = await client.post(url, json=payload)
por:
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:
resp = await client.get(url, auth=self._auth())
Agora abra:
apps/agent_gateway/app/main.py
Adicione:
import os
Troque:
backend_client = BackendClient(
timeout_seconds=settings.BACKEND_TIMEOUT_SECONDS
)
por:
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:
Agent Gateway → Agent Backend
Authorization: Basic base64(agent-gateway-test:GatewayBackend-Test-2026!)
5. Configurar o Agent Backend autenticado
Entre no diretório:
cd Tuning-Performance/Authentication/agent_template_backend_authentication
Copie o exemplo:
cp .env.example .env
Ajuste a seção de autenticação:
# 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:
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:
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:
libs/agent_framework/src/agent_framework/gateways/mcp_gateway_client.py
Substitua a implementação por:
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:
libs/agent_framework/src/agent_framework/mcp/tool_router.py
Localize:
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:
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:
libs/agent_framework/src/agent_framework/config/settings.py
Próximo das configurações existentes de MCP Gateway:
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:
Tuning-Performance/Authentication/
agent_template_backend_authentication/
app/mcp_gateway_client_factory.py
Ajuste para:
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:
cd apps/mcp_gateway
Crie .env:
cp .env.example .env
Adicione:
# 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:
apps/mcp_gateway/config/mcp_gateway.yaml
Localize a seção:
auth:
enabled: true
Altere para:
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:
source .venv/bin/activate
Suba o servidor telecom:
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:
uvicorn mcp.servers.retail_mcp_server.main:app \
--host 0.0.0.0 \
--port 8200 \
--reload
Confira as URLs configuradas em:
apps/mcp_gateway/config/mcp_gateway.yaml
Para execução local, devem apontar para:
url: http://localhost:8100
e:
url: http://localhost:8200
Terminal 2 — MCP Gateway
cd apps/mcp_gateway
source ../../.venv/bin/activate
Suba usando --env-file. Isso é importante porque o middleware lê variáveis com os.getenv():
uvicorn app.main:app \
--host 0.0.0.0 \
--port 8300 \
--reload \
--env-file .env
Teste a saúde pública:
curl http://localhost:8300/health
Teste um endpoint protegido sem credencial:
curl -i http://localhost:8300/v1/tools
Esperado:
HTTP/1.1 401 Unauthorized
Teste com Basic Auth:
curl -i \
-u 'agent-backend-test:BackendMcp-Test-2026!' \
http://localhost:8300/v1/tools
Esperado:
HTTP/1.1 200 OK
Terminal 3 — Agent Backend
cd Tuning-Performance/Authentication/agent_template_backend_authentication
source ../../../.venv/bin/activate
Suba:
uvicorn app.main:app \
--host 0.0.0.0 \
--port 8000 \
--reload \
--env-file .env
Teste saúde:
curl http://localhost:8000/health
Teste endpoint protegido sem credencial:
curl -i http://localhost:8000/agents
Esperado:
HTTP/1.1 401 Unauthorized
Teste com a credencial usada pelo Agent Gateway:
curl -i \
-u 'agent-gateway-test:GatewayBackend-Test-2026!' \
http://localhost:8000/agents
Esperado:
HTTP/1.1 200 OK
Teste mensagem diretamente:
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
cd apps/agent_gateway
source ../../.venv/bin/activate
Suba:
uvicorn app.main:app \
--host 0.0.0.0 \
--port 8010 \
--reload \
--env-file .env
Teste saúde:
curl http://localhost:8010/health
Teste endpoint protegido sem credencial:
curl -i http://localhost:8010/backends
Esperado:
HTTP/1.1 401 Unauthorized
Teste com a credencial externa:
curl -i \
-u 'tia-test:TiaGateway-Test-2026!' \
http://localhost:8010/backends
Esperado:
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:
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 é:
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
curl -i \
-u 'tia-test:senha-errada' \
http://localhost:8010/backends
Resultado esperado:
401 Unauthorized
Secret do gateway para backend incorreto
Altere temporariamente no apps/agent_gateway/.env:
BACKEND_AUTH_SECRET=senha-errada
Reinicie o Agent Gateway e envie uma mensagem.
O gateway deverá retornar erro de backend, normalmente:
502 Bad Gateway
O erro interno será originado por um:
401 Unauthorized
do Agent Backend.
Secret do backend para MCP incorreto
Altere temporariamente:
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:
401 Unauthorized
11. Verificação rápida de portas
No Linux ou WSL:
ss -lntp | grep -E ':8000|:8010|:8100|:8200|:8300'
No Windows PowerShell:
Get-NetTCPConnection -State Listen |
Where-Object LocalPort -in 8000,8010,8100,8200,8300 |
Sort-Object LocalPort
Você deverá ver:
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:
TIA ou curl:
TiaGateway-Test-2026!
Agent Gateway:
GatewayBackend-Test-2026!
Agent Backend:
BackendMcp-Test-2026!
Os componentes servidores armazenam apenas os hashes:
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.