The easiest way to get an AI agent into production is also one of the easiest ways to lose track of what it is allowed to do.
Give it a service account.
Give that account access to the APIs it needs.
Put the credential in a vault.
Done.
We have used that pattern for years. It works well for software that has a stable job: a batch process reads from one database, an integration moves orders from A to B, a monitoring job opens incidents.
An agent is not quite that.
An agent might read a ticket, inspect a customer, query an MCP server, call three APIs, decide that it needs another tool, and then update something — all because a person asked a fairly innocent question in a chat window.
That is a very different security shape.
And I think we are going to regret treating those agents as ordinary service accounts.
A service account tells me what the application can do
Imagine a support agent.
I ask:
Why is this customer’s order stuck?
The agent checks the order, inventory, provisioning state and recent incidents. So far, read-only.
Then I ask:
Can you fix it?
Now the same agent may need to retry an activation, update a ticket or trigger a workflow.
If every call arrives downstream as svc-ai-agent-prod, we have thrown away some of the most useful context before the request even reaches the business system.
Who asked?
Which agent is acting?
Is it acting for that person, or on its own?
What task is it performing?
Was this specific action approved?
Which permissions should apply right now?
A service account can answer one of those questions reasonably well: which technical principal made the call.
That is no longer enough.
This is becoming an identity problem, not an AI problem
The interesting signal is that identity vendors and cloud platforms are converging on roughly the same problem.
NIST recently called out long-lived API keys and bearer tokens as a weak foundation for agentic systems. Their argument is straightforward: possession of a static key does not prove who is using it, the credentials tend to be broad, and agents move them across more tools and resources than traditional applications do.
Microsoft Foundry now explicitly separates agent identity from user identity. Its model supports both attended agents acting on behalf of a person and unattended agents operating under their own authority. For attended use, the token can carry the agent identity together with the user’s delegated permissions.
AWS has moved its MCP authentication in the same direction. Interactive MCP access can use OAuth authorization code flow, while automated agents can obtain short-lived OAuth access tokens through client credentials instead of carrying a permanent MCP key.
Okta and Auth0 are using the term I like most: agent as principal.
Not the user.
Not a generic application account.
The agent itself becomes an identity that can be permissioned, governed and audited.
That feels like the right mental model.
The identity chain matters
For an attended enterprise agent, I want the request chain to look something like this:
%%{init: {"look": "handDrawn", "theme": "base", "themeVariables": {"fontFamily": "Comic Sans MS, Virgil, Arial", "primaryColor": "#fff8dc", "primaryBorderColor": "#333", "lineColor": "#333"}}}%%
flowchart LR
user["User<br/>Who asked?"]
agent["Agent<br/>What is acting?"]
policy["Policy / Authorization<br/>Is this action allowed?"]
tool["MCP / API / Business System<br/>Scoped access"]
user -->|authenticated user| agent
agent -->|agent identity + delegated user context| policy
policy -->|short-lived scoped credential| tool
There are two identities in that picture for a reason.
The user tells us who asked.
The agent tells us what is acting.
The authorization layer decides whether this combination is allowed to perform this action in this context.
That is much more useful than:
%%{init: {"look": "handDrawn", "theme": "base", "themeVariables": {"fontFamily": "Comic Sans MS, Virgil, Arial", "primaryColor": "#fff8dc", "primaryBorderColor": "#333", "lineColor": "#333"}}}%%
flowchart LR
agent["AI Agent"]
service["svc-ai-prod"]
everything["Everything"]
agent --> service --> everything
The second version is easy to build.
It is also how you end up staring at an audit log six months later where every action was performed by the same account.
On-behalf-of should not mean “become the user”
There is a trap on the other side too.
If shared service accounts are too broad, it is tempting to simply pass the user’s identity through and let the agent become the user.
I do not like that either.
If I can change 200 customer records manually, it does not follow that every agent I use should automatically inherit the ability to change 200 customer records.
The useful permission is the intersection:
what the user may do
∩ what this agent may do
∩ what this task requires
If I use a read-only assurance agent, my own write permissions should not magically turn it into a provisioning agent.
Likewise, a provisioning agent with powerful capabilities should not be able to exercise them for a user who is only allowed to inspect service state.
That intersection is where agent authorization starts to make sense.
Short-lived credentials change the failure mode
There is another reason I want this outside the model: credentials.
An agent should not know a password.
It should not have a permanent API token sitting in its configuration.
And the LLM definitely should not see the credential.
The runtime should obtain a short-lived token for the specific resource, with the smallest useful scope, and hand it to the deterministic tool layer.
That is not a theoretical design anymore. AWS’s MCP server documentation describes one-hour OAuth access tokens. Microsoft recommends Entra-based authentication when possible specifically to avoid managing shared secrets, and supports OAuth identity passthrough when the user’s context needs to survive the trip to an MCP server.
The important part is not whether the token lives for exactly one hour.
The important part is that access is issued, scoped, expires and can be revoked.
A leaked permanent service-account credential is an incident.
A short-lived token for one agent, one resource and a limited set of permissions is a much smaller problem.
MCP makes this more obvious
MCP is making tool access wonderfully easy.
That is also why identity becomes harder to ignore.
An agent may have access to an Order MCP, Inventory MCP, ServiceNow MCP and some internal platform tools. Each server may expose several capabilities. Some are reads. Some change state.
I do not want every MCP server inventing its own answer to identity.
And I do not want the LLM deciding whether the current user is authorized.
The model can decide:
I need the
retry_activationtool.
Fine.
The platform should decide:
This agent is registered for that capability. Nikolaj is allowed to request it for this customer. The action requires write access. Policy says this operation needs approval. Issue a scoped credential after approval.
That split is important.
The LLM chooses what might help.
The platform decides what is allowed.
Unattended agents are the harder case
Not every agent has a person sitting in front of it.
A scheduled incident agent might inspect failures every five minutes and create a ServiceNow ticket when something looks wrong. A housekeeping agent might clean stale resources overnight. A deployment agent might react to a pipeline event.
There is no user to delegate from.
That does not mean we go back to svc-ai-prod.
The agent should still have its own identity.
It should have an owner.
It should have a defined purpose.
It should have explicit resource connections and scopes.
And it should be possible to disable that agent without disabling ten unrelated automations that happened to share the same account.
This is where agent registries start to become more than catalogs.
Identity, ownership and lifecycle belong together.
If an agent is retired, its access should disappear with it.
What I would actually build
I would keep the first version boring.
Every production agent gets a unique identity and an owner.
Every run keeps both the initiating user identity, when there is one, and the agent identity.
Access to downstream tools is issued at runtime using short-lived credentials.
Authorization checks the user, agent, requested action and resource. Not just the token at the front door.
MCP servers and APIs receive enough trusted context to make a real authorization decision.
And the audit trail records the chain:
%%{init: {"look": "handDrawn", "theme": "base", "themeVariables": {"fontFamily": "Comic Sans MS, Virgil, Arial", "primaryColor": "#fff8dc", "primaryBorderColor": "#333", "lineColor": "#333"}}}%%
flowchart LR
user["User"]
agent["Agent"]
policy["Policy decision"]
tool["Tool"]
object["Business object"]
result["Result"]
user --> agent --> policy --> tool --> object --> result
For higher-risk writes, add approval before the credential or tool invocation is released.
None of that requires the LLM to become a security component.
That is the nice part.
Service accounts are not going away
There will still be service accounts.
Some old systems only support username/password credentials. Some APIs only understand API keys. Some integrations genuinely are fixed machine-to-machine processes.
The answer is not to pretend those systems disappear.
Put the ugly credential behind the platform.
Vault it.
Exchange into it as late as possible.
Limit which agent can request it.
Keep the user and agent context in the audit trail even if the final legacy hop unfortunately says svc_something.
Okta’s own agent token-exchange documentation is interesting here because it explicitly supports brokering access to existing service accounts and secrets. That is much more realistic than assuming every enterprise application will suddenly implement modern agent identity.
Modern identity at the control plane. Compatibility at the edge.
I can live with that.
The question I would ask before connecting an agent
When somebody wants to give an agent access to another system, I would stop asking only:
Which service account should we create?
I would ask:
Who is the agent when it makes this call?
Then:
Who is it acting for?
And finally:
Why is it allowed to do this?
If the answer to all three is the same shared username and a secret in a vault, the agent architecture is probably not finished.
The model is the new part.
Identity is not.
We already know how to build least privilege, delegation, short-lived credentials, policy enforcement and audit trails.
Agents are simply forcing us to use those ideas properly.
Sources
- NIST: Back to the Future — Why Agentic AI Needs a Strong Identity Foundation
- Microsoft Foundry: Agent identity concepts
- Microsoft Foundry: MCP server authentication
- AWS: OAuth 2.1 authentication for AWS MCP Server
- AWS: How AWS MCP Server works with IAM
- Auth0: Agent as Principal
- Okta: Agent SSO and first-class identity for AI agents
- Okta Developer: AI agent token exchange