---
id: 38
title: "Agents are principals: delegate, never impersonate"
status: current
date: 2026-06-12
authors:
  - "Theo Zourzouvillys"
tags: [security, auth, llm, architecture]
summary: "An agent acting with a copied user credential is impersonation — untraceable by design. Give agents their own identities and keys; let them act for a human only through explicit, scoped, time-bounded, revocable delegation; and record both actor and principal on every action."
supersedes: null
superseded_by: null
aliases: []
references:
  - id: rfc8693
    title: "RFC 8693 — OAuth 2.0 Token Exchange"
    url: https://www.rfc-editor.org/rfc/rfc8693
    abstract: "Defines token exchange including the 'act' (actor) claim, and draws exactly this distinction: in impersonation the original party becomes invisible, while in delegation the token carries both the principal and the actor — including chained actors — so every hop stays attributable."
  - id: confused-deputy
    title: "The Confused Deputy — Norman Hardy (1988)"
    url: https://css.csail.mit.edu/6.858/2015/readings/confused-deputy.html
    abstract: "The classic paper on what goes wrong when a program wields ambient authority it inherited from its environment rather than authority explicitly granted for the task — the failure mode shared by every agent that 'just uses' its user's credentials."
---

## TL;DR

When software acts on a person's behalf, there are two ways to wire it. **Impersonation**: hand it
the person's credential and let every downstream system believe it *is* the person.
**Delegation**: give it its own identity, grant it a scoped slice of the person's authority, and
record both names on everything it does. Choose delegation, every time:

- **Agents get their own identities and credentials.** Never a copy of a user's session, token, or
  key — an agent is a principal, not a disguise.
- **Delegation is a first-class grant**: explicit, scoped, time-bounded, revocable — and both the
  grant and every use of it are on the record.
- **Every audit record of a delegated action names two parties**: the actor (the agent) and the
  principal (the human it acted for). An audit record with one name is the bug.

The test: six months from now, can you tell whether the human or their agent did it? If not, you
built impersonation.

## Context

The expedient path is always impersonation. The agent needs to act as the user, the user already
has a cookie, a token, an API key — so the agent gets a copy. It works on day one, because every
downstream system already accepts the user. That's exactly the problem: it works by making the
agent **indistinguishable** from the person.

What that destroys, quietly:

- **Attribution.** Every action the agent takes is recorded as the human's. When an agent
  misbehaves — bad prompt, bad tool call, compromise — the forensic question "which of these
  actions were actually yours?" has no answer in the data. You're reconstructing from timing and
  vibes.
- **Scope.** The credential carries the user's *entire* authority. The agent that was supposed to
  triage email can also wire money, because the token doesn't know the difference.
- **Revocation.** The only off switch is the user's own credential. Killing a misbehaving agent
  means rotating the human's keys and breaking every other thing that depended on them.
- **Accountability across parties.** Downstream systems can't apply different limits, rates, or
  policies to the agent, because they can't see it.

None of this is new. [RFC 8693](ref:rfc8693) draws the impersonation/delegation line precisely and
gives delegation an `act` claim so chained actors stay visible; `sudo` has logged both uids for
decades; Kerberos grew *constrained* delegation because unconstrained was a disaster. The art is
settled. It's just being skipped in the agent gold rush, one pasted API key at a time — and the
number of agents per human is about to go from one to dozens.

> [!aside] Where this bites first
>
> Not in a breach — in an ordinary Tuesday incident. Something deleted records, the audit log says
> the user did it, the user says they didn't, and they're right: their agent did, with their
> credential, exactly as designed. Now every entry in your audit trail is a maybe.

## Recommendation

**Make every agent a principal.** Each agent — and each instance of it, if they run in different
trust domains — gets its own identity and its own credential, provisioned and rotated like any
workload identity ([ZFN-5](/zfn/5-platform-workload-identity-service/)). Sign or authenticate its
requests as *itself* ([ZFN-7](/zfn/7-sign-the-message/)), never as its user.

**Model "on behalf of" as an explicit grant.** A delegation is created by a deliberate user action,
and it is:

- **Scoped** — a named subset of the user's authority. The agent gets capabilities for its task,
  not the account.
- **Time-bounded** — it expires on its own. Standing delegations are renewed, not eternal; an
  abandoned agent's authority should age out like an unrenewed lease.
- **Revocable in isolation** — killing one delegation touches neither the user's credentials nor
  the agent's other grants.
- **Recorded** — the grant, each use, the expiry or revocation: all on the record.

**Record actor and principal together.** Every action taken under delegation carries both
identities, end to end — in the audit log, in downstream authorization decisions, in what humans
see ("agent X, on behalf of Y"). If sub-agents re-delegate, the chain is explicit and recorded,
exactly the shape of RFC 8693's chained `act` claims.

**Refuse ambient authority.** The agent must not acquire the user's power by running in the user's
environment — inheriting their cookies, their environment variables, their cloud role. That's the
[confused deputy](ref:confused-deputy) with a chat interface ([ZFN-10](/zfn/10-verify-resource-owner/)
is the same principle at the cloud-resource layer). Authority arrives through the delegation, or it
doesn't arrive.

**Keep the content rule too.** This note is the identity-layer half of a pair:
[ZFN-26](/zfn/26-ai-assisted-content-cosign/) says a human must be able to back what's published
under their name; this one says the *system* must always know which one of them acted. Both
collapse if the agent simply *is* the user.

## Consequences

**Easier:**

- "Who did this?" is a query, not an investigation. Actor and principal are columns.
- A misbehaving or compromised agent is revoked surgically; the human keeps working.
- Least privilege becomes real: delegations carry task-sized scopes, and downstream systems can
  rate-limit, monitor, and police agents as the distinct callers they are.
- Incident reviews and compliance audits stop arguing about whether the human was at the keyboard.

**Harder:**

- Every downstream surface has to learn two-party identity — authorize on the pair, display the
  pair. Systems that only know "a user token" need adapters or upgrades.
- Delegation needs product surface: grant flows, scope pickers, expiry defaults, a place to see and
  revoke what you've delegated. Skipping that UX is how teams end up back at "paste your API key."
- Agents need real credential infrastructure — issuance, rotation, storage ([ZFN-5](/zfn/5-platform-workload-identity-service/)) —
  which is more work than copying a token, on day one.

**New obligations:**

- The audit schema carries actor *and* principal (and the delegation that linked them) on every
  delegated action; one-name records are rejected, not tolerated.
- Delegation lifecycle is operated: expiries monitored, dormant grants reaped, revocation tested.

## References

- [RFC 8693 — OAuth 2.0 Token Exchange](https://www.rfc-editor.org/rfc/rfc8693) — the
  impersonation-vs-delegation distinction, and `act` claims for visible actor chains.
- [Norman Hardy — The Confused Deputy (1988)](https://css.csail.mit.edu/6.858/2015/readings/confused-deputy.html) —
  ambient authority is the root failure; explicit grants are the cure.
- [ZFN-5](/zfn/5-platform-workload-identity-service/) — the workload-identity platform agents
  should be provisioned from.
- [ZFN-7](/zfn/7-sign-the-message/) — agents authenticate as themselves, per message.
- [ZFN-10](/zfn/10-verify-resource-owner/) — the same no-ambient-authority principle at the
  cloud-resource layer.
- [ZFN-26](/zfn/26-ai-assisted-content-cosign/) — the content-layer companion: a human who can
  back the words; this note keeps the identities separable underneath.

## Changelog

- **2026-06-12**: First published as a Field Note.
