Delegation
Delegation lets one subject (the delegator) grant another subject (the delegate) the ability to act on its behalf for a defined set of actions. The most common use case is an AI agent acting on behalf of a human user, but delegation chains extend naturally to multi-agent systems, where an orchestrator agent delegates a sub-task to a specialized sub-agent.
How it works
When a delegation exists and the delegate calls /access/v1/evaluation, the delegate borrows the delegator's authority, narrowed by the delegation's scope:
Delegate's effective access = delegator's own policies ∩ delegation scope
Its authority for a delegated action comes entirely from the delegator, which is what makes delegation useful for an agent created to do one job on someone's behalf. The delegate can never exceed the delegator's own permissions, and if the delegator loses access, the delegate loses it on the next call, no propagation delay, no stale grants.
An agent that holds its own broad policies keeps them when a delegation is revoked. Grant the agent nothing directly and let every delegated action derive from a human, and revocation leaves it with nothing.
Delegation chains (multi-hop)
A delegate can itself become a delegator: for example, an orchestrator agent that was delegated access by a human can delegate a narrower slice of that access to a sub-agent. Authority originates at the root of the chain and is narrowed by every scope along the way:
Intermediate agents are actors, not sources of authority: an orchestrator with no standing permissions of its own passes authority through without adding any. Every scope in the chain must cover the requested action; if any one excludes it, the request is denied. Authority only narrows as it moves down a chain and can never widen, no matter how many agents are involved.
Chain depth is capped at 3 hops. A delegation that would push any chain beyond that limit is rejected at creation time.
Scope
You can restrict what a delegation covers using the scope field: a list of action identifiers the delegate is allowed to perform on the delegator's behalf.
{
"delegator_id": "USER_ID",
"delegate_id": "AGENT_ID",
"scope": ["read", "list"],
"expires_at": "2026-12-31T23:59:59Z"
}
Each scope entry is a token of the form <action> or <action>:<resource>. A bare <action> (e.g. read) covers that action on any resource; a qualified <action>:<resource> (e.g. read:doc-123, where the resource part matches the target resource's ID, name, or external ID) covers that action only on that resource. A request is allowed only if at least one token covers its action — and, for a qualified token, its resource. Anything not covered is denied immediately, before any policy evaluation runs, regardless of what either party's own policies would otherwise allow.
When scope is omitted
- For a root delegation (the delegator is not itself a delegate of anyone), omitting
scopemeans the delegate borrows the delegator's access with no additional ceiling. - For a sub-delegation in a chain (the delegator is itself a delegate), omitting
scopemeans the sub-delegation inherits the delegator's own scope. A sub-agent can never end up less restricted than the scope the principal above it was granted, even if no explicit scope is written on the new delegation.
If you do specify a scope on a sub-delegation, it must be a subset of the delegator's own scope. Attempting to widen scope beyond the parent's is rejected at creation time.
Expiry
Set expires_at to automatically revoke the delegation at a specific time. Omit it for an indefinite delegation. Delegations can also be revoked explicitly at any time via DELETE /v1/delegations/{id}, effective immediately, and immediately reflected for every hop downstream in a chain.
This is a different timer from the HITL decision reuse window: a delegation's expires_at governs how long the relationship exists; an HITL approval's approval_ttl_seconds governs how long a single human decision is reused. The two can both apply to the same request independently.
Constraints
- Delegator and delegate must be different subjects.
- Both subjects must already exist in your tenant before a delegation can be created.
- Chain depth is capped at 3 hops, enforced at creation time.
In the evaluation response
When access is granted through a delegation, the response reflects the policy that granted the delegator the access being borrowed:
{
"decision": true,
"context": {
"reason_code": "ALLOW",
"access_path": "direct",
"policy_id": "pol-456"
}
}
When access is denied because the requested action is outside a delegation's scope, a distinct reason code is returned, before any policy evaluation runs:
{
"decision": false,
"context": {
"reason_code": "delegation_scope_denied",
"reason": "action not in delegation scope"
}
}
When the requested action is within scope but the principal at the root of the chain does not hold the access, another distinct reason code is returned:
{
"decision": false,
"context": {
"reason_code": "DELEGATOR_DENIED",
"reason": "delegator <id> does not have access to perform this action"
}
}
DELEGATOR_DENIED distinguishes "the authority being borrowed does not cover this" from "the action is outside the delegation's scope", useful for debugging and policy auditing.
Audit trail for chains
Every delegated evaluation records a delegation_chain field in the audit log, an ordered list of the delegation IDs involved, from the immediate delegator up to the root. This means the audit log for a 3-hop chain traces every principal involved, not just the subject that made the request, so you can reconstruct exactly who authorized what at each level.
When to use delegation
| Scenario | Use delegation? |
|---|---|
| AI agent acting on behalf of a specific user | Yes |
| Orchestrator agent delegating a sub-task to a specialized sub-agent | Yes, see Delegation chains |
| Service-to-service calls with a fixed identity | No, give the service its own policies |
| An agent that needs standing access of its own | No, give it policies directly; delegation is for borrowed authority |
| Temporary admin access for a contractor | No, use JIT Access instead |
| User sharing their access with a teammate | Yes, with a scoped expires_at |
Related
- Access Paths: how delegation fits into the evaluation flow.
- JIT Access: time-boxed access without the intersection constraint.
- HITL: pausing a sensitive action for human approval, which can apply independently of any delegation chain.