Skip to main content

Token Exchange (OBO)

Mandaitor implements OAuth 2.0 Token Exchange (RFC 8693) to enable On-Behalf-Of (OBO) delegation chains. This allows AI agents to act on behalf of authenticated users while preserving the original user's identity in the delegation chain.

How It Works

  1. A user authenticates with their identity provider (Auth0, Okta, Entra ID)
  2. The user creates a mandate delegating authority to an AI agent
  3. The AI agent exchanges the user's token for a scoped delegation token
  4. The delegation token includes the original user's identity (act claim)
  5. Downstream services can verify both the agent's identity and the delegating user

API

POST /identity/token-exchange

Request

{
"subject_token": "eyJhbGciOiJSUzI1NiIs...",
"subject_token_type": "urn:ietf:params:oauth:token-type:access_token",
"mandate_id": "mdt_01ABC123",
"scope": "construction.validation.approve",
"audience": "https://downstream-service.example.com"
}

Response

{
"access_token": "eyJpc3MiOiJtYW5kYWl0b3I6...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "construction.validation.approve",
"issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
"delegation": {
"mandate_id": "mdt_01ABC123",
"principal": "oidc:entra:abc-123@def-456",
"delegate": "agent:my-ai-agent",
"provider": "ENTRA_ID"
}
}

Delegation Token Claims

The issued delegation token contains:

ClaimDescription
issmandaitor:<tenant_id>
subDelegate's subject ID
audTarget audience (downstream service)
act.subOriginal user's subject ID
act.providerIdentity provider that verified the user
mandate_idMandate authorizing the delegation
scopeGranted scopes from the mandate
delegation_chainFull delegation chain metadata

SDK Usage

import { MandaitorClient } from "@mandaitor/sdk";

const client = new MandaitorClient({
apiKey: "mk_live_...",
tenantId: "tnt_your_tenant",
});

const result = await client.exchangeToken({
subject_token: userAccessToken,
mandate_id: "mdt_01ABC123",
scope: "construction.validation.approve",
audience: "https://downstream-api.example.com",
});

// Use the delegation token
const response = await fetch("https://downstream-api.example.com/action", {
headers: {
Authorization: `Bearer ${result.access_token}`,
},
});

Validation

The token exchange endpoint validates:

  1. Subject token — Resolved via the identity provider registry
  2. Mandate existence — The mandate must exist and be ACTIVE
  3. Principal match — The subject token identity must match the mandate's principal
  4. Audit trail — A VERIFICATION_ALLOWED event is emitted