Skip to main content
When using agent.serve(), you can protect HTTP endpoints with authentication. Set agent.auth to an auth provider and all requests to /run and webhook endpoints require valid credentials.

API Key Authentication

from definable.agent.auth import APIKeyAuth

agent.auth = APIKeyAuth(keys={"sk-my-secret-key"})
agent.serve(port=8000)
Clients send the key via the X-API-Key header or the Authorization: Bearer <key> header:
# X-API-Key header
curl -X POST http://localhost:8000/run \
  -H "X-API-Key: sk-my-secret-key" \
  -H "Content-Type: application/json" \
  -d '{"input": "Hello"}'

# Or Authorization header
curl -X POST http://localhost:8000/run \
  -H "Authorization: Bearer sk-my-secret-key" \
  -H "Content-Type: application/json" \
  -d '{"input": "Hello"}'
keys
str | Set[str]
required
A single API key or a set of allowed keys.
header
str
default:"X-API-Key"
HTTP header name to read the key from. Falls back to the Authorization header if the primary header is empty.
User ID is derived from the key hash: apikey_<sha256[:12]>.

JWT Authentication

from definable.agent.auth import JWTAuth

agent.auth = JWTAuth(secret="your-secret-key")
agent.serve(port=8000)
Clients send a Bearer token in the Authorization header:
curl -X POST http://localhost:8000/run \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{"input": "Hello"}'
secret
str
required
Secret key or public key for token validation.
algorithm
str
default:"HS256"
JWT algorithm.
audience
str
Expected audience claim.
issuer
str
Expected issuer claim.
User ID is extracted from token claims, checking sub, then user_id, then id. Remaining claims are available in AuthContext.metadata.
Requires pyjwt: pip install pyjwt or pip install 'definable[jwt]'

Allowlist Authentication

For messaging interfaces (Telegram, Discord), use AllowlistAuth to restrict access by user ID:
from definable.agent.auth import AllowlistAuth

agent.auth = AllowlistAuth(
  user_ids={"user-123", "user-456"},
  platforms={"telegram"},
)
user_ids
Set[str]
required
Set of allowed user IDs.
chat_ids
Set[str]
Optional set of allowed chat/group IDs.
platforms
Set[str]
Optional platform filter. When set, the provider only applies to requests from these platforms (e.g., {"telegram", "discord"}). Returns None for other platforms.
AllowlistAuth only applies to AuthRequest instances (messages from interfaces). It returns None for raw HTTP requests, making it safe to combine with API key auth.

Composite Authentication

Chain multiple providers with CompositeAuth. It tries each in order and returns the first successful result:
from definable.agent.auth import APIKeyAuth, AllowlistAuth, CompositeAuth

agent.auth = CompositeAuth(
  APIKeyAuth(keys={"sk-my-api-key"}),
  AllowlistAuth(user_ids={"user-123"}, platforms={"telegram"}),
)
This is the recommended pattern for agents that serve both HTTP endpoints and messaging interfaces — API keys protect /run while the allowlist controls messaging access.
*providers
AuthProvider
One or more auth providers. At least one is required. Supports mixed sync/async providers.

Per-Webhook Auth Override

Individual webhooks can override the agent-level auth:
@agent.on(Webhook("/public-hook", auth=False))    # No auth required
async def public(event): ...

@agent.on(Webhook("/private-hook"))                # Uses agent.auth
async def private(event): ...

AuthContext

When authentication succeeds, the provider returns an AuthContext:
FieldTypeDescription
user_idstrCanonical user identifier
metadataDict[str, Any]Extra claims or info from the provider

Custom Auth Provider

Implement the AuthProvider protocol to create your own auth backend:
from definable.agent.auth import AuthProvider, AuthContext

class MyAuth:
  async def authenticate(self, request) -> AuthContext | None:
    token = request.headers.get("X-Custom-Token")
    if verify(token):
      return AuthContext(user_id="user-123", metadata={"role": "admin"})
    return None

agent.auth = MyAuth()
The authenticate method can be sync or async. Return AuthContext on success, None on failure (returns 401).

Auth Bypass

  • /health is always public
  • Webhooks with auth=False bypass authentication
  • In dev mode, /docs, /redoc, and /openapi.json are also public