Authentication & Security¶
Hector provides two layers of security: global JWT authentication for the A2A server and agent-level security for fine-grained access control.
Security Layers¶
┌──────────────────────────────────────────┐
│ Incoming Request │
└─────────────────┬────────────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ Global Authentication (Optional) │
│ - JWT validation │
│ - Token verification │
└─────────────────┬────────────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ Agent-Level Security (Optional) │
│ - Bearer auth │
│ - API key auth │
│ - Security schemes │
└─────────────────┬────────────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ Agent Processes Request │
└──────────────────────────────────────────┘
Global JWT Authentication¶
Validate JWT tokens from external auth providers (Auth0, Keycloak, Okta, etc.).
Quick Setup¶
global:
a2a_server:
host: "0.0.0.0"
port: 8080
auth:
jwks_url: "https://your-provider.com/.well-known/jwks.json"
issuer: "https://your-provider.com"
audience: "hector-api"
agents:
secure_agent:
llm: "gpt-4o"
# ... agent config
Start server:
hector serve --config config.yaml
# Output:
# Authentication: ENABLED
# JWT validator initialized
Make authenticated request:
# Get token from your auth provider first
TOKEN="eyJ..."
# Call Hector with token
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8080/agents/secure_agent/tasks \
-d '{"task": "Process request"}'
How It Works¶
- User logs in at auth provider (Auth0, Keycloak, etc.)
- Provider issues JWT token
- User includes token in request:
Authorization: Bearer <token>
- Hector validates token:
- Fetches JWKS from provider (cached)
- Verifies signature
- Checks expiration
- Validates issuer and audience
- If valid → process request
- If invalid → return 401 Unauthorized
Configuration¶
global:
auth:
jwks_url: "https://provider.com/.well-known/jwks.json" # Required
issuer: "https://provider.com" # Required
audience: "hector-api" # Required
# Optional
leeway: 60 # Clock skew tolerance (seconds)
cache_duration: "15m" # JWKS cache duration
Supported Providers¶
Hector works with any OAuth2/OIDC provider:
Auth0¶
auth:
jwks_url: "https://YOUR-TENANT.auth0.com/.well-known/jwks.json"
issuer: "https://YOUR-TENANT.auth0.com/"
audience: "hector-api"
Keycloak¶
auth:
jwks_url: "https://keycloak.example.com/realms/YOUR_REALM/protocol/openid-connect/certs"
issuer: "https://keycloak.example.com/realms/YOUR_REALM"
audience: "hector-api"
Okta¶
auth:
jwks_url: "https://YOUR-DOMAIN.okta.com/oauth2/default/v1/keys"
issuer: "https://YOUR-DOMAIN.okta.com/oauth2/default"
audience: "api://hector"
Google¶
auth:
jwks_url: "https://www.googleapis.com/oauth2/v3/certs"
issuer: "https://accounts.google.com"
audience: "YOUR_CLIENT_ID.apps.googleusercontent.com"
Token Claims¶
Hector extracts standard JWT claims:
sub
- Subject (user ID)iss
- Issueraud
- Audienceexp
- Expirationiat
- Issued atcustom_claims
- Provider-specific claims
Access claims in agent prompts (future feature):
agents:
personalized:
prompt:
system_role: |
You are assisting user: ${jwt.sub}
User email: ${jwt.email}
User role: ${jwt.role}
Agent-Level Security¶
Fine-grained security per agent using OpenAPI-style security schemes.
Quick Example¶
agents:
protected_agent:
llm: "gpt-4o"
security:
# Define security schemes
schemes:
bearer_auth:
type: "http"
scheme: "bearer"
bearer_format: "JWT"
api_key_auth:
type: "apiKey"
name: "X-API-Key"
in: "header"
# Require authentication (AND relationship)
require:
- bearer_auth
- api_key_auth
Request must include both:
curl -H "Authorization: Bearer token" \
-H "X-API-Key: my-api-key" \
http://localhost:8080/agents/protected_agent/tasks \
-d '{"task": "Secure task"}'
Security Schemes¶
HTTP Bearer Authentication¶
agents:
bearer_agent:
security:
schemes:
bearer_auth:
type: "http"
scheme: "bearer"
bearer_format: "JWT" # Optional
require:
- bearer_auth
Request:
curl -H "Authorization: Bearer your-token" \
http://localhost:8080/agents/bearer_agent/tasks
API Key Authentication¶
agents:
api_key_agent:
security:
schemes:
api_key:
type: "apiKey"
name: "X-API-Key" # Header/query/cookie name
in: "header" # header|query|cookie
require:
- api_key
Request:
# Header
curl -H "X-API-Key: your-api-key" \
http://localhost:8080/agents/api_key_agent/tasks
# Query
curl "http://localhost:8080/agents/api_key_agent/tasks?api_key=your-api-key"
# Cookie
curl -b "api_key=your-api-key" \
http://localhost:8080/agents/api_key_agent/tasks
Multiple Schemes (AND)¶
agents:
multi_auth:
security:
schemes:
bearer:
type: "http"
scheme: "bearer"
api_key:
type: "apiKey"
name: "X-API-Key"
in: "header"
require:
- bearer
- api_key # Both required
Alternative Schemes (OR)¶
agents:
flexible_auth:
security:
schemes:
bearer:
type: "http"
scheme: "bearer"
api_key:
type: "apiKey"
name: "X-API-Key"
in: "header"
require:
# If you need OR logic, use at the application level
- bearer # Currently only AND supported
Combining Both Layers¶
Use global JWT + agent-level security together:
# Global JWT validation
global:
auth:
jwks_url: "https://auth.example.com/.well-known/jwks.json"
issuer: "https://auth.example.com"
audience: "hector-api"
agents:
# Public agent (JWT only)
public_agent:
llm: "gpt-4o"
# Protected agent (JWT + API key)
admin_agent:
llm: "gpt-4o"
security:
schemes:
api_key:
type: "apiKey"
name: "X-Admin-Key"
in: "header"
require:
- api_key
Requests:
# Public agent: JWT required (global auth)
curl -H "Authorization: Bearer $JWT" \
http://localhost:8080/agents/public_agent/tasks
# Admin agent: JWT + API key required
curl -H "Authorization: Bearer $JWT" \
-H "X-Admin-Key: admin-key" \
http://localhost:8080/agents/admin_agent/tasks
Authenticating to External A2A Agents¶
When calling external A2A agents, provide their credentials:
agents:
# Local coordinator
coordinator:
llm: "gpt-4o"
tools: ["agent_call"]
# External agent with Bearer token
external_researcher:
type: "a2a"
url: "https://external-agent.example.com"
credentials:
type: "bearer"
token: "${EXTERNAL_AGENT_TOKEN}"
# External agent with API key
external_analyst:
type: "a2a"
url: "https://analyst.example.com"
credentials:
type: "api_key"
key: "${ANALYST_API_KEY}"
header: "X-API-Key"
# External agent with Basic auth
external_writer:
type: "a2a"
url: "https://writer.example.com"
credentials:
type: "basic"
username: "${WRITER_USER}"
password: "${WRITER_PASS}"
Environment variables:
export EXTERNAL_AGENT_TOKEN="bearer-token-here"
export ANALYST_API_KEY="api-key-here"
export WRITER_USER="username"
export WRITER_PASS="password"
See How to Integrate External Agents for details.
Security Best Practices¶
1. Use Environment Variables¶
Never hardcode secrets:
# ✅ Good
global:
auth:
jwks_url: "${JWKS_URL}"
issuer: "${AUTH_ISSUER}"
audience: "${AUTH_AUDIENCE}"
agents:
external:
type: "a2a"
credentials:
token: "${EXTERNAL_TOKEN}"
# ❌ Bad
global:
auth:
jwks_url: "https://hardcoded-url.com/jwks.json"
agents:
external:
credentials:
token: "hardcoded-token-123"
2. Use HTTPS in Production¶
global:
a2a_server:
tls:
cert_file: "/path/to/cert.pem"
key_file: "/path/to/key.pem"
Or use a reverse proxy (nginx, Caddy, Traefik).
3. Rotate Credentials Regularly¶
- Rotate API keys periodically
- Use short-lived JWT tokens
- Implement token refresh flows
- Monitor for compromised credentials
4. Principle of Least Privilege¶
agents:
# Public access (read-only)
public_reader:
llm: "gpt-4o"
# No additional security
# Authenticated access
authenticated_writer:
llm: "gpt-4o"
security:
schemes:
bearer:
type: "http"
scheme: "bearer"
require:
- bearer
# Admin access (JWT + API key)
admin:
llm: "gpt-4o"
security:
schemes:
bearer:
type: "http"
scheme: "bearer"
admin_key:
type: "apiKey"
name: "X-Admin-Key"
in: "header"
require:
- bearer
- admin_key
5. Monitor and Log¶
logging:
level: "info"
format: "json"
# Log authentication attempts
log_auth: true
Common Scenarios¶
Public API with Authentication¶
global:
auth:
jwks_url: "${JWKS_URL}"
issuer: "${ISSUER}"
audience: "public-api"
agents:
chatbot:
llm: "gpt-4o"
# No additional security
All agents require JWT token.
Mixed Public/Private Agents¶
# No global auth
agents:
# Public agent
public:
llm: "gpt-4o"
# Private agent
private:
llm: "gpt-4o"
security:
schemes:
bearer:
type: "http"
scheme: "bearer"
require:
- bearer
Public agent accessible to all, private agent requires token.
Multi-Tenant System¶
global:
auth:
jwks_url: "${JWKS_URL}"
issuer: "${ISSUER}"
audience: "multi-tenant"
agents:
tenant_agent:
llm: "gpt-4o"
security:
schemes:
tenant_key:
type: "apiKey"
name: "X-Tenant-ID"
in: "header"
require:
- tenant_key
prompt:
system_role: |
You are assisting tenant: ${tenant_id}
Respect tenant boundaries.
Debugging Authentication¶
Enable Debug Logging¶
logging:
level: "debug"
log_auth: true
Test Authentication¶
# Without token (should fail)
curl http://localhost:8080/agents/protected/tasks
# Expected: 401 Unauthorized
# With invalid token (should fail)
curl -H "Authorization: Bearer invalid" \
http://localhost:8080/agents/protected/tasks
# Expected: 401 Unauthorized
# With valid token (should work)
curl -H "Authorization: Bearer $VALID_TOKEN" \
http://localhost:8080/agents/protected/tasks
# Expected: 200 OK
Check JWKS¶
# Verify JWKS is accessible
curl https://your-provider.com/.well-known/jwks.json
# Should return JSON with keys:
# {"keys": [{"kty": "RSA", "kid": "...", ...}]}
Next Steps¶
- How to Deploy to Production - Production security setup
- How to Integrate External Agents - External agent authentication
- API Reference - Authentication headers and responses
- Configuration Reference - All security options
Related Topics¶
- Agent Overview - Understanding agents
- Sessions - Session-based authentication
- Multi-Agent - Secure multi-agent systems