> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Set up cross-app access with ID-JAG-style token delegation

> Wire an enterprise agent host to Devotel Orbit without a static, broadly scoped API key — issue an authorization mandate per user-and-agent pair, redeem declared intents for 300-second scoped credentials, and let the IdP-issued assertion slot in when ID-JAG lands.

# Set up cross-app access with ID-JAG-style delegation

This runbook connects an enterprise agent host — ChatGPT Enterprise,
Claude for Work, or an internal A2A coordinator — to Devotel Orbit using
the ID-JAG delegation pattern instead of a shared static key: user-level
consent recorded as a mandate, then single-scope credentials minted per
task and dead within five minutes. The conceptual model is in
[Cross-app access (ID-JAG)](https://docs.orbit.devotel.io/concepts/cross-app-access-id-jag.md); this
page is the wiring.

## Prerequisites

* An API key with `agents:write` scope, held by the owner, admin, or
  developer role — the mandate and credential endpoints are write-gated
  on both.
* A name for the agent identity you will delegate to (the `agentId` the
  host will claim) and the user identifier your enterprise uses as the
  accountable principal (`principalId`) — usually the user's IdP subject
  or email.
* The agent host's dispatch point where intents are declared — the place
  a task becomes "tool X, purpose Y" before it runs.

## Step 1 — Set up the IdP side of the delegation

The enterprise IdP (Okta, Auth0, Microsoft Entra) is the root of user
identity, and the pattern does not change that. Decide how the user's
identity will reach each mandate:

1. **Choose the principal identifier.** Use a stable per-user value —
   the IdP `sub`, or the enterprise email — and pass it unchanged into
   `principalId` at issuance. This value lands in the consent digest, the
   audit log, and every minted token's actor chain, so pick once.
2. **Decide which agent hosts get mandates.** A mandate is per
   user-and-agent pair. A fleet of agents means one mandate per agent —
   never a shared "team" mandate, which would defeat binding.
3. **(When ID-JAG finalizes) enable the identity-assertion grant in the
   IdP.** Today's few-vendor preview: chain the IdP-issued assertion into
   the mandate issuance below, instead of your host minting mandates
   directly. The Orbit-side gate and credential endpoint you build now
   are unchanged by that swap.

## Step 2 — Issue the mandate (the Orbit-side consent record)

Issue one mandate per user-and-agent pair, scoped to exactly the actions
and tools that pair may use:

```bash Request theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/agents/agent-authorization-mandate \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "mandate-user-agent-001",
    "agentId": "enterprise-chatgpt-connector",
    "principalId": "annika@example.com",
    "allowedActions": ["invoke_tool"],
    "allowedTools": ["list_campaigns", "send_sms"],
    "allowedDataCategories": [],
    "maxInvocations": 1000,
    "expiresAt": 1760000000000
  }'
```

Store the returned mandate snapshot — including its `consentDigest` —
in the agent host. Every subsequent gate check round-trips this
snapshot, and the digest is what makes a tampered copy detectable.
`maxInvocations` caps how many actions the pair may ever perform;
`expiresAt` bounds the consent lifetime independent of any credential.

## Step 3 — Redeem a declared intent for a scoped credential

At task start, the host declares its intent — "this agent needs this
tool, for N seconds" — and exchanges mandate plus intent for one
short-lived token:

```bash Request theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/agents/agent-authorization-mandate/credential \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "mandate": { "id": "mandate-user-agent-001", "agentId": "...", "principalId": "...", "allowedActions": ["invoke_tool"], "allowedTools": ["list_campaigns"], "allowedDataCategories": [], "maxInvocations": 1000, "invocationCount": 0, "status": "active", "consentDigest": "...", "expiresAt": null, "createdAt": 1760000000000, "updatedAt": 1760000000000, "revokedAt": null },
    "action": { "action": "invoke_tool", "tool": "list_campaigns", "reference": "run-42" },
    "audience": "agent-runtime",
    "ttlSeconds": 60
  }'
```

On success the response carries:

```json Response theme={null}
{
  "ok": true,
  "data": {
    "token": "eyJhbGciOi...",
    "expiresAt": 1760000060000,
    "ttlSeconds": 60,
    "authorization": { "authorized": true, "reason": "ok" }
  }
}
```

Send the returned token as the task's bearer credential. The `audience`
must be one of `agent-runtime` or `voice-gateway` — the two worker pools
the broker mints for. `ttlSeconds` is clamped to a hard ceiling of 300
seconds; ask for less per task, not more. An intent outside the mandate —
a tool not in `allowedTools`, an action not in `allowedActions`, an
exhausted cap, an expired or revoked mandate — is refused with
`422 VALIDATION_ERROR` and the deny `reason` in the body; no token is
minted.

## Step 4 — Verify the delegation

Dry-run the gate before committing an action. The `/authorize` endpoint
evaluates mandate plus intent and returns the decision **without**
advancing the invocation count — and `/verify` recomputes the consent
digest so a tampered snapshot is caught:

```bash Request theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/agents/agent-authorization-mandate/authorize \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "mandate": { "id": "mandate-user-agent-001", "...": "..." }, "action": { "action": "invoke_tool", "tool": "list_campaigns", "reference": "probe" } }'
```

Expect `200` with `authorized: true` for an in-scope intent, `authorized:
false` plus a `reason` otherwise. A further check on a public boundary:
if the agent speaks A2A, its AgentCard advertises the bearer scheme
(`at+jwt`) and the JWKS URI the token's signature verifies against.

## Step 5 — Revoke and audit

When the delegation ends — user offboarded, agent retired, consent
withdrawn — revoke the mandate:

```bash Request theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/agents/agent-authorization-mandate/revoke \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "mandate": { "id": "mandate-user-agent-001", "...": "..." } }'
```

Revocation is terminal: every later gate check against that mandate
denies, and any credential already minted from it expires within its
300-second ceiling. Mandate issuance, every authorization decision,
every credential mint, and the revocation itself each land in the audit
log under the principal and agent you bound — audit answers "user U,
through agent A, did X" rather than "the key did X".

For the full endpoint catalog — the `/act` and `/act-chain` commit
paths, delegated sub-mandates, and the chain-audit surfaces — see
[Authorization mandates](https://docs.orbit.devotel.io/agents/authorization-mandates.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.