DEV Community

Jack M
Jack M

Posted on

AI Agent Permission Inheritance: Let Agents Act Without API Keys

When an AI agent needs to do real work, the dangerous shortcut is simple: give it a service API key and hope the prompt behaves.

That shortcut does not scale. A helpful agent can now read tickets, create issues, update CRM records, run queries, trigger workflows, and call internal tools. If that runs through one broad key, you do not have user permission. You have a robot with a borrowed master badge.

A safer pattern is AI agent permission inheritance: the agent acts with the current user's scoped permissions, for one task, with explicit limits, revocation, and an audit trail.

This guide shows how to design that pattern for production AI tools.

Why permission inheritance matters now

Recent AI platform discussions keep circling the same problem: agents are becoming useful because they can act, not just answer. But action requires access.

The pressure is coming from several directions:

  • Internal teams want agents that work across support, sales, engineering, docs, and data systems.
  • Developers are connecting agents through MCP servers, workflow platforms, browser tools, and private APIs.
  • Security teams are seeing broad keys, copied tokens, and prompt-visible credentials appear in experiments.
  • AI gateways and agent platforms are adding observability, access control, fallback, and spend controls because model calls are becoming infrastructure.
  • Safety incidents around misconfigured agent environments are reminding builders that "testing" and "production" boundaries must be real.

The practical lesson is not "never let agents act." That is too blunt. The lesson is: agents should inherit bounded authority from the user and task, not from a permanent shared secret.

The common anti-pattern: one key for every agent

Small teams often start with this architecture:

User request
  -> AI agent
  -> tool router
  -> service API key
  -> internal systems
Enter fullscreen mode Exit fullscreen mode

It feels fast. It is easy to demo. It avoids OAuth complexity. It also creates a pile of problems:

Problem What happens in practice
No user boundary The agent can access data the user could not normally access.
Weak revocation Disabling one user does not stop the shared key.
Poor auditability Logs show "agent-service" instead of the real actor and purpose.
Prompt injection blast radius A malicious input can steer the agent while the tool still has broad access.
Hard tenant isolation Multi-tenant filters become optional application logic instead of enforced policy.
Secret exposure Keys can leak through traces, errors, screenshots, or debug prompts.

This is not only a security issue. It is a product quality issue. If users cannot understand what an agent was allowed to do, what it actually did, and how to undo or revoke it, they will not trust the feature when it matters.

What is AI agent permission inheritance?

AI agent permission inheritance means the agent receives a temporary, task-scoped authorization derived from the user's identity, role, tenant, consent, and current workflow.

The agent does not get the user's raw password. It does not get a broad service key. It receives a delegation token or permission envelope that says:

  • who initiated the task
  • which tenant or workspace it belongs to
  • which tools may be called
  • which records or resources are in scope
  • which actions are read-only, draft-only, or executable
  • how much spend, time, or tool usage is allowed
  • when the permission expires
  • what evidence must be logged
  • what requires human approval

A simple model looks like this:

User session
  -> permission service
  -> task-scoped delegation token
  -> agent runtime
  -> policy-checked tool calls
  -> audit log + revocation path
Enter fullscreen mode Exit fullscreen mode

The key idea: the agent's authority is not decided by the prompt. The prompt can explain the job, but the backend enforces what is allowed.

The permission envelope

Start with a plain object. Do not hide the design inside prompts.

{
  "delegation_id": "dlg_01J8...",
  "actor_user_id": "user_123",
  "tenant_id": "tenant_456",
  "agent_id": "support_refund_agent",
  "task_id": "task_789",
  "purpose": "draft_refund_response",
  "allowed_tools": ["tickets.read", "orders.read", "refunds.draft"],
  "resource_scope": {
    "ticket_ids": ["ticket_234"],
    "customer_ids": ["cust_987"],
    "max_order_age_days": 90
  },
  "action_mode": "draft_only",
  "budget": {
    "max_model_calls": 12,
    "max_tool_calls": 20,
    "max_runtime_seconds": 180
  },
  "approval_required_for": ["refunds.execute", "emails.send"],
  "expires_at": "2026-08-06T10:30:00Z",
  "policy_version": "agent-policy-v4"
}
Enter fullscreen mode Exit fullscreen mode

This object becomes the contract between product, security, engineering, and support. It is also much easier to test than a vague instruction like "only access what the user can access."

Map tools to user permissions, not model intent

An agent may claim it needs a tool. That claim is not enough.

Every tool call should pass through a policy check that combines:

  1. User permissions: Can this user perform this action without AI?
  2. Task scope: Is this resource part of the current task?
  3. Agent mode: Is the agent in read-only, draft, copilot, or autopilot mode?
  4. Risk tier: Could this action send money, delete data, email a customer, change permissions, or expose secrets?
  5. Evidence: Did the agent use trusted sources for the arguments?
  6. Budget: Has the run exceeded tool, token, or time limits?

