Securing agentic apps: Give your AI agents their own credentials
Most AI agents run with borrowed sessions and far more access than they need. Here's how to replace that with scoped, revocable credentials and tool-level authorization.
Your support agent needs to look up a customer's last invoice. The customer asks, the agent obliges. Simple enough. But look at what's happening under the hood: the agent is using the support rep's full OAuth session to hit Stripe, Zendesk, and your internal admin API. That session can refund invoices, delete tickets, and modify account settings. The agent only needed read access to one invoice, but you've handed it credentials that could drain every account in the system.
This is ASI03: identity and privilege abuse. It's the third risk in the OWASP Top 10 for Agentic Applications, and it's the one that underpins nearly everything else on the list. Goal hijacking (ASI01) is more dangerous when the hijacked agent holds elevated credentials. Tool misuse (ASI02) only matters when the agent is authorized to call those tools in the first place. Rogue agents (ASI10) are containable if their identity can be revoked. Fix identity and authorization first, and you've reduced the blast radius of almost every other risk.
This guide walks through how to do it, with concrete architecture decisions, code patterns, and migration steps for teams that already have agents in production.
The three anti-patterns you're probably running
Before building the fix, it's worth naming the failure modes. Most agentic systems in production today fall into one of three patterns, all of which are some version of "the agent has way more access than it needs."
1. Borrowing the user's session
This is the most common pattern and the easiest mistake to make. The user authenticates, gets a session token, and the agent uses that same token to make API calls on the user's behalf. It works. It's also the equivalent of handing your car keys to a valet and telling them they can also access your safety deposit box.
The problem isn't just that the agent could misuse the credentials. It's that when something goes wrong, whether through a compromised agent, a prompt injection, or a plain bug, the blast radius is the user's entire permission set. If the user is an admin, a confused agent is an admin too.
2. Shared service accounts
The second pattern shows up in backend and multi-agent systems. A single service account with broad API access gets shared across every agent in the fleet. One set of credentials, stored in an environment variable, used by the support agent, the analytics agent, and the deployment agent alike.
This is the agentic version of a problem enterprise security teams solved a decade ago for microservices. The fix there was per-service identity with scoped credentials. The same fix applies here.
3. Static API keys with no scoping
The third pattern is the simplest and the most brittle. A long-lived API key, often with full access, gets baked into the agent's configuration. No expiry, no rotation, no scope limits. If the key leaks through a log file, a debug endpoint, or a compromised dependency, the attacker has persistent access to everything the agent could reach.
The mental model: Agents as first-class principals
The fix starts with a conceptual shift. An agent is not an extension of the user. It's not a background job running with inherited credentials. It's a new category of actor in your system that needs its own identity, its own credentials, and its own permission boundaries.
This isn't a new idea. The industry went through exactly this evolution with microservices: shared database credentials gave way to per-service identity, which gave way to scoped tokens, which gave way to zero trust architectures where every request is authenticated and authorized regardless of network position. Agentic systems are replaying that history, just faster.
Every action an agent takes should answer three questions:
- Who is acting? The agent should have its own identity, separate from the user who invoked it.
- What are they authorized to do? Permissions should be scoped to the specific task, time-bound, and revocable.
- Can we prove it later? Every action needs an audit trail that links the agent identity, the user authorization, and the specific tool invocation.
The rest of this guide is organized around those three questions.
Authentication: Giving agents their own identity
There are two primary flows, depending on whether a human initiated the agent's session.
User-authorized agents: Authorization code with PKCE
When a user kicks off an agent workflow, the agent should not inherit the user's session wholesale. Instead, the user authenticates through your identity provider, and the agent receives a separate, scoped token that represents what the user has authorized the agent to do. Not what the user can do. What the user has authorized the agent to do.
With WorkOS AuthKit acting as the authorization server, the flow looks like this:
- The user authenticates through AuthKit (which handles SSO, SAML, MFA, and all the enterprise identity plumbing).
- AuthKit issues an access token scoped to the agent's declared needs, not the user's full permission set.
- The MCP client stores that token and presents it on every tool invocation.
- Each MCP server validates the token, checks the scopes, and either permits or rejects the call.
The key detail is step 2. The token the agent receives should have narrower scopes than what the user holds. If the user is an admin with billing:write permissions, but the agent's job is answering support questions, the agent's token should only carry tickets:read and tickets:write. The user authorized the agent to act, but they didn't authorize it to do everything they could do themselves.
In code, the MCP server middleware that validates incoming tool calls looks something like this:
Every tool invocation gets checked. The agent's identity (sub) is logged. The required permission is validated against the token. No blanket access.
Machine-to-Machine agents: Client Credentials
Not every agent is triggered by a user clicking a button. Background agents, scheduled workflows, and inter-agent delegations need credentials too. For these cases, you use the OAuth 2.1 Client Credentials flow. Each agent is registered as its own client in WorkOS with a unique client ID and secret.
The important property of this pattern: if this agent is compromised, you revoke its client credentials. No user sessions are affected. No other agents are affected. The blast radius is exactly one agent.
For enterprise customers that use existing identity providers, WorkOS handles SAML and OIDC federation. This affects how the user authenticates, not how the agent is credentialed. The agent still gets its own scoped token regardless of whether the user signed in through Okta, Azure AD, or a magic link.
Authorization: Scoping what agents can actually do
Authentication answers "who is this agent?" Authorization answers "is this agent allowed to do what it's asking to do?" You need both, and you need authorization enforced at every tool boundary, not just at the front door.
RBAC at the tool level
The first layer of authorization is role-based access control. Define roles that map to what your agents actually do, then assign permission sets to each role.
For example:
These permissions get encoded in the token claims that AuthKit issues. When an MCP server receives a tool invocation, it checks the agent's role against the permission required for that specific tool:
Notice the default-deny at the bottom. If a tool isn't in the map, access is rejected. This is least privilege in action: the agent can only call tools that have been explicitly mapped to permissions it holds.
This directly addresses ASI02 (tool misuse). Your agent might have a database tool, a file tool, and an email tool all available in its environment. RBAC ensures the support-agent role can query the database for reads only, can't write files to external paths, and can't send email outside the organization's domain. The tools exist, but the permissions are scoped per role.
Fine-grained authorization for resource-level control
RBAC handles "can this agent type perform this action type?" But agentic systems often need more specificity:
- Can this agent access this specific workspace's data?
- Can it modify this particular project?
- Can it act on resources in this tenant, or does the boundary stop here?
WorkOS Fine-Grained Authorization (FGA) extends RBAC by adding hierarchical, resource-scoped access control. It keeps the same mental model (roles, permissions, assignments) but makes resources and their hierarchy first-class. You define resource types in the WorkOS Dashboard to mirror your product's entity structure, then register resource instances at runtime as users create entities. This builds a hierarchy that FGA uses to evaluate permissions:
When a user has a workspace-admin role on the Engineering workspace, they (and any agent acting on their behalf) can access Project Alpha and Project Beta, because permissions flow down the hierarchy automatically. But they can't touch the Marketing workspace or Project Gamma. The boundary is enforced by the authorization model itself, not by a query filter you hope your code remembers to apply.
The access check at the MCP server level uses workos.authorization.check(), which evaluates all possible sources of access: direct assignments on the resource, inherited permissions from a parent resource, and organization-level roles.
This is how you enforce tenant isolation in multi-tenant agentic applications. The tenant boundary is a node in the resource hierarchy, not a WHERE clause in a SQL query. An agent operating within Tenant A's tree can never reach Tenant B's resources because no assignment bridges the two hierarchies.
Temporal scoping
Credentials should expire. This sounds obvious, but the default for many agentic systems is tokens that last far longer than the task they enable.
For interactive sessions where a user triggers an agent, tokens should be short-lived (minutes to a single-digit number of hours). For background agents running scheduled jobs, slightly longer, but never permanent. The pattern for handling token expiry mid-workflow is to check expiry before each tool invocation and refresh proactively:
If a token can't be refreshed (the user revoked authorization, the agent's credentials were rotated), the agent should halt gracefully, not fail open. A 401 from the MCP server means "stop what you're doing," not "try again with cached credentials."
Delegation chains: When agents call other agents
Multi-agent architectures introduce a specific identity question: when Agent A delegates a task to Agent B, what identity does Agent B use?
The wrong answer is that Agent A passes its own token to Agent B. This is credential sharing between agents, and it means Agent B operates with Agent A's full permission set. If Agent B is compromised, the attacker effectively controls Agent A's access too.
The right pattern is that Agent B authenticates as itself, with its own client credentials and its own role. But its effective permissions for the delegated task should be the intersection of its own role and Agent A's authorization scope. Agent B can never escalate beyond what Agent A was allowed to do, and it can never exceed its own role's permissions either.
In practice, this means the delegation request from Agent A to Agent B includes context about the originating authorization (which user, which resource scope), and Agent B's MCP server evaluates both:
Both checks must pass. This prevents privilege escalation in delegation chains and directly addresses ASI07 (insecure inter-agent communication) from the identity angle.
Audit and attribution
The third question, "can we prove it later?" requires logging every tool invocation with enough context to reconstruct what happened and why.
Every log entry should capture:
- Agent identity: which agent performed the action
- User authorization: which user's session authorized this agent
- Tool invoked: the specific tool name and its arguments
- Resource accessed: the specific resource ID in the FGA hierarchy
- Authorization decision: permitted or denied, and which policy evaluated
- Timestamp: when the action occurred
- Delegation chain: if this was a delegated task, the full chain of agents involved
When your customer's security team asks "which agent accessed customer X's billing data last Tuesday, and who authorized it," you need to answer in seconds, not days. The audit trail also feeds into behavioral baselining for detecting rogue agents (ASI10), which we'll cover in a future guide.
Migrating from over-permissioned to properly scoped
If you already have agents in production running with borrowed sessions or shared service accounts, here's how to migrate without breaking everything.
- Inventory current permissions. Map every tool, API, and system your agents can access today. List the credentials they use and the permission set those credentials carry. If this list surprises you, that's the point.
- Map actual usage. Turn on logging before you start restricting. Capture which tools each agent actually calls over a representative time period (a week or two is usually enough). You'll find that most agents use a small fraction of the permissions they hold.
- Define roles based on actual usage. Use the usage data to create role definitions that match what each agent type actually needs. Add a small buffer for edge cases, but resist the urge to be generous. You can always add permissions later. Removing them is harder.
- Register per-agent identities. Create client registrations in WorkOS for each agent type. Issue scoped credentials. Run the new credentials in parallel with the old ones initially, so you can verify that nothing breaks.
- Add tool-level authorization. Implement the middleware pattern described above on each MCP server. Start in audit-only mode: log authorization decisions but don't enforce them. Compare the audit log against actual behavior to catch any permission gaps before you flip the switch.
- Enforce and monitor. Once you're confident the roles are correct, switch from audit-only to enforcement. Monitor for 403 responses that indicate missing permissions and adjust roles as needed. Keep the audit log running permanently.
The key insight is that you can do this incrementally. You don't need to rewrite your agent architecture in one pass. Start with audit logging, then add identity, then add authorization, then tighten the scopes over time.
What comes next
Identity and authorization are the foundation, but they're not the whole story. In the next guide, we'll cover tool misuse and exploitation: how to add policy controls on how tools are used, not just whether they're accessible. That means argument validation, tool chain analysis, and runtime policy enforcement on top of the authorization layer we've built here.
The OWASP Top 10 for Agentic Applications describes ten risks, but the controls are cumulative. Get identity right first, and everything else gets easier.
If you want to skip the DIY auth infrastructure and start shipping scoped agent credentials today, WorkOS handles the OAuth 2.1 flows, RBAC, fine-grained authorization, and audit logging out of the box, including native support for MCP server authentication. Start today with 1 million active users per month free, no credit card required.