Behaviour for authenticating an inbound A2A request at the transport boundary.
Hosts wire an A2aEngine.Auth implementation into each transport so
request dispatch can either:
- succeed with an
auth_contextthat downstream handlers can inspect, or - reject the request without touching the handler.
Built-in implementations
A2aEngine.Auth.Bearer— shared-secret tokens (with allowlist or custom validator). Day-1 default for external peers.A2aEngine.Auth.Localhost— same-host bypass. Trusts requests whose peer socket is127.0.0.1or::1.
OAuth2 / OIDC implementations slot in later as additional modules without changing the behaviour.
request_info shape
The transport layer normalises the incoming request into a uniform map before handing it to the auth impl:
%{
headers: %{"authorization" => "Bearer ..."},
peer: {:tcp, {127, 0, 0, 1}} | {:beam, :"app@host"} | :local,
transport: :http | :beam_native
}auth_context shape
On success, the impl returns an auth_context that travels into
handler calls:
%{
scheme: :bearer | :localhost | :anonymous | atom(),
principal: "agent_name" | nil,
extra: %{...} # impl-specific
}Error kinds
On rejection, impls return {:error, :unauthenticated | :forbidden}.
Transports translate to HTTP 401/403 (for HTTP) or a JSON-RPC
invalid-request / internal-error envelope (for BeamNative).
Summary
Functions
Shortcut for building an auth_context with defaults filled in.
Types
@type request_info() :: %{ headers: %{required(String.t()) => String.t()}, peer: {:tcp, :inet.ip_address()} | {:beam, node()} | :local, transport: :http | :beam_native }
Callbacks
@callback authenticate(request_info(), opts :: keyword()) :: {:ok, auth_context()} | {:error, error()}
Functions
@spec context(atom(), String.t() | nil, map()) :: auth_context()
Shortcut for building an auth_context with defaults filled in.