Skip to main content

A2A Authentication

The A2A protocol supports two authentication methods for securing agent-to-agent communication:

Tip: When testing OAuth2 authentication, use version 0.2.7 or greater of the agent-chat-cli to ensure the Authorization: Bearer <token> header is sent correctly.

Usage:

docker run -it --network=host ghcr.io/cnoe-io/agent-chat-cli:0.2.7

Public Endpoints​

All authentication methods allow public access to the following endpoints without authentication:

  • <A2A_HOST>/.well-known/agent.json
  • <A2A_HOST>/.well-known/agent-card.json

These endpoints provide agent discovery and metadata information.

Shared Key Authentication​

Shared key authentication provides a simple authentication mechanism using a pre-shared secret. This method is suitable for development and testing environments.

Configuration:

  • Set the following required environment variable:
    • A2A_AUTH_SHARED_KEY: The shared secret key for authentication

Usage:

  • Send the shared key as Authorization: Bearer <shared_key> header
  • The key must match exactly with the configured A2A_AUTH_SHARED_KEY value

OAuth2 Authentication​

OAuth2 authentication provides enterprise-grade security using JWT tokens with JWKS validation. This method is recommended for production environments.

Configuration:

  • Set A2A_AUTH_OAUTH2=true in your environment
  • Configure the following required environment variables:
    • JWKS_URI: The JWKS endpoint URL for token validation
    • AUDIENCE: Expected audience claim in the JWT token
    • ISSUER: Expected issuer claim in the JWT token
    • OAUTH2_CLIENT_ID: Client ID for audience validation

Token Requirements:

  • Must be a valid JWT token with RS256 or EC256 signature
  • Must include iss, aud, exp, and nbf claims
  • Optional cid claim for additional client validation
  • Must be sent as Authorization: Bearer <token> header

Getting OAuth2 Tokens:

You can use the provided utility script to obtain OAuth2 JWT tokens:

python ai_platform_engineering/utils/oauth/get_oauth_jwt_token.py

This script requires the following environment variables:

  • OAUTH2_CLIENT_ID: Your OAuth2 client ID
  • OAUTH2_CLIENT_SECRET: Your OAuth2 client secret
  • TOKEN_ENDPOINT: The OAuth2 token endpoint URL

The script will:

  • Validate your environment configuration
  • Obtain a JWT access token using client credentials flow
  • Display token contents and expiration status
  • Check if the token is expired or about to expire

Local Development with Keycloak:

For local development and testing, you can use the provided Keycloak setup:

# Start local Keycloak OAuth server
cd deploy/keycloak
docker compose up

Keycloak Configuration:

  1. Access admin console at http://localhost:7080
  2. Login with admin/admin
  3. Switch to the caipe realm
  4. Create a client called caipe-cli
  5. Copy the client secret

Environment Variables for Local Keycloak:

A2A_AUTH_OAUTH2=true
JWKS_URI=http://localhost:7080/realms/caipe/protocol/openid-connect/certs
AUDIENCE=caipe
ISSUER=http://localhost:7080/realms/caipe
OAUTH2_CLIENT_ID=caipe-cli
OAUTH2_CLIENT_SECRET=your-client-secret-from-keycloak
TOKEN_ENDPOINT=http://localhost:7080/realms/caipe/protocol/openid-connect/token

Generate JWT Token with Keycloak:

export OAUTH2_CLIENT_ID=caipe-cli
export OAUTH2_CLIENT_SECRET=<YOUR CLIENT SECRET> # randomly generated from Keycloak
export TOKEN_ENDPOINT=http://localhost:7080/realms/caipe/protocol/openid-connect/token

python ai_platform_engineering/utils/oauth/get_oauth_jwt_token.py

Keycloak OAuth Server Setup​

This section provides comprehensive instructions for setting up and configuring Keycloak as an OAuth2 server for CAIPE A2A authentication.

Quick Start​

  1. Start Keycloak Server

    cd deploy/keycloak
    docker compose up
  2. Access Admin Console

  3. Configure Realm

    • The caipe realm is automatically imported from caipe-realm.json
    • Switch to the caipe realm in the admin console

Client Configuration​

Create OAuth2 Client​

  1. In the Keycloak admin console, navigate to the caipe realm

  2. Go to Clients → Create

  3. Configure the client:

    • Client ID: caipe-cli
    • Client Protocol: openid-connect
    • Access Type: confidential
    • Standard Flow Enabled: ON
    • Direct Access Grants Enabled: ON
    • Service Accounts Enabled: ON
  4. Save the client and go to the Credentials tab

  5. Copy the Secret value for use in your environment

Client Scopes​

The following scopes are available in the caipe realm:

  • profile - User profile information
  • email - User email address
  • caipe - CAIPE-specific audience claim

Token Validation​

The A2A middleware validates JWT tokens using:

  • Signature verification via JWKS endpoint
  • Audience validation (must match caipe)
  • Issuer validation (must match Keycloak realm)
  • Expiration validation (exp and nbf claims)
  • Client ID validation (optional cid claim)

Realm Configuration​

The caipe-realm.json file includes:

  • Pre-configured realm with caipe as the realm name
  • Default user caipe with password caipe
  • Client scopes for profile, email, and CAIPE audience
  • Security policies and authentication flows

Production Considerations​

For production deployments:

  1. Change default passwords
  2. Use HTTPS endpoints
  3. Configure proper CORS settings
  4. Set up proper SSL certificates
  5. Configure database persistence
  6. Set up proper logging and monitoring

Troubleshooting​

Common Issues​

  1. Token validation fails

    • Check JWKS_URI is accessible
    • Verify AUDIENCE matches realm configuration
    • Ensure ISSUER matches Keycloak realm URL
  2. Client authentication fails

    • Verify OAUTH2_CLIENT_ID exists in Keycloak
    • Check OAUTH2_CLIENT_SECRET is correct
    • Ensure client has proper permissions
  3. Token generation fails

    • Verify TOKEN_ENDPOINT is correct
    • Check client credentials are valid
    • Ensure client has service account enabled

Debug Mode​

Enable debug logging to troubleshoot issues:

export DEBUG_UNMASK_AUTH_HEADER=true

This will show unmasked authorization headers in the logs (use only for debugging).