Toggle Theme

AI Agent Permission Model: User Identity, Tool Access, Audit Logs, and Secret Isolation

Easton editorial illustration: production agent control room
3
Identity types
user identity, service account, and delegated token.
4
Control planes
scope, approval, sandbox, and server-side authorization.
6
Core objects
actor, subject, tool, resource, secret, and audit.
数据来源: Structured engineering model in this article

"MCP Security Best Practices describes token passthrough as an anti-pattern and recommends least-privilege scopes, server-side authorization, and auditable elevation flows."

A team gives the same admin token to an agent because “it is all internal anyway.” Then user A submits a query, and the agent reads user B’s CRM record under the admin identity. Broken permissions are worse than having no agent at all.

This is not a made-up edge case. MCP Security Best Practices explicitly treats token passthrough as an anti-pattern because it bypasses security controls, breaks the audit trail, and crosses trust boundaries. The OWASP AI Agent Security Cheat Sheet also lists tool abuse and privilege escalation as core risks.

The problem comes down to three questions: who does the agent represent, what authorizes the call, and what can it access? The blueprint below covers the full engineering model: the identity mapping table, tool permission fields, the core Secret Vault flow, an audit log schema with redaction rules, a permission decision table, a troubleshooting checklist, and an implementation path.

Identity mapping: who does the agent represent?

When an agent calls a tool, the logging and authorization systems first need to answer one question: who initiated the call, and who is being represented? Those two entities may be the same, or they may be different. Mixing them up leads to permission drift and unusable audit logs.

Identity type reference table

TypeactorsubjectWhen to use itPermission boundary
user identityUser AUser ADirect user interactionInherits the user’s permissions
service accountsystem_botnullBackground jobs and scheduled tasksSystem-level permission, independent of any user
delegated tokenworkflow_123User AUser-authorized automation workflowsWorkflow scope, limited by the user’s grant
tenant contextagent_456tenant_BMulti-tenant systemsTenant isolation; no cross-tenant access

Field definitions: actor is the entity that initiates the call, such as a user, agent, workflow, or system. The log records the actor ID. subject is the entity being represented, either a user or null. During direct user interaction, actor=subject. When a service account runs a background job, subject=null. delegatedBy identifies which user authorized the workflow. tenantId identifies the tenant and enforces data isolation in multi-tenant systems.

Under the MCP Authorization specification, MCP servers must verify that an access token was issued for the server as the intended audience. The token audience must point to that MCP server’s resource identifier. Tokens should not be placed in a URI query string because URIs can appear in logs, browser history, and proxy caches.

The OWASP Access Control Cheat Sheet emphasizes deny by default, least privilege, and checking permissions on every request. Identity mapping is the first step in that check: actor, subject, and tenantId determine the authorization decision that follows.

Tool permissions: what may the agent call?

Tool registration is not only name, description, and input_schema. The OpenAI Agents SDK tool reference includes fields that control permission and execution behavior.

Tool permission decision table

Permission controlWhen to use itImplementationRisk
per-tool permissionEach tool needs separate authorizationSet permission_level, such as read/write/admin, when registering the toolPermission configuration becomes more complex; you need to maintain a matrix
scope minimizationProgressive least privilegeStart with low-risk scopes, then expand high-privilege operations through scope challengesScope management costs more and may need dynamic adjustment
whitelistTool allowlistAllow only specific tool combinations, such as read_customer + summarizeAllowlist maintenance cost, with possible loss of flexibility
approvalHuman approvalTools with needs_approval=true pause before execution and wait for approvalApproval adds latency and affects user experience

OpenAI Agents SDK tool fields include is_enabled for runtime enablement control, so a tool can be disabled dynamically based on user role, tenant, or workflow context. needs_approval marks a tool that requires human approval. After approval, tool_input_guardrails still run. tool_input_guardrails validate inputs, such as PII checks and parameter bounds. tool_output_guardrails validate outputs, such as content filtering.

