docs: commit all Phase 6 documentation updates and OpenSpec archives
- devops docs: 8 files updated for Phase 6 state; field-trial.md added (946-line runbook) - developer docs: api-reference (50+ endpoints), quick-start, 5 existing guides updated, 5 new guides added - engineering docs: all 12 files updated (services, architecture, SDK guide, testing, overview) - OpenSpec archives: phase-7-devops-field-trial, developer-docs-phase6-update, engineering-docs-phase6-update - VALIDATOR.md + scripts/start-validator.sh: V&V Architect tooling added - .gitignore: exclude session artifacts, build artifacts, and agent workspaces Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
167
docs/developers/guides/a2a-delegation.md
Normal file
167
docs/developers/guides/a2a-delegation.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# A2A Delegation
|
||||
|
||||
Agent-to-Agent (A2A) delegation lets one agent grant another agent a subset of its OAuth 2.0
|
||||
scopes for a defined period. This is the foundation for building secure multi-agent pipelines
|
||||
where an orchestrator agent coordinates specialist sub-agents.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A running AgentIdP instance
|
||||
- Two registered agents: the delegator (has a Bearer token) and the delegatee (knows its
|
||||
`agentId`)
|
||||
- The delegator's scopes must be a superset of the scopes it wants to delegate
|
||||
|
||||
---
|
||||
|
||||
## How delegation works
|
||||
|
||||
```
|
||||
Delegator agent Delegatee agent
|
||||
| |
|
||||
|-- POST /oauth2/token/delegate ----------->| (creates chain server-side)
|
||||
|<-- { delegationToken, chainId, scopes } --|
|
||||
| |
|
||||
|-- passes delegationToken out-of-band ---->|
|
||||
| |
|
||||
| POST /oauth2/token/verify-delegation
|
||||
| <-- { valid: true, scopes, expiresAt }
|
||||
| |
|
||||
| (optional) DELETE /oauth2/token/delegate/{chainId}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Create a delegation chain
|
||||
|
||||
The delegator agent creates the chain by specifying the delegatee's `agentId`, the scopes to
|
||||
delegate (must be a strict subset of the delegator's own scopes), and the TTL in seconds.
|
||||
|
||||
```bash
|
||||
curl -s -X POST http://localhost:3000/api/v1/oauth2/token/delegate \
|
||||
-H "Authorization: Bearer $DELEGATOR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"delegateeAgentId": "'$DELEGATEE_AGENT_ID'",
|
||||
"scopes": ["agents:read"],
|
||||
"ttlSeconds": 3600
|
||||
}' | jq .
|
||||
```
|
||||
|
||||
Response (`201 Created`):
|
||||
|
||||
```json
|
||||
{
|
||||
"delegationToken": "sa_del_a1b2c3d4e5f6...",
|
||||
"chainId": "d4e5f6a7-b8c9-0123-def0-123456789abc",
|
||||
"delegatorAgentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"delegateeAgentId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
|
||||
"scopes": ["agents:read"],
|
||||
"expiresAt": "2026-04-04T10:00:00.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
Save the `delegationToken` and `chainId`:
|
||||
|
||||
```bash
|
||||
export DELEGATION_TOKEN="sa_del_a1b2c3d4e5f6..."
|
||||
export CHAIN_ID="d4e5f6a7-b8c9-0123-def0-123456789abc"
|
||||
```
|
||||
|
||||
**TTL constraints**: minimum 60 seconds, maximum 86400 seconds (24 hours). Choose the minimum
|
||||
TTL that covers the delegatee's task.
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Pass the delegation token to the delegatee
|
||||
|
||||
Pass `DELEGATION_TOKEN` to the delegatee agent out-of-band. This can be via a shared queue,
|
||||
a direct API call to the sub-agent, or any other channel. The token is a signed opaque string —
|
||||
do not parse it; treat it as an opaque credential.
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Verify the delegation token
|
||||
|
||||
The delegatee (or any agent checking the delegation) calls the verify endpoint. This confirms
|
||||
the chain is valid and not expired or revoked.
|
||||
|
||||
```bash
|
||||
curl -s -X POST http://localhost:3000/api/v1/oauth2/token/verify-delegation \
|
||||
-H "Authorization: Bearer $DELEGATEE_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{ "delegationToken": "'$DELEGATION_TOKEN'" }' | jq .
|
||||
```
|
||||
|
||||
Response (`200 OK` — valid delegation):
|
||||
|
||||
```json
|
||||
{
|
||||
"valid": true,
|
||||
"chainId": "d4e5f6a7-b8c9-0123-def0-123456789abc",
|
||||
"delegatorAgentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"delegateeAgentId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
|
||||
"scopes": ["agents:read"],
|
||||
"issuedAt": "2026-04-04T09:00:00.000Z",
|
||||
"expiresAt": "2026-04-04T10:00:00.000Z",
|
||||
"revokedAt": null
|
||||
}
|
||||
```
|
||||
|
||||
Response (`200 OK` — expired delegation):
|
||||
|
||||
```json
|
||||
{
|
||||
"valid": false,
|
||||
"chainId": "d4e5f6a7-b8c9-0123-def0-123456789abc",
|
||||
"delegatorAgentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"delegateeAgentId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
|
||||
"scopes": ["agents:read"],
|
||||
"issuedAt": "2026-04-03T09:00:00.000Z",
|
||||
"expiresAt": "2026-04-03T10:00:00.000Z",
|
||||
"revokedAt": null
|
||||
}
|
||||
```
|
||||
|
||||
> The verify endpoint always returns `200 OK`. Check the `valid` field — it is never an error
|
||||
> response for an expired or revoked token.
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — (Optional) Revoke the delegation early
|
||||
|
||||
If the delegatee has completed its task and you want to revoke the delegation before it expires,
|
||||
the delegator calls:
|
||||
|
||||
```bash
|
||||
curl -s -X DELETE "http://localhost:3000/api/v1/oauth2/token/delegate/$CHAIN_ID" \
|
||||
-H "Authorization: Bearer $DELEGATOR_TOKEN" \
|
||||
-o /dev/null -w "%{http_code}\n"
|
||||
```
|
||||
|
||||
Expected response: `204` (no body).
|
||||
|
||||
After revocation, verify requests for this chain return `{ "valid": false, "revokedAt": "<timestamp>" }`.
|
||||
|
||||
---
|
||||
|
||||
## Scope rules
|
||||
|
||||
- Delegated scopes must be a strict subset of the delegator's own token scopes
|
||||
- You cannot delegate scopes you do not have
|
||||
- You cannot delegate to yourself (delegateeAgentId must differ from delegatorAgentId)
|
||||
- Delegation is not transitive — a delegatee cannot re-delegate to a third agent
|
||||
|
||||
---
|
||||
|
||||
## Common errors
|
||||
|
||||
### `400 VALIDATION_ERROR` — scope not a subset
|
||||
|
||||
The delegator attempted to delegate a scope it does not hold. Check `GET /api/v1/token/introspect`
|
||||
to confirm which scopes your token carries.
|
||||
|
||||
### `400 VALIDATION_ERROR` — ttlSeconds out of range
|
||||
|
||||
Min: 60, Max: 86400. Values outside this range return a validation error.
|
||||
Reference in New Issue
Block a user