Zylos LogoZylos
2026-05-20

RBAC for AI Agent Systems: Authorization Patterns Beyond Static Roles

ai-agentssecurityrbacauthorizationmulti-agentgo

Executive Summary

Role-Based Access Control was designed for humans with stable job functions — a developer role, an admin role, a read-only role. AI agents are neither stable nor human. Within a single task, an agent may need to read source code, open a pull request, query a database, and send a Slack notification — four distinct permission domains requiring four different privilege levels that may all expire the moment the task completes. Traditional RBAC collapses under this pressure: you either over-privilege a single role to cover every possible operation, or you thrash role assignments between subtasks, generating audit noise and race conditions that make security reviews meaningless.

The industry has converged on a hybrid model: RBAC sets structural boundaries (a code-review agent can never delete production databases), while Attribute-Based Access Control (ABAC) enforces runtime constraints (this specific agent, for this specific PR review, can read files in this repository for the next 12 minutes). The tool interface becomes the primary permission boundary, not the agent identity. Per-task credentials replace ambient delegated tokens, and every authorization decision is anchored to signed context that carries user identity, tenant ID, session ID, and scope claims through every hop of a multi-agent chain.

For teams building Go backends with RBAC systems — like the current Zylos cws-core work — the practical implication is architectural: authorization should be designed at the request level, not the user level. The shift requires treating agents as first-class principals in the identity system, issuing them per-task OAuth tokens with automatic expiration, and enforcing scope narrowing at each delegation hop rather than inheriting the initiating user's full permission set.

1. Why Traditional RBAC Fails for Agents

1.1 The Confused Deputy Problem

The most common failure mode in early agent deployments is implicit ambient authority. An agent is given a user's OAuth token for convenience — it needs to "act like the user" — and inherits every scope that token carries: email, storage, GitHub, Jira, production databases. When a prompt injection attack targets the agent, it exploits this ambient authority without triggering a single permission check. The agent is already authorized for everything.

This is the confused deputy problem: a system that holds more privileges than it needs for any specific task becomes a proxy for attackers who can coerce it into exercising those excess privileges. For AI agents, the attack surface is the prompt itself, and the blast radius scales with the scope of inherited credentials.

1.2 Role Thrashing

The alternative naive approach — assign narrow roles and reassign as the task evolves — generates its own failure mode. A code-review agent that needs different permissions for "reading a PR," "fetching CI results," and "posting review comments" might go through three role assignments in 30 seconds. Each assignment generates an audit event, and the audit trail becomes uninterpretable noise rather than a useful security record. More critically, race conditions emerge in multi-agent systems where two agents contending for the same role assignment can end up in undefined permission states.

1.3 The Five Identity Layers

Multi-tenant agent deployments reveal a structural gap in traditional identity models. In a conventional web application, five identity concepts all refer to the same person: who triggered the action, who the executing credential belongs to, who authorized the delegation, which tenant owns the data, and who is recorded in downstream audit logs. In an agent system, these are five separate actors that must be tracked independently:

  • Trigger identity — the human who initiated the workflow
  • Execution identity — the OAuth credential making each API call
  • Authorization identity — the principal whose delegated grant authorizes the agent
  • Tenant identity — the organizational boundary for the operation
  • Attribution identity — the human recorded in downstream systems for compliance

Collapsing these five into a single "agent user" makes audit trails unreadable and compliance reviews impossible. Separating them requires deliberate architectural choices from day one.

2. The Hybrid RBAC + ABAC Model

2.1 RBAC for Structural Boundaries

RBAC remains appropriate for high-level, invariant constraints that define what categories of operation are ever permissible for an agent class. Examples:

  • A code-review agent can never delete resources in production
  • A monitoring agent has read-only access to all environments
  • A deployment agent can only write to namespaces it explicitly owns
  • A user-facing agent can never query raw credential stores

These rules are slow-changing, easy to audit, and represent organizational risk decisions. They belong in RBAC policy. Importantly, they should be defined at the tool interface level, not the agent identity level — a delete_production_resource tool should simply not exist in a code-review agent's tool set, regardless of what role it holds.

2.2 ABAC for Runtime Constraints

