ai

AI Agents Are Not Users: Building an Identity Model That Reflects That

Forcing autonomous software into human user profiles creates massive security risks. Discover how to build a first-class AI agent identity architecture.

Jun 17, 202614 min read

In April 2026, an AI coding agent deleted the entire production database of PocketOS, a B2B platform used by car rental companies, along with every volume-level backup, in nine seconds. The agent was Cursor, running on a leading frontier model, configured with explicit safety rules its founder later described as "exactly what these vendors tell developers to do." It was working on a routine staging task when it encountered a credential mismatch, found a token with sufficient permissions, and issued a single GraphQL mutation that wiped everything.

The system prompt told it not to do anything destructive without approval, but system prompts are advisory, not enforced. As the post-mortem makes clear, the deeper architectural failure was giving a non-deterministic agent the same access a human operator would have, and trusting natural-language instructions to constrain what it did with that access.

The agent did not behave like a human user. It ran continuously and ignored explicit instructions. It also did not behave like a backend service, as it had no fixed code path and no auditor-readable workflow. The identity layer underneath it had to choose one of those two shapes, because those are the shapes our identity infrastructure offers. It chose wrong, but there was no way for it to choose right, because the right shape did not really exist.

This article makes the case that AI agents need to be treated as first-class identities in their own right, distinct from human users and from traditional machine identities. That case covers why the traditional models break down, what a first-class agent identity consists of, how lifecycle management has to change, why authorization has to be evaluated at runtime against the request rather than baked into roles at provisioning time, and what observability requirements emerge. The goal is not to build a new identity primitive from scratch, but to extend your existing infrastructure to handle a class of actor it was not designed for.

Why the Legacy Models Break Down

OAuth delegation gives the agent the same authority as the user. When a user grants an agent access to their CRM with the scopes they themselves hold, the agent can do anything the user can, across every future interaction, regardless of what it is being asked to do in any specific moment. The intent is selective delegation, but OAuth cannot express it at that granularity. Saying "let the agent see contact details for accounts I'm currently working on, but not anything in the legal holding queue" requires elaborate scope engineering that few products expose.

Service accounts have the opposite problem. The agent gets its own credential, but that credential is typically static, broadly scoped, and disconnected from any user context. When something goes wrong, the audit log shows that the service account did it, which is almost no information at all. There is no way to trace back through the chain of delegation, no way to see which user request triggered the action, and no way to revoke a single agent run without revoking the entire service account.

Both models share four failure modes that worsen as agent usage scales:

  • Over-permissioning: The credential carries broader authority than the agent needs for the task in front of it, because scopes are typically defined at the resource level (billing:write) rather than the capability level (billing.refund.issue_under_50_usd).
  • Blast radius: A compromise of the agent process, its memory, or its logs exposes a credential that grants standing access to production systems.
  • Lack of behavioral context: The identity layer cannot distinguish between "the agent is summarizing tickets" and "the agent is issuing refunds" because both operations present the same broadly-scoped credential that authorizes both actions.
  • Credential sprawl: Every new tool the agent integrates with means another credential to provision, store, rotate, and audit.

All four failure modes existed before AI agents and have been seen in incidents involving traditional automation. However, agents make them worse for two main reasons.

  1. The gap between the credential's authority and the work the agent is doing at any specific moment is much wider than it is for traditional automation.
  2. The agent's behavior is non-deterministic in a way that conflicts with the assumptions baked into both models.

A service account is safe partly because the code calling it is fixed. An agent's "code" is a tool-calling loop steered by an LLM interpreting natural language input that may itself be untrusted. When you can no longer rely on the determinism of an automation's code, the credential's scoping becomes one of the few remaining constraints on what the agent can do.

What a First-Class Agent Identity Looks Like

A first-class agent identity is more than a service account with a different label. It has its own lifecycle, permissions, policy bindings, and audit trail. It is an identity primitive that is structurally distinct from both users and traditional machine identities.

OpenFGA, the CNCF authorization engine that underpins Auth0's Fine-Grained Authorization product, formalizes this in its authorization patterns for agents. Agents are modeled as first-class principals that participate in the same permission hierarchy as users, with their own type in the authorization model and their own relationships to resources, but with permissions scoped to capabilities and bound to tasks rather than inherited as-is from a user role.

