Skip to main content

Overview

Handler supports two authentication schemes for communicating with protected A2A agents:
  • Bearer Token: OAuth-style token in the Authorization header
  • API Key: Custom or standard API key header (default: X-API-Key)
Authentication credentials can be configured via the TUI, CLI options, or saved to session storage for automatic reuse.

Authentication Types

Handler implements authentication through the AuthCredentials class:
@dataclass
class AuthCredentials:
    """Authentication credentials for an agent.
    
    Stores the credential value and metadata about how to apply it.
    """
    
    auth_type: AuthType
    value: str
    header_name: str | None = None  # For API key: custom header name
    
    def to_headers(self) -> dict[str, str]:
        """Generate HTTP headers for this credential.
        
        Returns:
            Dictionary of headers to include in requests
        """
        if self.auth_type == AuthType.BEARER:
            return {"Authorization": f"Bearer {self.value}"}
        elif self.auth_type == AuthType.API_KEY:
            header = self.header_name or "X-API-Key"
            return {header: self.value}
        return {}

Using Bearer Token Authentication

Bearer tokens are commonly used with OAuth 2.0 and JWT-based authentication.
Pass the token directly with each command:
handler message send \
  --url http://localhost:8000 \
  --bearer-token "your-token-here" \
  "Hello!"
Or save the token to your session:
handler auth set \
  --url http://localhost:8000 \
  --bearer-token "your-token-here"

# Future commands use the saved token automatically
handler message send --url http://localhost:8000 "Hello!"

How Bearer Tokens Work

When you set a bearer token, Handler adds it to the Authorization header:
auth.py:60-62
def create_bearer_auth(token: str) -> AuthCredentials:
    """Create bearer token authentication."""
    return AuthCredentials(auth_type=AuthType.BEARER, value=token)
HTTP request:
POST /a2a/v1/messages HTTP/1.1
Host: localhost:8000
Authorization: Bearer your-token-here
Content-Type: application/json

Using API Key Authentication

API key authentication allows custom header names for flexibility with different agent implementations.
Using the default X-API-Key header:
handler message send \
  --url http://localhost:8000 \
  --api-key "your-api-key" \
  "Hello!"
Using a custom header name:
handler message send \
  --url http://localhost:8000 \
  --api-key "your-api-key" \
  --api-key-header "X-Custom-API-Key" \
  "Hello!"
Save to session:
handler auth set \
  --url http://localhost:8000 \
  --api-key "your-api-key"

How API Keys Work

API key credentials are sent in a custom header:
auth.py:65-79
def create_api_key_auth(
    key: str,
    header_name: str = "X-API-Key",
) -> AuthCredentials:
    """Create API key authentication.
    
    Args:
        key: The API key value
        header_name: Header name to use (default: X-API-Key)
    """
    return AuthCredentials(
        auth_type=AuthType.API_KEY,
        value=key,
        header_name=header_name,
    )
HTTP request:
POST /a2a/v1/messages HTTP/1.1
Host: localhost:8000
X-API-Key: your-api-key
Content-Type: application/json

Credential Application

Credentials are applied to HTTP requests through the A2AService:
def set_credentials(self, credentials: AuthCredentials) -> None:
    """Set or update authentication credentials.
    
    Args:
        credentials: Authentication credentials to apply
    """
    # Remove old auth headers
    for header_name in self._applied_auth_headers:
        self.http_client.headers.pop(header_name, None)
    self._applied_auth_headers.clear()
    
    # Apply new credentials
    self.credentials = credentials
    auth_headers = credentials.to_headers()
    self.http_client.headers.update(auth_headers)
    self._applied_auth_headers = set(auth_headers.keys())
    logger.debug("Applied authentication headers: %s", list(auth_headers.keys()))

Saving Credentials to Sessions

Persist credentials across Handler invocations using session storage.
1

Set credentials

handler auth set \
  --url http://localhost:8000 \
  --bearer-token "your-token"
2

Verify storage

Credentials are saved to ~/.handler/sessions.json:
{
  "http://localhost:8000": {
    "context_id": "ctx-123",
    "task_id": "task-456",
    "credentials": {
      "auth_type": "bearer",
      "value": "your-token",
      "header_name": null
    }
  }
}
Implementation in session.py:104-109:
data: dict[str, Any] = {
    "context_id": agent_session.context_id,
    "task_id": agent_session.task_id,
}
if agent_session.credentials:
    data["credentials"] = agent_session.credentials.to_dict()
3

Use automatically

Future commands automatically load credentials:
# No --bearer-token needed
handler message send --url http://localhost:8000 "Hello!"

Managing Credentials

List sessions with credential status:
handler session list
Output:
Saved Sessions (2)

http://localhost:8000
  Context ID: ctx-abc123
  Task ID: task-xyz789
  Credentials: Yes

http://example.com
  Context ID: ctx-def456
  Credentials: No

Security Considerations

Credential Storage SecurityCredentials in ~/.handler/sessions.json are stored in plain text. Ensure:
  • File permissions are restrictive (chmod 600 ~/.handler/sessions.json)
  • Sessions file is excluded from version control
  • Production credentials use environment variables or secret managers
  • Rotate credentials regularly
For enhanced security in production:
  • Use short-lived tokens when possible
  • Store credentials in environment variables
  • Pass credentials via CLI flags instead of persisting
  • Implement token refresh mechanisms

Authentication Required State

Agents can signal that authentication is required:
service.py:91-93
@property
def needs_auth(self) -> bool:
    """Check if the task requires authentication."""
    return self.state == TaskState.auth_required if self.state else False
When a task enters auth-required state:
  1. Configure authentication credentials
  2. Resend the message or continue the task
  3. The agent processes the request with credentials

Next Steps