ABAC handles the volatile, context-dependent constraints that change per request:

  • This agent may read files in /repos/frontend/** for the duration of session sess_abc123
  • This agent may call the payment API only during business hours for tenant acme-corp
  • This agent may write to the staging database only when deployment_stage = canary
  • This agent's token expires in 8 minutes and cannot be renewed without user re-authorization

ABAC evaluates these claims against a signed context object that accompanies every tool call. The context is immutable once issued and carries a cryptographic signature preventing tampering mid-chain.

2.3 The Tool Interface as Permission Boundary

The highest-leverage RBAC investment is eliminating broad tools in favor of narrowly scoped operations. Instead of manage_github (which implies read, write, delete, admin), expose:

open_pull_request       # write: PR creation only
read_file               # read: single file, path-restricted
list_open_issues        # read: issue listing only
post_review_comment     # write: PR comments only

This design means RBAC policies map to tools one-to-one, making policy audits readable by non-engineers. It also eliminates parameter injection attacks: an agent that only holds read_file permission cannot be coerced into deleting files regardless of what appears in its prompt context.

3. Agent Identity and Delegation Chains

3.1 Agent-as-Principal vs. On-Behalf-Of

Two delegation patterns dominate production deployments, and the choice has significant audit implications.

Agent-as-Principal assigns the agent a dedicated service account with fixed, pre-approved scopes. This is simple to engineer and appropriate for fully autonomous background jobs (scheduled enrichment, batch processing, system-to-system workflows with no originating human). The critical drawback: audit trails collapse into the agent's identity. Every downstream action shows the agent as actor, making per-user accountability impossible and failing most compliance frameworks that require human attribution.

On-Behalf-Of (OBO) threads the originating user's identity through every tool call while maintaining the agent as a distinguishable executing party. RFC 8693 formalizes this: "the acting party is still distinguishable from the party on whose behalf it is acting." This is the correct default for any agent handling user requests. The engineering cost is higher — token exchange flows, context propagation, identity correlation at every hop — but it's the only model that produces audit trails meaningful to compliance reviewers.

The practical recommendation: use agent-as-principal for headless batch jobs and automated monitoring, OBO for any agent that processes user-initiated requests.

3.2 Scope Narrowing in Delegation Chains

Multi-agent architectures introduce a structural risk: a parent agent with broad permissions delegates a subtask to a child agent, and the child inherits the same broad token. Scope narrowing inverts this: each delegation hop must produce a token with equal or narrower permissions than the issuer holds. A parent with read+write authority can delegate only read to a child; it cannot grant what it doesn't have, and it cannot escalate.

Emerging token formats make this enforceable offline without a round-trip to an authorization server:

  • Macaroons: Append-only caveat chains where each holder can add restrictions but never remove them
  • Biscuits: A public-key variant allowing holder-bound tokens with verifiable attenuation
  • Wafers: Scope narrowing via signed constraint overlays

These formats create verifiable, append-only delegation chains. An orchestrator that issued a subtask token can prove its own chain of authority, trace the full path of delegation, and identify the exact hop where a permission boundary was violated.

3.3 Cross-Provider Delegation: The Unsolved Problem

The hardest open problem in 2026 is cross-provider delegation chains. When a Claude-authenticated orchestrator delegates a subtask to a GPT-4-authenticated subagent that then accesses Salesforce APIs, the identity chain spans three providers with three authentication methods and three trust domains. No single audit system captures the complete path. SPIFFE/SPIRE workload identity provides partial solutions — mTLS certificates rooted in a shared trust domain can authenticate agent-to-agent calls — but the policy question of what cross-provider delegations are permitted remains application-specific. The decentralized-identity community is actively working on scoped delegation chain standards, but no production-ready specification exists as of mid-2026.

4. Implementation Patterns for Go Backends

4.1 Casbin for Policy-as-Code

Apache Casbin is the most widely adopted Go authorization library for agent systems. It supports ACL, RBAC, ABAC, and Relationship-Based Access Control (ReBAC) through a unified PERM metamodel (Policy, Effect, Request, Matchers), with adapter-based policy storage for databases, Redis, and file systems.

For agent authorization, the critical Casbin capability is domain-based RBAC — roles scoped to a tenant domain — combined with ABAC extensions for contextual attributes. A policy definition that enforces the core agent authorization pattern looks like:

[request_definition]
r = sub, dom, obj, act, context

[policy_definition]
p = sub, dom, obj, act

[role_definition]
g = _, _, _   # user-role-domain triples

[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act
    && r.context.expires_at > now()
    && r.context.session_id != ""

The context attribute enforces temporal expiration and requires a non-empty session ID — a cheap approximation of ABAC runtime constraints without a separate policy engine.

For more complex attribute evaluation (risk scores, time-window constraints, data classification labels), Cerbos and OPA integrate cleanly with Go backends via gRPC. Cerbos evaluates policies as YAML with explicit RBAC and ABAC rule separation; OPA uses the Rego language with broader applicability but steeper learning curve.

4.2 Per-Task Credential Issuance

The recommended pattern replaces ambient user token propagation with per-task credential issuance at the orchestrator boundary:

  1. User initiates a task → orchestrator issues a short-lived OAuth token scoped to the exact tools the task requires
  2. Token is bound to: user ID, tenant ID, session ID, task ID, allowed tool list, expiry (typically 5-15 minutes)
  3. All subagents receive this token via the signed context object — never the user's full OAuth token
  4. At completion or failure, the token is revoked explicitly; expiry provides the backstop

This pattern eliminates ambient authority by construction. A prompt injection attack that tries to expand scope cannot succeed — the token simply does not carry the requested permission, and no code path can grant what the token doesn't hold.

4.3 Config-Driven RBAC Over Code-Based Role Checks

A recurring pattern in production agent platforms is migrating role checks from code into versioned configuration files. The motivation: role checks in application code require a deployment to change. A misconfigured permission discovered at 3 AM cannot be corrected without a code push and a service restart.

Config-driven RBAC stores the role-permission mapping in a versioned YAML or JSON file validated at startup. The authorization middleware reads this configuration at initialization and fails closed if any validation error occurs. This enables:

  • Permission changes without code deployments (configuration reload)
  • Policy audits readable by non-engineers
  • Schema validation catching invalid policy combinations before they reach production
  • Version-controlled policy history in the same repository as application code

4.4 Signed Context Objects

The signed context object is the foundational primitive of request-scoped authorization. Every agent tool call should carry an immutable, signed payload containing:

{
  "user_id": "usr_abc123",
  "tenant_id": "tenant_acme",
  "session_id": "sess_xyz789",
  "request_id": "req_def456",
  "task_id": "task_ghi012",
  "allowed_scopes": ["read_file", "list_open_issues", "post_review_comment"],
  "issued_at": 1747728000,
  "expires_at": 1747728900,
  "delegation_depth": 1,
  "parent_agent_id": "agent_orchestrator_v2"
}

The signature prevents tampering mid-chain. The delegation_depth field enforces maximum chain length (typically 3-5 hops) to prevent unbounded delegation trees. The parent_agent_id creates the audit lineage: every action is traceable to its originating task.

5. Multi-Tenant Authorization Architecture

5.1 Isolation Levels and Trade-offs

Three architectures exist for multi-tenant agent deployments, each representing a different point on the isolation-vs-cost curve:

ArchitectureIsolationCostUse Case
Per-tenant processesStrongestHighestRegulated industries, high-value tenants
Per-tenant credentials, shared processPracticalModerateB2B SaaS default
Shared agent with policy-enforced tenant tagsWeakestLowestConsumer applications, low-risk workflows

The per-tenant credentials model is the practical default: each tenant has distinct OAuth client credentials stored in the authorization system, and the agent resolves the correct credential set via the tenant ID in the signed context. No tenant can accidentally receive another tenant's credential — the lookup is keyed, not positional.

5.2 Channel-Owned Authorization

An emerging pattern in team collaboration contexts (Slack integrations, Lark bots, multi-channel agents) binds OAuth grants to channels rather than individual users. Any team member posting in the channel inherits its permissions automatically, eliminating per-person OAuth flows and the associated offboarding complexity when team members leave. The authorization identity is the channel; the attribution identity is the specific team member who triggered the action. This separation provides both operational simplicity and compliance auditability.

5.3 Privilege Escalation Prevention

Three injection patterns require explicit prevention in any production agent authorization system:

  • Parameter injection: An agent receiving resource identifiers (repository names, database tables, file paths) from message payloads can be coerced into operating on unintended resources. Prevention: all resource targets must come from configuration files or signed context, never from free-text input.
  • Token reuse across tenants: Without explicit validation, a token issued for tenant A may be accepted by a service that operates for tenant B. Prevention: validate at startup that all credential-identifier pairs match expected tenants, fail closed on mismatch.
  • Stale user mappings in multi-worker deployments: Per-process in-memory caches of user-to-authorization mappings diverge across worker instances. Prevention: store authorization state in a shared external store (Redis, database) with TTL-based invalidation.

6. Observability and Audit Requirements

Authorization without observability is incomplete. Every authorization decision in a multi-agent system should emit a structured audit event containing:

  • Principal identity (agent ID + delegation lineage)
  • Resource and action requested
  • Policy decision (permit/deny) and which rule triggered
  • Signed context object reference
  • Timestamp and latency

These events feed two distinct consumers: security teams performing compliance audits (who need the full attribution chain) and engineers debugging permission failures (who need the specific rule that fired). Combining both consumers into the same log stream works if the schema is consistent and the fields are indexed.

Performance budget for authorization evaluation is typically sub-10ms for co-located policy engines (Casbin embedded in the service process) and sub-50ms for network-separated policy services (OPA sidecar, Cerbos hub). Authorization that adds more than 50ms to the critical path in an agent tool call will degrade user-visible latency noticeably and is typically resolved by policy caching with bounded TTL.

7. Implications for Zylos cws-core

The Go backend RBAC work in cws-core sits at the intersection of these patterns. A few specific design choices that will pay dividends long-term:

Define authorization at the tool/action level from the start. RBAC policies that map to fine-grained operations (not broad capabilities) are auditable and safe to delegate. Retrofitting this after launch is expensive.

Implement the five identity layers explicitly. Even if today's users are all direct human users, agent workflows will arrive. Building the data model with separate trigger, execution, authorization, tenant, and attribution fields avoids a schema migration later.

Adopt signed request context as the authorization primitive. JWT-based context objects carrying agent lineage, session binding, and expiry travel naturally through gRPC and REST APIs without requiring middleware changes at each service boundary.

Use Casbin's domain-based RBAC for multi-tenant isolation. The model handles the tenant-scoped role assignment pattern cleanly and integrates with standard Go HTTP middleware via Casbin's enforcer API.

Treat per-task credential issuance as table stakes for any agent integration. When the first agent workflow lands on cws-core, the authorization system should already support issuing narrow-scoped tokens with automatic expiration — retrofitting this under production load is painful.


Sources: