Skip to main content

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 (
    act
    claim)
  • 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:

SettingDefaultDescription
maxChainDepth
2Maximum number of hops in a delegation chain

The

chain
claim in the token tracks the full delegation path. If
chain_depth
exceeds
maxChainDepth
, the exchange is rejected.

Node 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

  1. Explicit consent — Users must explicitly approve each delegation request
  2. Scoped access — Delegated tokens only contain the approved scopes
  3. Time-limited — Delegations expire after the specified duration
  4. Revocable — Either party can revoke a delegation at any time
  5. Audit trail — All delegation actions are logged

A2A Security

  1. Trust required — Both agents must have an established trust relationship
  2. Audience restriction — Exchanged tokens are locked to the target agent
  3. Chain depth limits — Prevents infinite delegation chains
  4. Short-lived tokens — A2A tokens have a 5-minute default expiry
  5. Scope reduction — Exchanged tokens can only have equal or fewer scopes

Token Claims

Delegated and exchanged tokens include special claims for audit:

ClaimDescription
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

Was this page helpful?

Let us know how we can improve our documentation