Specifically, a first-class agent identity has four properties:

  • A directory identifier distinct from any user or service account, with metadata describing the agent type, the agent definition version, and ideally, who is accountable for its behavior.
  • Scoped permissions defined in business terms, separate from any user's permissions even when the agent is acting on a user's behalf.
  • Delegation context recording both the agent as actor and the user as subject when the agent acts on someone's behalf. Downstream systems see "agent X, acting on behalf of user Y, with delegated authority Z" rather than just "service account did a thing."
  • A dedicated audit trail attributing every action to the specific agent identity with the delegation chain intact, separate from the logs the underlying tools generate.

A backend service has a static workflow and code paths that an auditor can read, so a broadly scoped credential is constrained by what the code does. An agent has none of these constraints. Its workflow is determined at runtime by an LLM, and its code path is a tool-calling loop that takes in untrusted input. The credential has to do the work that the code is not doing, and it has to do that work at the request level, not at provisioning time. OAuth 2.0 Token Exchange (RFC 8693) was designed to support this kind of dynamic, request-scoped delegation, and it is the foundation that Auth0's Token Vault builds on.

Lifecycle Management for Ephemeral Actors

User accounts live for years, and service accounts live for the lifetime of the service. Agent identities live somewhere in between, often lower down the spectrum. A long-running agent that handles support tickets might persist for the lifetime of the deployment. A task-scoped agent that runs once to answer a single user query might exist only for the duration of that task.

Provisioning is rarely interactive. Consent happens when a user authorizes an application that uses agents, and the agent identities are created on demand by that application. Provisioning has to be programmatic, idempotent, and tied to the agent definition rather than a human approval workflow.

Execution-context credentials should not be the same credentials that establish the agent's identity. The identity establishes who the agent is and what it could in principle do, while the execution-context credential is a short-lived token, scoped to the operation in front of the agent, that authorizes a particular call. This is the pattern Auth0's Token Vault implements at the OAuth layer: the agent does not hold the long-lived refresh token for a connected service, and instead requests a just-in-time access token through OAuth 2.0 Token Exchange. If the agent is compromised, the only credential exposed is whatever short-lived token it currently holds.

The diagram below shows what this flow looks like in practice. There are two phases. Once, when the application is first authorized, the user grants consent and the identity provider stores the long-lived refresh token in Token Vault, where it stays. Then, for each operation the agent needs to perform, it requests a short-lived access token scoped to that specific operation. The identity provider evaluates the request against policy, returns a token that lasts minutes rather than days, and the agent uses it for a single tool call before discarding it. If the agent is compromised, the attacker inherits only whatever short-lived token happens to be in memory, and revoking the connection at the identity provider invalidates all future token exchanges immediately.

Sequence diagram showing the provisioning of agent credentials

Suspension and decommissioning also have to be easy, fast, and accurate. Recall the PocketOS incident: when the agent went off the rails, there was no equivalent of "revoke the agent's database write capability for the next ten minutes while we figure out what just happened." The credential it was using gave it standing authority, and standing authority can only be revoked at the level of the whole credential. Centralizing token issuance through a single identity provider makes finer-grained revocation possible, since revoking a connection invalidates future token exchanges immediately while leaving the rest of the system running.

Policy-Driven Authorization

Static role assignment is the traditional model for user and service identity: an actor has a role, the role grants permissions, and permissions are checked against actions. This works fine when behavior is predictable, but is inadequate for agents. An agent might have access to a wide set of capabilities in principle, but in any given task, it should only exercise a narrow subset, determined by the task itself.

A better model is to bind authorization to behavior rather than to identity, evaluated at runtime against the specific request. There are two relevant patterns here. Attribute-based access control (ABAC) takes contextual attributes into account: the user the agent is acting on behalf of, the resource, the time, the action, and any task parameters. Relationship-based access control (ReBAC) goes further, expressing authorization in terms of relationships between entities. This makes it natural to write rules like "an agent can read contact details for accounts where it has an active assigned ticket," because the relationship is a first-class concept in the model rather than something encoded through scope engineering.

ABAC alone is enough for most teams. If your authorization rules can be expressed as "this attribute equals that attribute," you may not need the full relational graph. ReBAC pays for itself when you're managing thousands of resource-relationship pairs across a multi-tenant system, where the cost of expressing those rules in any other model becomes prohibitive. For a small team with a single-tenant product and a handful of resource types, a policy engine evaluating attributes against requests will likely cover most of what you want. You may not need ReBAC, but if you are deploying agents, you need some kind of policy-driven, runtime-evaluated authorization, whatever shape that takes.

