What this is
The Agent-to-Agent (A2A) protocol carries tasks between agents over HTTP. AIP adds an identity layer: every task carries a chained token in metadata.aip_token, the receiver verifies the signature chain and scope, and the agent card declares the receiver's AIP identifier so callers know who they're talking to. No shared secrets. No bearer tokens that can be stolen and replayed.
Install
pip install agent-identity-protocol>=0.3.0
Generate an Ed25519 keypair for your agent:
python -c "from aip_core.crypto import KeyPair; kp = KeyPair.generate(); print('pub:', kp.public_key_bytes().hex()); open('agent.sk','wb').write(kp.private_key_bytes())"
Server side — verify incoming tasks
Wrap your task handler in A2AVerifyMiddleware. The middleware extracts the token from metadata.aip_token, verifies the chain, checks audience and scope, and only then calls your handler.
from aip_a2a import A2AVerifyMiddleware
OWN_ID = "aip:web:acme.com/researcher"
ROOT_PUBKEY = bytes.fromhex("...") # the orchestrator's pubkey
def handle_task(body, *, context):
# context.subject == OWN_ID, context.chain_depth, context.issuer
print(f"verified caller chain depth={context.chain_depth}")
return {"jsonrpc": "2.0", "result": "..."}
middleware = A2AVerifyMiddleware(
handle_task,
own_aip_id=OWN_ID,
root_public_key_bytes=ROOT_PUBKEY,
required_scope="research:read",
)
# Use middleware(parsed_request_body) inside your A2A server.
Client side — forward a task with delegation
Before calling another A2A agent, append a delegation block that attenuates scope:
from aip_a2a import append_delegation_block
extended = append_delegation_block(
incoming_token, # your verified token
delegator="aip:web:acme.com/researcher",
delegate="aip:web:acme.com/writer", # the next agent
scopes=["write:draft"], # narrowed
context="draft-summary",
budget_cents=50,
)
body = {
"jsonrpc": "2.0",
"method": "tasks/send",
"params": {
"task_id": "task-2",
"message": {"role": "user", "parts": [{"text": "..."}]},
"metadata": {"aip_token": extended.to_base64()},
},
}
Agent card extension
Your agent card MUST include an aip_identity extension so callers can resolve your identity document and verify mutual auth (when used).
{
"name": "Researcher",
"skills": ["research"],
"aip_identity": {
"id": "aip:web:acme.com/researcher",
"document_url": "https://acme.com/.well-known/aip/agents/researcher.json"
}
}
For the full normative requirements, see spec §A2A binding.
Try to break it
Run the working example:
git clone https://github.com/sunilp/aip
cd aip/examples/a2a-multi-agent
./run.sh
Then try these:
- Tamper with the token (flip a byte in the base64). The receiver returns
{"error":{"code":"aip_chain_invalid"},"status":401}. - Set
required_scope="delete"in the writer. Verification fails withaip_scope_insufficient. - Set
own_aip_idon the writer to a different identifier. Verification fails withaip_audience_mismatch.
Next
For multi-hop delegation, see the chained delegation guide. For the full normative spec, see /aip/spec/.