Skip to content

A2A Delegation

Agent-to-Agent Delegation (A2A Auth)

When Agent A tells Agent B to perform an action, both sides must be authorised. Xybern intermediates every agent-to-agent interaction with bidirectional authorisation, scope attenuation, and cryptographic delegation grants recorded in the Provenance Vault.

Info

Why this matters: Multi-agent frameworks (CrewAI, AutoGen, LangGraph) let agents freely call each other with zero authorisation. Xybern ensures Agent A is authorised to delegate, Agent B is authorised to accept, and the delegated scopes are the intersection of both, not a superset.

Core Concepts

Concept Description
delegation_policy Per-agent config: can_delegate, can_accept_delegation, delegable_scopes, acceptable_scopes, max_delegation_depth
Scope Attenuation Granted scopes = source's delegable ∩ target's acceptable ∩ requested. Wildcards supported (trade:*).
Delegation Grant First-class verifiable token (dlg_...) that the target agent presents when acting on behalf of the source.
Delegation Chains Agent B can re-delegate to Agent C if depth allows. Max depth enforced, cascading revocation propagates down the chain.

Register Agents with Delegation Policy

import requests

BASE = "https://xybern.com/api/v1"
HEADERS = {"X-API-Key": "xb_...", "Content-Type": "application/json"}

# Source agent — can delegate trade:read and db:read
requests.post(f"{BASE}/enforce/agents", headers=HEADERS, json={
    "name": "finance-agent",
    "framework": "crewai",
    "permissions": {"allowed_action_types": ["execute_trade", "query_database"]},
    "scopes": ["trade:write", "trade:read", "db:read", "agent:delegate"],
    "delegation_policy": {
        "can_delegate": True,
        "can_accept_delegation": False,
        "delegable_scopes": ["trade:read", "db:read"],
        "max_delegation_depth": 3
    }
})

# Target agent — accepts trade:read and db:read
requests.post(f"{BASE}/enforce/agents", headers=HEADERS, json={
    "name": "analyst-agent",
    "framework": "crewai",
    "permissions": {"allowed_action_types": ["query_database", "read_data"]},
    "scopes": ["trade:read", "db:read"],
    "delegation_policy": {
        "can_delegate": False,
        "can_accept_delegation": True,
        "acceptable_scopes": ["trade:read", "db:read"]
    }
})

POST /v1/enforce/delegate

Request a delegation grant from one agent to another.

resp = requests.post(f"{BASE}/enforce/delegate", headers=HEADERS, json={
    "source_agent_id": "agent_abc123",
    "target_agent_id": "agent_def456",
    "scopes": ["trade:read", "db:read"],
    "action_types": ["query_database"],
    "constraints": {"max_amount": 100000},
    "instruction": "Analyse Q1 trading performance",
    "ttl_hours": 12,
    "max_uses": 5
})

grant = resp.json()["grant"]
# grant["grant_id"]          → "dlg_42eb33adab69"
# grant["attenuated_scopes"] → ["db:read", "trade:read"]
# grant["delegation_depth"]  → 1
# grant["vault_entry_id"]    → "ve_590dba34..."

POST /v1/enforce/delegate/verify

Verify a delegation grant before executing an action.

resp = requests.post(f"{BASE}/enforce/delegate/verify", headers=HEADERS, json={
    "grant_id": "dlg_42eb33adab69",
    "agent_id": "agent_def456",
    "action_type": "query_database"
})
# resp.json()["valid"]  → True
# resp.json()["reason"] → "Grant verified"

Using a Grant with Intercept

Pass grant_id to /enforce/intercept so the control plane verifies the delegation before policy evaluation.

resp = requests.post(f"{BASE}/enforce/intercept", headers=HEADERS, json={
    "action_type": "query_database",
    "action_content": "SELECT * FROM trades WHERE quarter='Q1'",
    "agent_id": "agent_def456",
    "grant_id": "dlg_42eb33adab69",
    "metadata": {"table": "trades", "operation": "read"}
})
# If grant is invalid or revoked → decision: "block"
# If grant is valid → normal policy evaluation proceeds

POST /v1/enforce/delegate/{grant_id}/revoke

Revoke a grant with cascading, all child grants in the delegation chain are revoked automatically.

resp = requests.post(f"{BASE}/enforce/delegate/dlg_42eb33adab69/revoke",
    headers=HEADERS, json={"reason": "task_complete"})
# resp.json()["revoked_count"]  → 1
# resp.json()["revoked_grants"] → ["dlg_42eb33adab69"]

GET /v1/enforce/delegations

List all delegation grants for the workspace. Filter by status (active, revoked, expired) or agent_id.

curl -H "X-API-Key: xb_..." \
  "https://xybern.com/api/v1/enforce/delegations?status=active"

Delegation Policies

Create enforcement policies of type delegation to control A2A behaviour at the workspace level.

requests.post(f"{BASE}/enforce/policies", headers=HEADERS, json={
    "name": "Block Finance→Marketing delegation",
    "policy_type": "delegation",
    "decision": "block",
    "conditions": {
        "blocked_pairs": [["agent_finance", "agent_marketing"]],
        "max_depth": 2,
        "blocked_scopes": ["payments:execute"]
    }
})