Auth0's Fine-Grained Authorization, built on OpenFGA, is one of the more developer-accessible ways to do the ReBAC version of this. The authorization model defines types and relations, and condition checks ask whether a specific relationship holds for a specific request. The following is an example of an OpenFGA authorization model definition with a few relationships between users, agents, and accounts, and a condition:

model  
  schema 1.1

type user

type agent

type account  
  relations  
    define owner: [user]  
    define assigned_agent: [agent with active_assignment]  
    define can_read: assigned_agent or owner

condition active_assignment(current_time: timestamp, expires_at: timestamp) {  
  current_time < expires_at  
}  

The agent identity participates in the relationship graph as a first-class type. The condition expression incorporates runtime context — in this case, a time-bound assignment that expires automatically. The check happens at the moment the agent attempts an action, not when the agent was provisioned. If the assignment has expired, the check fails and the agent cannot perform the action.

Static permissions cannot keep up with agents that make autonomous decisions in real time. By the time a role change has rolled out to fix an over-permissioning issue, the agent has already acted with the old permissions a thousand times. Policy-driven authorization moves the decision to the moment of the action, where the context is known and the authorization layer can evaluate the specific request rather than against a generalization of expected behavior. That is also what makes the audit trail meaningful: every check is a discrete decision tied to a specific request, not a side effect of role membership configured in advance.

Observability and Non-Repudiation

A user-proxy or service-account model collapses the chain of accountability. The log shows that "the user" or "the service" did something, with no record of which agent was involved or what task it was executing. With a first-class agent identity, the chain is preserved, and three observability requirements become apparent:

  • Delegation chains must be explicit: Each API call should be traceable back through user → agent → sub-agent → tool → resource, with each hop recorded. OAuth 2.0 Token Exchange supports this, with actor and subject claims expressing the delegation relationship in the token itself.
  • Decisions must be logged, not just actions: Knowing the end decision is not enough. You also need to know which plan the agent was executing, which tool calls led to that point, what input shaped the decision, and which policy evaluations approved or denied each step. This is closer to distributed tracing than to traditional audit logging.
  • Non-repudiation must extend to original user intent: When a user authorizes an action, that authorization should be bound to the specific action approved, not to a generic scope. Rich Authorization Requests (RAR) support this by letting the authorization request carry structured details about what is being approved. Combined with Client-Initiated Backchannel Authentication (CIBA) for asynchronous user approval, the audit log can show exactly what the user approved and how the agent executed against it.

Centralized token issuance, as with Auth0's Token Vault, supports all three requirements by routing every credential through a single control plane. Every token is logged with the agent identity, the user it was issued for, the scope, and the time. Every revocation propagates immediately. The audit infrastructure does not have to reconstruct the chain of custody from scattered logs across multiple tools because the identity provider has already recorded it.

Building for Agent Identity

Treating AI agents as first-class identities is no longer a theoretical exercise. The traditional models of user-proxy delegation and static service accounts were not designed for non-deterministic actors that interpret natural language at runtime, and the gaps they leave compound quickly as agents take on more of the work the business depends on. The right response is to extend existing identity infrastructure with primitives designed for the way agents behave: distinct identities with their own lifecycles, policies bound to behavior rather than to roles, and audit trails that preserve the delegation chain from user intent through autonomous action.

Most of the building blocks exist. OAuth 2.0 Token Exchange provides the delegation semantics. CIBA and Rich Authorization Requests provide standards-based approval flows. OpenFGA and similar engines provide the policy infrastructure. Products like Auth0's Token Vault and Fine-Grained Authorization assemble these into developer-accessible platforms, and the patterns documented in OpenFGA's Authorization for Agents guidance show how to apply them in practice.

Organizations need to recognize that the identity model is not an implementation detail to be papered over with whichever credential pattern is most familiar to them. The PocketOS incident was not a freak accident. It was the predictable consequence of applying an identity model to a class of actors it was never designed for. AI agents in production deserve the same care that goes into provisioning user accounts and service identities, with the recognition that they are neither.

About the author

Cameron Pavey

Cameron Pavey

Senior Developer

Cameron is a full-stack dev living and working in Melbourne. He's committed himself to the never-ending journey of understanding the intricacies of quality code, developer productivity, and job satisfaction.View profile