MCP Security Best Practices recommends progressive least privilege for scope minimization: the initial scope should include only low-risk discovery or read operations, such as read:metadata and list:resources. Higher-privilege operations should be added through precise scope challenges. Avoid wildcard and full-access scopes.

The OWASP AI Agent Security Cheat Sheet recommends per-tool permission scoping: use different tool sets for different trust levels, require explicit authorization for sensitive operations, and fail closed when authorization fails.

Secret isolation: how should the agent access credentials?

An agent should not directly hold long-lived plaintext API keys. The OWASP Secrets Management Cheat Sheet recommends centralized and standardized secret management. A secret management system should also support authentication, authorization, accounting, and lifecycle controls.

Secret access pattern table

PatternRiskWhen to use itExample
Direct possession, such as plaintext .envHigh leak risk, no attribution, no revocationNot recommendedHard-coded API key
Environment variablesLog leakage risk, still weak on attribution and revocationSingle-machine deploymentprocess.env.API_KEY
secret vaultCentralized management, encrypted storage, audit trail, revocationProduction systemsAWS Secrets Manager, HashiCorp Vault
secret referenceThe agent holds a reference and exchanges it for a short-lived token at execution timeMulti-tenant and high-security systemsvault.get(secretRef)

The secret lifecycle has four stages: creation should generate short-lived tokens instead of long-lived keys; rotation should happen on a schedule, such as every 30 days, with an automated process that updates the secret and notifies dependent systems; revocation should provide an emergency disable path so a leaked secret can be blocked immediately; expiration should set an expiry time so the credential stops working automatically.

MCP Security Best Practices explicitly says token passthrough is an anti-pattern: passing a user’s OAuth token directly to an agent bypasses security controls, breaks the audit trail, and crosses trust boundaries. The safer design is to issue a delegated token when the user authorizes the agent: short-lived, limited in scope, and explicit about its audience.

The core OWASP Secrets Management principles are centralize, least privilege, automate, and auditing. Secret access should follow least privilege. Manual maintenance increases leak and error risk, while rotation, revocation, and expiration are part of the lifecycle.

Audit logs: who called what, and when?

Audit logs need to reconstruct “who called which tool on behalf of whom, which object was accessed, and what happened” while redacting parameters and secrets.

Audit Log Schema

FieldMeaningRedaction rule
traceIdCall-chain ID, reusing the trace/runId concept from N156Do not redact
timestampCall time in ISO 8601Do not redact
actorEntity that initiated the callDo not redact
subjectEntity being representedDo not redact
toolTool nameDo not redact
actionOperation type, such as read/write/deleteDo not redact
resourceTarget objectRedact: customer_id → cust_***
outcomeResult, such as success/failure/deniedDo not redact

Redaction rules: do not record tokens, secrets, passwords, email addresses, phone numbers, or PII. Record who/what/when/where/outcome. For example, store customer_id=12345 as cust_, email=user@example.com as e@***.com, token=Bearer xxx as Bearer ***, and do not record password=secret123 at all.

The OWASP Logging Cheat Sheet says security logs should support investigation, audit, and monitoring, but should not record passwords, session IDs, access tokens, or sensitive personal data. They should record traceable fields such as who, what, when, where, and outcome.

The audit and accountability control family in NIST SP 800-53 reinforces a useful design point: audit logs are the last line of defense in a permission system. When an authorization check fails, the log must record the reason, such as actor has no permission, subject has no permission for the target, or scope is insufficient.

Permission model decision table: choose the right control mix

Identity mapping, tool permissions, Secret isolation, and audit logs are not separate checkboxes. They constrain each other. The table below maps common scenarios to control combinations.

