Delegation & Agent-to-Agent (A2A) Token Exchange
ZewstID supports two advanced agent interaction patterns: user delegation (agents acting on behalf of users) and A2A token exchange (agents calling other agents with audience-restricted tokens).
Part 1: User Delegation
Delegation allows an agent to request permission from a user to act on their behalf. The user explicitly approves the request, and the agent receives a scoped token.
Flow
Agent ZewstID API User │ │ │ │ POST /delegations │ │ │ { userId, scopes } │ │ │ ────────────────────► │ │ │ │ │ │ { delegationId, │ Notification │ │ status: "pending" } │ ──────────────────► │ │ ◄──────────────────── │ │ │ │ │ │ │ POST /delegations/:id/│ │ │ approve │ │ │ ◄────────────────── │ │ │ │ │ POST /delegations/:id/ │ │ │ exchange │ │ │ ────────────────────► │ │ │ │ │ │ { access_token, │ │ │ delegated: true } │ │ │ ◄──────────────────── │ │
Step 1: Request Delegation
The agent requests delegation from a user:
curl -X POST https://api.zewstid.com/api/v1/agents/agent_xyz789/delegations \ -H "Authorization: Bearer AGENT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "userId": "user_123", "scopes": ["profile:read", "orders:read"], "reason": "Access your order history to help with your support ticket", "expiresIn": 3600 }'
Response:
{ "delegationId": "del_abc123", "agentId": "agent_xyz789", "userId": "user_123", "scopes": ["profile:read", "orders:read"], "status": "pending", "reason": "Access your order history to help with your support ticket", "expiresAt": "2026-02-20T11:00:00Z", "createdAt": "2026-02-20T10:00:00Z" }
Step 2: User Approves
The user receives a notification and approves the request. This can happen through:
- The ZewstID account portal at account.zewstid.com
- A push notification to the mobile app
- An in-app approval UI built with the SDK
# User approves via the API curl -X POST https://api.zewstid.com/api/v1/delegations/del_abc123/approve \ -H "Authorization: Bearer USER_TOKEN"
Step 3: Exchange for Delegated Token
Once approved, the agent exchanges the delegation for an access token:
curl -X POST https://api.zewstid.com/api/v1/delegations/del_abc123/exchange \ -H "Authorization: Bearer AGENT_TOKEN"
Response:
{ "access_token": "eyJhbGciOiJSUzI1NiIs...", "token_type": "Bearer", "expires_in": 3600, "scope": "profile:read orders:read", "delegated": true, "delegator": "user_123", "agent_id": "agent_xyz789" }
The delegated token contains:
- The user's identity as the subject
- The agent's identity as the actor (claim)
act - Only the approved scopes
- A delegation chain for audit purposes
Revoking Delegation
Either the user or the agent can revoke a delegation:
curl -X POST https://api.zewstid.com/api/v1/delegations/del_abc123/revoke \ -H "Authorization: Bearer USER_OR_AGENT_TOKEN"
Listing Delegations
# List all delegations for an agent curl https://api.zewstid.com/api/v1/delegations?agentId=agent_xyz789 \ -H "Authorization: Bearer AGENT_TOKEN" # List all delegations for a user (from account portal) curl https://api.zewstid.com/api/v1/delegations?userId=user_123 \ -H "Authorization: Bearer USER_TOKEN"
Part 2: Agent-to-Agent (A2A) Token Exchange
A2A token exchange allows one agent to call another agent's API with a token scoped to the target agent's audience. This uses the OAuth 2.0 Token Exchange standard (RFC 8693).
How It Works
Agent A ZewstID API Agent B's API │ │ │ │ POST /a2a/exchange │ │ │ { targetAgent, │ │ │ subjectToken } │ │ │ ────────────────────► │ │ │ │ │ │ Verify trust │ │ │ relationship │ │ │ │ │ │ { access_token, │ │ │ audience: "agent_b" } │ │ │ ◄──────────────────── │ │ │ │ │ │ GET /api/data │ │ │ Authorization: Bearer... │ │ │ ──────────────────────────────────────────────► │ │ │ │ │ { data: [...] } │ │ │ ◄────────────────────────────────────────────── │
Trust Relationships
Before A2A exchange works, agents must have a trust relationship. Trust is established via the admin portal or API:
curl -X POST https://api.zewstid.com/api/v1/a2a/trust \ -H "Authorization: Bearer ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "sourceAgentId": "agent_a", "targetAgentId": "agent_b", "bidirectional": false, "maxChainDepth": 2, "allowedScopes": ["data:read"] }'
Performing an A2A Exchange
curl -X POST https://api.zewstid.com/api/v1/a2a/exchange \ -H "Authorization: Bearer AGENT_A_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", "subject_token": "AGENT_A_TOKEN", "subject_token_type": "urn:ietf:params:oauth:token-type:access_token", "audience": "agent_b", "scope": "data:read" }'
Response:
{ "access_token": "eyJhbGciOiJSUzI1NiIs...", "token_type": "Bearer", "expires_in": 300, "scope": "data:read", "issued_token_type": "urn:ietf:params:oauth:token-type:access_token" }
Audience-Restricted Tokens
The exchanged token is restricted to the target agent's audience:
{ "sub": "agent_a", "aud": "agent_b", "act": { "sub": "agent_a", "agent_type": "autonomous" }, "scope": "data:read", "chain": ["agent_a"], "chain_depth": 1, "exp": 1708420800 }
Chain Depth
A2A exchanges can be chained (Agent A → Agent B → Agent C), but the chain depth is limited to prevent infinite delegation:
| Setting | Default | Description |
|---|---|---|
maxChainDepth | 2 | Maximum number of hops in a delegation chain |
The
chainchain_depthmaxChainDepthNode SDK Examples
Delegation
import { ZewstIDAgent } from '@zewstid/node'; const agent = new ZewstIDAgent({ domain: 'auth.zewstid.com', clientId: process.env.AGENT_CLIENT_ID!, clientSecret: process.env.AGENT_CLIENT_SECRET!, agentId: 'agent_xyz789', }); // Request delegation from a user const delegation = await agent.requestDelegation({ userId: 'user_123', scopes: ['profile:read', 'orders:read'], reason: 'Access your order history for support', expiresIn: 3600, }); console.log(`Delegation ${delegation.delegationId}: ${delegation.status}`); // Wait for user approval, then exchange const delegatedToken = await agent.exchangeDelegation(delegation.delegationId); // Use the delegated token to access user resources const profile = await fetch('https://api.zewstid.com/api/v1/m2m/users/user_123', { headers: { Authorization: `Bearer ${delegatedToken}` }, });
A2A Token Exchange
import { ZewstIDAgent } from '@zewstid/node'; const agentA = new ZewstIDAgent({ domain: 'auth.zewstid.com', clientId: process.env.AGENT_A_CLIENT_ID!, clientSecret: process.env.AGENT_A_CLIENT_SECRET!, agentId: 'agent_a', }); // Exchange token for Agent B's audience const exchangedToken = await agentA.exchangeA2AToken({ targetAgentId: 'agent_b', scopes: ['data:read'], }); // Call Agent B's API with the audience-restricted token const data = await fetch('https://agent-b-api.example.com/api/data', { headers: { Authorization: `Bearer ${exchangedToken}` }, });
Listing Delegations
// List all active delegations const delegations = await agent.listDelegations({ status: 'approved', }); for (const del of delegations) { console.log(`${del.delegationId}: ${del.userId} → scopes: ${del.scopes.join(', ')}`); }
Security Considerations
Delegation Security
- Explicit consent — Users must explicitly approve each delegation request
- Scoped access — Delegated tokens only contain the approved scopes
- Time-limited — Delegations expire after the specified duration
- Revocable — Either party can revoke a delegation at any time
- Audit trail — All delegation actions are logged
A2A Security
- Trust required — Both agents must have an established trust relationship
- Audience restriction — Exchanged tokens are locked to the target agent
- Chain depth limits — Prevents infinite delegation chains
- Short-lived tokens — A2A tokens have a 5-minute default expiry
- Scope reduction — Exchanged tokens can only have equal or fewer scopes
Token Claims
Delegated and exchanged tokens include special claims for audit:
| Claim | Description |
|---|---|
act.sub | The acting agent's identity |
act.agent_type | The agent's type (autonomous, user-delegated, service) |
delegator | The user who granted delegation (delegation only) |
chain | Array of agent IDs in the delegation chain (A2A only) |
chain_depth | Current depth in the delegation chain |
delegated | Boolean flag indicating this is a delegated token |
Next Steps
- M2M Authentication — Service account basics
- Agent Authentication — Agent registration and trust
- Node.js SDK Reference — Full SDK API reference
Was this page helpful?
Let us know how we can improve our documentation