Here is a simplified TypeScript-style policy check:

type ToolCall = {
  tool: string;
  args: Record<string, unknown>;
};

type Delegation = {
  actorUserId: string;
  tenantId: string;
  allowedTools: string[];
  actionMode: "read_only" | "draft_only" | "supervised" | "bounded_autopilot";
  resourceScope: {
    ticketIds?: string[];
    customerIds?: string[];
  };
  approvalRequiredFor: string[];
  expiresAt: string;
};

function authorizeToolCall(call: ToolCall, delegation: Delegation) {
  if (new Date(delegation.expiresAt) < new Date()) {
    return deny("delegation_expired");
  }

  if (!delegation.allowedTools.includes(call.tool)) {
    return deny("tool_not_delegated");
  }

  if (!userCanUseTool(delegation.actorUserId, delegation.tenantId, call.tool)) {
    return deny("user_lacks_permission");
  }

  if (!resourceInScope(call.args, delegation.resourceScope)) {
    return deny("resource_out_of_scope");
  }

  if (delegation.approvalRequiredFor.includes(call.tool)) {
    return requireApproval("human_approval_required");
  }

  if (delegation.actionMode === "draft_only" && isStateChanging(call.tool)) {
    return deny("draft_mode_blocks_state_change");
  }

  return allow();
}
Enter fullscreen mode Exit fullscreen mode

Notice what is missing: there is no "the LLM said this is safe" branch.

The model can propose. The runtime decides.

Use short-lived delegation tokens

A delegation token should be boring. That is a compliment.

Good delegation tokens are:

  • short-lived
  • scoped to one tenant
  • scoped to one task or workflow run
  • bound to a user and agent identity
  • unusable outside the agent runtime
  • revocable
  • logged every time they authorize a tool call

Avoid long-lived "agent tokens" that become shadow accounts. If you need a background agent to continue later, persist the workflow state and issue a fresh delegation after re-checking policy.

For long-running work, use leases:

run starts -> delegation valid for 10 minutes
run pauses -> lease released
run resumes -> policy re-check -> new delegation issued
Enter fullscreen mode Exit fullscreen mode

This helps when a user's role changes, a customer record is locked, a tenant disables an integration, or a support manager revokes approval.

Separate read, draft, and execute modes

Most useful agent workflows do not need full autonomy on day one.

Use modes:

Mode Agent can do Good for
Read-only Search, summarize, inspect Research, support triage, analytics explanations
Draft-only Prepare changes without applying them Email drafts, refund drafts, CRM update previews
Supervised Execute after approval Billing changes, user messaging, account updates
Bounded autopilot Execute low-risk actions inside hard limits Labeling, routing, enrichment, small internal updates

A permission envelope should include the mode. Tool handlers should enforce it.

Do not rely on UI labels alone. If the product says "draft mode," the backend must reject state-changing calls.

Design for revocation before launch

Revocation is where many agent systems get fuzzy.

You need at least four revocation paths:

  1. User revocation: the user cancels the agent run.
  2. Admin revocation: an admin disables a user, role, tenant, or integration.
  3. Policy revocation: the risk engine blocks a run because limits or evidence rules changed.
  4. Incident revocation: security disables a tool, provider, connector, or agent class.

The agent runtime should check revocation before every tool call, not only when the run starts.

async function beforeToolCall(call, delegation) {
  const status = await delegationStore.getStatus(delegation.delegation_id);

  if (status.revoked) {
    throw new Error(`Delegation revoked: ${status.reason}`);
  }

  return authorizeToolCall(call, delegation);
}
Enter fullscreen mode Exit fullscreen mode

This can feel strict, but it prevents the worst version of agent failure: a workflow that continues acting after the human thinks it stopped.

Store delegation receipts

Every meaningful agent action should leave a receipt.

A good receipt answers:

  • Who initiated this?
  • Which agent acted?
  • Which permission envelope allowed it?
  • Which tool ran?
  • What resources were touched?
  • Was the action read, draft, or execute?
  • Was approval required?
  • What was the result?
  • Can it be replayed, reviewed, or rolled back?

Example receipt:

{
  "receipt_id": "rcpt_01J9...",
  "delegation_id": "dlg_01J8...",
  "actor_user_id": "user_123",
  "tenant_id": "tenant_456",
  "agent_id": "support_refund_agent",
  "tool": "refunds.draft",
  "resource_ids": ["order_555"],
  "decision": "allowed",
  "approval_id": null,
  "policy_version": "agent-policy-v4",
  "created_at": "2026-08-06T10:18:14Z"
}
Enter fullscreen mode Exit fullscreen mode

Receipts are not only for audits. They help developers debug wrong outputs, support teams explain agent behavior, and product teams see which workflows are trusted enough to automate further.

Content gap: what most guides skip

Top-ranking content around AI agents, OAuth, MCP, and API security often covers one layer well:

  • how to connect tools
  • how to store secrets
  • how to build OAuth flows
  • how to add prompt guardrails
  • how to log model calls
  • how to use an AI gateway