Scenarioidentity typetool permissionsecret accessaudit logTypical application
Low-risk internal toolservice accountwhitelist, read tools onlyEnvironment variablesactor/tool/outcomeInternal report generation, scheduled sync
Multi-tenant SaaSdelegated token + tenantIdper-tool permission with tenant filteringsecret vault with tenant isolationfull schema with tenantIdCRM agent, email assistant
Financial transactionuser identity + approvalscope minimization + approvalsecret reference with short-lived tokenfull schema + approvalIdTrade approval, funds movement
Sensitive data operationdelegated token + approvalwhitelist + approval + guardrailssecret vault with emergency revocationfull schema + redactionData export, customer lookup

The OWASP AI Agent Security Cheat Sheet recommends separate tool sets for different trust levels and explicit authorization for sensitive operations. The core idea behind the decision table is composition: high-risk scenarios need layered controls, not one single control pretending to cover everything.

Troubleshooting checklist: common permission symptoms

These are common symptoms, likely causes, checks, and fixes for agent permission problems.

SymptomLikely causeWhat to checkFix
The agent gets 403 Forbidden when calling a toolactor has no tool permission, or subject has no target permissionCheck the actor permission_level and the subject’s resource permissionConfirm identity mapping and adjust the permission matrix
Logs show an empty actor or confused subjectIdentity mapping fields are not being passed correctlyCheck whether the agent context contains actor/subject/tenantIdPass identity fields through the whole call chain
Tool call succeeds, but the audit log misses required fieldsAudit Log Schema is incompleteCheck whether the log writer includes every fieldComplete the schema and add traceId/approvalId
User A’s request can read user B’s datatenantId or subject is not isolated, or an admin token is sharedCheck whether delegated tokens are used and tenantId is correctUse delegated tokens and enforce tenantId validation
After secret rotation, the agent still uses the old keySecret reference was not updated, or rotation did not take effectCheck whether the vault returns the new secret and whether the agent fetches it againMake rotation update the reference automatically
After approval, the tool call still failsGuardrails failed because of out-of-bounds parameters or PII detectionCheck the tool_input_guardrails logsAdjust the parameters or guardrail rules

Implementation checklist: build an agent permission model from zero

These are the five core steps for putting the permission model in place.

Step 1: Define identity mapping rules

Decision points: do you need multi-tenant isolation, which means adding tenantId? Do you have background jobs, which means defining a service account? Do you have automation workflows, which means using delegated tokens?

Pseudocode:

interface IdentityContext {
  actor: string;        // Entity initiating the call
  subject: string | null;  // Entity being represented
  delegatedBy?: string;  // Delegation source
  tenantId?: string;    // Tenant identifier
}

Step 2: Design the tool permission matrix

Decision points: do you need approval, which means needs_approval=true? Do you need dynamic filtering, which means implementing runtime is_enabled checks? Do you need parameter validation, which means implementing tool_input_guardrails?

Code example:

interface ToolPermission {
  name: string;
  permission_level: 'read' | 'write' | 'admin';
  required_scope: string[];
  needs_approval: boolean;
  is_enabled: (context: IdentityContext) => boolean;
}

Step 3: Connect a secret vault

Decision points: do you need short-lived credentials, which means using a secret reference? Do you need emergency revocation, which means ensuring the vault can disable access immediately?

Code example:

async function getSecret(secretRef: string, context: IdentityContext): Promise<string> {
  // Validate identity
  await vault.authenticate(context.actor);
  // Validate permission
  await vault.authorize(context.actor, secretRef);
  // Get a short-lived token
  const token = await vault.getToken(secretRef, expiresIn: '15m');
  // Record audit event
  await auditLog.record({
    actor: context.actor,
    action: 'get_secret',
    resource: secretRef,
    outcome: 'success'
  });
  return token;
}

Step 4: Implement audit logs

Decision points: do you need redaction, which means implementing redaction rules? Do you need traceId, which means reusing the trace/runId from N156?

Code example:

interface AuditLogEntry {
  traceId: string;
  timestamp: Date;
  actor: string;
  subject: string | null;
  tool: string;
  action: 'read' | 'write' | 'delete';
  resource: string;  // Redacted
  outcome: 'success' | 'failure' | 'denied';
}

