a2a-agents 0.7.0

Framework for building A2A Protocol agents with declarative configuration
Documentation
# Authenticating an agent's HTTP surface.
#
# One config with every `[server.auth]` shape written out: the JWT block is live,
# the other three are commented alternatives. Swap whichever you want in — only
# one `[server.auth]` can be active, since `type` selects the whole block.
#
#   a2a validate --config a2a-agents/examples/auth.toml
#   JWT_SECRET=dev-secret a2a run --config a2a-agents/examples/auth.toml
#
# Needs the `auth` feature: `cargo run -p a2a-agents --features auth --bin a2a`.
# Secrets are environment references so the config can be committed; `a2a
# validate` checks the shape without them, `a2a run` requires them to resolve.
#
# One gotcha this file demonstrates: an environment reference inside a *comment*
# still counts. The scanner reads the raw text — it has to, since the allowlist
# is checked before the config is parsed — so `a2a validate` lists the commented
# blocks' variables below as unset, and a control plane would require them under
# `--allow-env`. Delete the alternatives you are not using.

[agent]
name = "Secure Agent"
description = "An agent that requires a credential."

[handler]
type = "echo"

[server]
host = "127.0.0.1"
http_port = 8080

[server.storage]
type = "inmemory"

# --- JWT --------------------------------------------------------------------
# Verifies a bearer JWT. HMAC (HS*) takes a shared `secret`; RSA (RS*) takes the
# path to a public key. `issuer` and `audience` are optional and checked only
# when set — leaving them out accepts any token the key validates, which is
# rarely what a production deployment wants.
[server.auth]
type = "jwt"
secret = "${JWT_SECRET}"
algorithm = "HS256"                    # HS256 | HS384 | HS512 | RS256 | RS384 | RS512
issuer = "https://auth.example.com"
audience = "api://my-agent"

# RSA instead of a shared secret — replace `secret` with:
# rsa_pem_path = "/etc/agent/jwt-public.pem"
# algorithm = "RS256"

# --- Bearer tokens ----------------------------------------------------------
# A fixed list of accepted tokens. No expiry, no revocation, no claims: fine for
# a service-to-service link you control, wrong for anything user-facing.
#
# [server.auth]
# type = "bearer"
# tokens = ["${AGENT_TOKEN}"]
# format = "JWT"                       # advertised on the agent card, optional

# --- API key ----------------------------------------------------------------
# Same trade-off as bearer, carried somewhere else. `location` is header, query,
# or cookie; `name` is the header/param it is read from.
#
# [server.auth]
# type = "api_key"
# keys = ["${AGENT_API_KEY}"]
# location = "header"
# name = "X-API-Key"

# --- OAuth2 -----------------------------------------------------------------
# `flow = "authorization_code"` is the interactive flow and needs `redirect_url`;
# `flow = "client_credentials"` is machine-to-machine and ignores it (the
# `authorization_url` is still required by the schema and unused).
#
# Endpoints for common providers:
#   GitHub     https://github.com/login/oauth/authorize
#              https://github.com/login/oauth/access_token
#   Google     https://accounts.google.com/o/oauth2/v2/auth
#              https://oauth2.googleapis.com/token
#   Azure AD   https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
#              https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
#   Keycloak   https://{host}/realms/{realm}/protocol/openid-connect/auth
#              https://{host}/realms/{realm}/protocol/openid-connect/token
#
# [server.auth]
# type = "oauth2"
# client_id = "${OAUTH_CLIENT_ID}"
# client_secret = "${OAUTH_CLIENT_SECRET}"
# authorization_url = "https://provider.example.com/oauth/authorize"
# token_url = "https://provider.example.com/oauth/token"
# flow = "authorization_code"          # or "client_credentials"
# redirect_url = "http://localhost:8080/oauth/callback"
# scopes = ["read", "write"]

[[skills]]
id = "secure-echo"
name = "Secure echo"
description = "Echoes a message back, for callers holding a valid credential."
examples = ["hello"]