The missing practical value is the connection between those layers. Permission inheritance is that connection.

The question is not only "Where do I store the key?" It is:

What exact authority should this agent inherit from this user for this task, and how will the system prove it enforced that authority?

That is the architecture gap small teams should close early.

Implementation checklist

Use this checklist before giving an agent access to real tools.

1. Classify every tool

Tag tools by risk:

  • read customer data
  • read internal data
  • write draft
  • write production state
  • send external message
  • spend money
  • change permissions
  • access secrets

If you cannot classify a tool, it should not be available to an autonomous agent.

2. Create a permission envelope per run

Do not let the agent discover its own authority from the prompt. Generate a backend permission envelope after checking the user's session, tenant, role, plan, consent, and integration status.

3. Bind tool calls to trusted arguments

If an agent wants to refund an order, the order_id should come from a trusted lookup or selected UI record, not from free text alone.

4. Add approval gates for risky actions

Approvals should show the diff, the source evidence, and the exact action. "Approve agent" is too vague. "Approve refund draft for order_555 for $42.00" is reviewable.

5. Log receipts, not just traces

Model traces show what the agent thought. Receipts show what the system allowed. You need both.

6. Test cross-tenant denial

Add regression tests where the agent tries to use a valid tool on the wrong tenant, wrong customer, wrong record, or expired delegation. These tests should fail closed.

7. Give users a stop button

A visible stop button should revoke the delegation, cancel queued steps, and prevent future tool calls from the same run.

Real-world use cases

Support agent

A support agent can read the current ticket, inspect recent orders, draft a refund, and prepare a reply. It cannot execute the refund or email the customer until a human approves the exact action.

Analytics agent

An analytics agent can query metrics the user can already access. The delegation includes row-level tenant filters, metric definitions, query budgets, and blocked columns. The agent cannot bypass analytics permissions by writing raw SQL against a broader warehouse role.

Engineering agent

A coding agent can read issues, inspect repository files, create a branch, and draft a pull request. It cannot rotate secrets, change deployment settings, or merge without approval.

Sales operations agent

A sales agent can enrich a lead, draft CRM notes, and suggest next steps. It cannot export a full customer list or send outbound messages without consent and rate limits.

A simple reference architecture

[User Session]
      |
      v
[Permission Service] ---- checks roles, tenant, consent, integration status
      |
      v
[Delegation Token / Envelope]
      |
      v
[Agent Runtime]
      |
      v
[Tool Policy Gateway] ---- checks tool, resource, mode, budget, approval
      |
      v
[Internal Tools / MCP Servers / APIs]
      |
      v
[Delegation Receipts + Audit Logs]
Enter fullscreen mode Exit fullscreen mode

This architecture works whether your tools are REST APIs, MCP servers, queues, browser actions, SQL queries, or internal SDK calls. The important part is that every path to action crosses the policy gateway.

What to measure

Track metrics that reveal whether permission inheritance is working:

  • denied tool calls by reason
  • approval rate by action type
  • revoked delegations
  • expired delegations reused
  • cross-tenant denial tests passing
  • tool calls per run
  • cost per successful delegated task
  • incidents involving overbroad scope
  • user trust signals, such as approval edits and cancellation rate

If every action is approved, your agent may be too restricted. If no action is denied, your policy may not be doing real work.

The builder takeaway

AI agents need access to be useful. But access should not mean handing a model broad keys, invisible permissions, or permanent authority.

Permission inheritance gives builders a better middle path: agents can act with the user's bounded authority, for a specific task, with receipts, revocation, and policy checks around every tool call.

That is how you move from impressive demos to agent workflows users can actually trust.

FAQ

What is AI agent permission inheritance?

AI agent permission inheritance is a pattern where an agent receives temporary, task-scoped authority derived from the current user's permissions, tenant, consent, and workflow mode. The agent does not receive broad API keys or raw credentials.

Is permission inheritance the same as OAuth?

No. OAuth can be part of the implementation, but permission inheritance is the broader product and runtime pattern. It includes task scope, resource limits, tool policy, approval gates, revocation, budgets, and audit receipts.

Should AI agents ever use service accounts?

Sometimes, but service accounts should still be constrained by tenant, tool, task, and policy. A broad service account that can do everything is risky. Prefer user-scoped delegation for user-initiated work.

Can prompts enforce user permissions?

Prompts can describe rules, but they should not be the enforcement layer. Permissions must be checked by backend services before tool calls execute.

How long should a delegation token last?

Keep it short. Many interactive tasks only need minutes. Long-running workflows should use leases and re-check policy before issuing a fresh delegation.

What is the biggest mistake small teams make?

The biggest mistake is giving the agent one powerful key because it makes the demo easier. That shortcut usually creates weak audit logs, poor revocation, broad blast radius, and cross-tenant risk.

Top comments (0)