As AI agents gain the ability to take real-world actions — reading databases, calling APIs, sending messages, executing code, and managing infrastructure — the question of what they are allowed to do becomes as important as what they are able to do. Agent permissions and authorization models define the rules governing what an agent may read, what it may modify, which tools it may invoke, when it must pause for human approval, and what data boundaries it must respect.
The principle of least privilege — giving agents exactly enough power to complete the approved task, for the approved time, in the approved context — is the cornerstone of agent security. Without it, a single compromised or misbehaving agent can access data it shouldn’t see, take actions beyond its scope, or cascade failures across connected systems. Broad or “just in case” access permissions are one of the most common root causes of AI-related security incidents.
This topic covers the authorization frameworks, identity models, and access control patterns that AI engineers must understand to build agents that are both powerful and safely constrained. The emergence of standards like MCP (Model Context Protocol) with built-in OAuth 2.1 support is rapidly professionalizing this space, but the core principles remain constant regardless of the specific protocol.
Every agent action should pass through a consistent control path before execution. This path follows a clear sequence: Identity (who is the agent acting on behalf of?) → Policy Gate (is this action allowed by the current policy?) → Tools & Data (execute within approved scope) → Approval (require human confirmation for high-risk actions) → Evidence (log everything for audit).
Least privilege means the agent receives exactly enough permissions to complete its specific task, for only the duration needed, in only the approved context. Permissions should be granted per-session, not permanently, and should default to the minimum viable access level.
Agents can authenticate using several identity models, each with different security tradeoffs:
# Delegated access: Agent inherits user's OAuth scopes
class DelegatedAgentAuth:
def __init__(self, user_token: str):
self.token = user_token
self.scopes = decode_scopes(user_token)
def can_execute(self, tool: Tool) -> bool:
"""Check if the user's delegated scopes cover this tool."""
required_scopes = tool.required_scopes
return required_scopes.issubset(self.scopes)
async def execute_tool(self, tool: Tool, params: dict):
if not self.can_execute(tool):
raise InsufficientScopesError(
f"Tool '{tool.name}' requires scopes "
f"{tool.required_scopes - self.scopes}"
)
return await tool.run(params, auth_token=self.token)
The Model Context Protocol (MCP) specification now includes explicit OAuth 2.1 support for agent authentication. In this model, the AI agent acts as an OAuth client, the application’s API is the resource server, and the authorization server issues scoped tokens. This standardizes how agents discover, authenticate with, and access protected resources.
Key aspects of MCP’s authorization workflow include:
# MCP tool with scoped authorization
class MCPToolDefinition:
name: str
description: str
required_scopes: set[str] # e.g., {"files:read", "calendar:write"}
async def authorize_and_execute(self, request, auth_context):
# 1. Validate token is still active
if not await auth_context.validate_token():
raise TokenExpiredError("Re-authentication required")
# 2. Check scopes at request time (not just connection time)
if not auth_context.has_scopes(self.required_scopes):
raise InsufficientScopesError(
required=self.required_scopes,
available=auth_context.current_scopes
)
# 3. Check resource-level permissions via policy engine
if not await policy_engine.evaluate(
principal=auth_context.identity,
action=self.name,
resource=request.target_resource
):
raise PolicyDeniedError("Action denied by policy")
# 4. Execute and log
result = await self.execute(request)
await audit_log.record(auth_context, self.name, request, result)
return result
For fine-grained authorization decisions, many production systems use Open Policy Agent (OPA) to define agent permissions as code. OPA policies are written in Rego, a declarative language that evaluates authorization decisions at runtime. This approach allows permissions to be version-controlled, tested, and deployed independently of the agent code.
# OPA Rego policy for agent tool access
package agent.authz
default allow = false
# Allow read-only tools for all authenticated agents
allow {
input.action == "read"
input.agent.authenticated == true
}
# Allow write tools only for agents with explicit write scope
allow {
input.action == "write"
input.agent.scopes[_] == "data:write"
input.resource.owner == input.agent.delegated_user
}
# Require human approval for destructive operations
require_approval {
input.action == "delete"
}
# Block access to PII fields unless agent has PII scope
deny {
input.resource.contains_pii == true
not input.agent.scopes[_] == "pii:access"
}
Production agent systems typically implement a tiered permission model that maps to risk levels:
OWASP identifies “excessive agency” as a top risk for LLM applications. This occurs when an agent determines that the best solution to a problem is to take broader actions beyond its authorized scope — for example, an email-drafting agent that decides to also access the user’s calendar to “improve” the response. Permissions must be enforced at the infrastructure level, not trusted to the model’s judgment.
Beyond authorization checks, agents should be sandboxed at the infrastructure level. This includes running agent code in isolated containers or VMs, using separate credentials per agent (never sharing API keys across agents), implementing network-level restrictions to prevent unauthorized outbound connections, and using ephemeral environments that are destroyed after each task. Sandboxing ensures that even if an agent’s authorization logic is bypassed through prompt injection or other attacks, the blast radius is contained.
Every sensitive action taken by an agent must be logged with full context: who authorized it, what scope was used, what resource was affected, and what the outcome was. This audit trail serves three purposes: security incident investigation, compliance reporting, and debugging agent behavior. Logs should be immutable and stored separately from the agent’s accessible data to prevent tampering.
An enterprise AI assistant that can access HR systems, financial databases, and communication tools must enforce strict data boundaries. A sales team member’s agent should be able to read CRM data and draft emails but should never access salary information or modify financial records. Delegated OAuth tokens scoped to the user’s role naturally enforce these boundaries.
A DevOps agent that manages infrastructure must have carefully scoped permissions. It might have read access to logs and metrics, write access to deploy configurations in staging, but require human approval for any production deployment. Infrastructure-as-code tools like Terraform can be wrapped with OPA policies that prevent agents from modifying critical resources like databases or networking rules.
Platforms that serve multiple customers with shared AI agents must enforce strict tenant isolation. Each agent session is scoped to a single tenant’s data, API keys are rotated per-session, and cross-tenant data access is blocked at the network and database level. This prevents a compromised agent serving one customer from accessing another customer’s data.
The MCP protocol is enabling an ecosystem of third-party tools that agents can discover and use. Each MCP server publishes its authorization requirements, and agents must present valid tokens with the correct scopes before accessing any tool. This creates a standardized, auditable way for agents to interact with external services while maintaining least-privilege access.