Step 5: Test permission boundaries

Decision points: will you test unauthorized access, such as user A trying to access user B’s data? Will you test token leakage by simulating revocation after a secret leak? Will you test audit traceability by replaying the full call chain through traceId?

Test checklist: unauthorized access test (actor=user_A, resource=tenant_B → should return 403); token leak test (vault.revoke(secretRef) → the agent should no longer be able to get a new token); audit trace test (query the full call chain by traceId → it should include actor/subject/tool/outcome).

Next steps: further reading

An agent permission model spans identity, tools, Secrets, and audit. These related pieces are worth reading next.

Published articles:

  • Agent Sandbox Guide: Sandbox solves runtime isolation with containers and Docker. This article covers permission and secret boundaries; the two are complementary.
  • Tool Calling in Practice: The basics of tool calling. This article extends them with tool allowlists, per-tool permissions, and input validation.
  • AI Agent Monitoring and Recovery: Monitoring and alerting basics. This article adds audit fields and traceId.

Design an AI agent permission model

Design user identity, tool permissions, secret access, and audit logging for a production agent system.

  1. 1

    Step 1: List tools and resources

    List the tools, resources, actions, and external systems the agent can touch. Separate read-only operations from write, send, delete, and financial actions.
  2. 2

    Step 2: Define the identity context

    For every run, define actor, subject, tenant, workflow, and traceId so that user identity, service accounts, and automation workflows do not collapse into one admin identity.
  3. 3

    Step 3: Separate identity types

    Separate delegated user identity, service accounts, and system maintenance jobs, then define resource boundaries and audit fields for each.
  4. 4

    Step 4: Build the tool permission matrix

    For every tool, define action, resource, scope, approval, secret, and audit metadata, then run server-side authorization before execution.
  5. 5

    Step 5: Connect a secret vault

    Store secrets in a vault or credential service, exchange them for short-lived credentials only at the execution layer, and support rotation, revocation, and expiration.
  6. 6

    Step 6: Fail closed

    Before the tool gateway executes anything, check actor, subject, resource, action, scope, and approval. Reject the call explicitly whenever a check fails.
  7. 7

    Step 7: Write redacted audit logs

    Record who, what, when, where, outcome, traceId, approvalId, and a redacted resource summary. Add alerts for permission changes, scope elevation, and secret access.

FAQ

When an agent calls a tool, does it represent the user, a service account, or the workflow itself?
Look at the actor/subject pair. In direct user interaction, actor=subject. In background jobs, actor=system_bot and subject=null. In delegated workflows, actor=workflow_123 and subject=user_a. Both the log system and the authorization system should record actor and subject.
Why do I still need per-tool permissions after OAuth authorization succeeds?
OAuth scope is protocol-level permission. Per-tool permission is business-level authorization. Scope is not enough to answer the business question; the server still has to check actor, subject, resource, and action.
Can one admin token let an agent query data for every user?
No. That is a classic permission failure: the agent reads every user's data under an admin identity, so user A's request can expose user B's CRM records. Use short-lived delegated tokens with limited scopes and an explicit audience instead.
Can an agent read .env files or user API keys directly?
No. Secrets should live in a vault, and the agent should use a secret reference when it needs access. Reading .env directly makes leaks, attribution, and revocation much harder.
After approval, can I keep reusing the same high-privilege token?
I would not. Tokens should be short-lived and bound to the approved tool call. Reusing a high-privilege token increases blast radius and makes it hard to connect an approval record to a specific execution.
Should audit logs store parameters, and how do I avoid logging tokens, email addresses, or customer data?
Store parameter summaries and target resources, but redact sensitive values. Do not log passwords, session IDs, access tokens, full secrets, or sensitive personal data. For example, store customer_id as cust_***, email as e***@***.com, and token as Bearer ***.

11 min read · Published on: Sep 17, 2026

Comments

Sign in with GitHub to leave a comment

Easton BlogEaston Blog