---
title: "Multi-agent auth: delegation chains and revocation"
description: "Give each sub-agent its own identity, a narrower slice of its parent's permissions, a depth cap and cascading revocation. Tested TypeScript example."
canonical: https://theauth.dev/use-cases/multi-agent/
lastmod: 2026-10-08
---

Use case

# Auth for orchestrators that spawn sub-agents.

When one agent hands work to another, the second one should hold less than the first, for less time, and be stoppable on its own. This page shows how delegation chains do that in theAuth, with code that was run before it was published.

[Delegation docs](https://docs.theauth.dev/delegation) [Jump to the code](https://theauth.dev/use-cases/multi-agent/#uc-steps)

The problem

## One shared key per swarm does not survive an incident.

A planner splits a task. A reviewer reads pull requests. A fetcher pulls diffs. If all three use the same API key, you cannot tell them apart in logs, you cannot cut one off, and the fetcher can do whatever the planner can.

The fix is the same one operating systems use for processes: each worker gets its own identity, receives a subset of its parent's rights, and loses them when the parent's grant is withdrawn.

What a multi-agent setup needs

- **Separate identities.**Each agent has an owner and its own token.
- **Narrowing grants.**A child can only receive what its parent holds.
- **A depth cap.**No unbounded chains of agents creating agents.
- **Cascading revocation.**Cut a link and everything downstream goes with it.
- **Attribution.**An audit row per decision that names the agent.

The theAuth path

## Identities, narrowing delegation, then audit.

A human owner creates an agent, and the agent can hand a subset of its permissions to a sub-agent. Each hop adds one to the delegation depth, which is capped by maxDepth (default 3), and revoking a link also revokes every link created downstream of it.

In code

## A planner delegates one read-only slice to a reviewer.

Run on @glinr/theauth 0.6.0 on 2026-10-08. It prints read: true, write: false, then read after revoke: false. The reviewer is created with no permissions of its own, so everything it can do comes from the chain.

multi-agent.ts

```ts
import { createTheAuth, users } from "@glinr/theauth";

const theauth = await createTheAuth({
  database: { provider: "sqlite", url: ":memory:" },
  agents: { enabled: true },
});

// Agents need an owner row. In a real app the owner is a signed-in user.
await theauth.db.insert(users).values({ id: "user-1", email: "ada@example.com", createdAt: new Date(), updatedAt: new Date() });

const orchestrator = await theauth.agent.create({
  ownerId: "user-1",
  name: "planner",
  type: "autonomous",
  permissions: [{ resource: "mcp:github:*", actions: ["read", "write"] }],
});

const reviewer = await theauth.agent.create({
  ownerId: "user-1",
  name: "reviewer",
  type: "delegated",
  permissions: [],
});

// The planner hands the reviewer a narrower slice, for one hour, one hop deep.
const chain = await theauth.delegate({
  fromAgent: orchestrator.id,
  toAgent: reviewer.id,
  permissions: [{ resource: "mcp:github:pulls", actions: ["read"] }],
  expiresAt: new Date(Date.now() + 3_600_000),
  maxDepth: 1,
});

const read = { action: "read", resource: "mcp:github:pulls" };
const write = { action: "write", resource: "mcp:github:pulls" };
console.log("read:", (await theauth.authorize(reviewer.id, read)).allowed);
console.log("write:", (await theauth.authorize(reviewer.id, write)).allowed);

await theauth.delegation.revoke(chain.id);
console.log("read after revoke:", (await theauth.authorize(reviewer.id, read)).allowed);
```

Install with pnpm add @glinr/theauth sql.js and run with pnpm tsx multi-agent.ts. Setup details are on the [get started page](https://theauth.dev/get-started/).

Pitfalls

## Limits worth knowing before you ship.

- **Budgets are not enforced by authorize.**Call `policies.checkBudget()` before an LLM call and `recordUsage()` after it. Nothing is capped unless your code does this.
- **Re-delegation uses the parent's own permissions.**An agent that holds only delegated permissions cannot pass them on. Give an intermediate agent its own copy if it must re-delegate.
- **maxDepth is per call.**It is checked on each `delegate()` call and not stored as a ceiling for later hops. Pass a small value on every call.
- **Revocation is eventual per call.**It takes effect on the next `authorize()`. Operations already in flight keep running.
- **Approval needs your UI.**theAuth stores approval requests but ships no screen and does not deliver the notification.

## Keep reading

- [Agent identity in depth](https://theauth.dev/agent-identity/)
- [Identity and permissions for AI agents](https://theauth.dev/use-cases/ai-agents/)
- [Add auth to an MCP server](https://theauth.dev/use-cases/mcp-servers/)
- [Guide: secure an MCP server](https://theauth.dev/guides/mcp-server-typescript/)
- [theAuth vs Descope](https://theauth.dev/compare/descope/)
