Appearance
9.4 — Authentication, Authorization, RBAC, and OAuth
1. What is it?
Authentication (authN) verifies who someone is. Authorization (authZ) determines what they're allowed to do. RBAC (Role-Based Access Control) is a common authorization model assigning permissions to roles, and users to roles, rather than managing permissions per individual user. OAuth is a standard protocol for delegated authorization — letting a user grant a third-party application limited access to their data on another service, without sharing their actual password with that application.
2. Why does it exist?
Every prior security chapter in this Part (9.1-9.3) has referenced "authorization enforced in code" as the essential backstop against a manipulated model — this chapter is where that authorization is actually designed and implemented as a coherent system, rather than assumed as a given. AI systems raise this discipline's stakes specifically because an agent's tool-calling capability (Part 3.3) means authorization decisions happen not just at a human clicking through a UI, but at every single tool call an agent makes, potentially many times per user interaction, autonomously.
3. What problem does it solve?
AuthN solves "is this really who they claim to be." AuthZ solves "given who they are, what should they be allowed to do or see." RBAC solves "how do I manage authorization at scale without a per-user permission list becoming unmanageable as an organization grows." OAuth solves "how does a third-party AI tool/integration get scoped access to a user's data in another system, without that user handing over their actual credentials" — directly relevant whenever an AI agent needs to act on a user's behalf against an external system (their calendar, their CRM, Part 10.1).
4. How does it work internally?
AuthN vs. AuthZ — a distinction that matters acutely for agents
Authentication"You are indeed user_123" — verified via password, token, SSO (Part 10.1)
Authorization"user_123 may view their own orders, NOT other users' orders, NOT delete their account without confirmation"
Every tool call an agent makes on behalf of a user (Part 3.3) must pass through this same two-step check — the agent's own "authentication" to your backend (it's a trusted internal component) is not the same as the end user's authorization for the specific action being requested through it. This distinction, easy to blur in a simple system, is precisely what Part 3.3/9.2/9.3's "bind user scope at tool-construction time" pattern exists to enforce correctly.
RBAC — roles as the unit of authorization
User "alice"
Role: "support_agent"
Permissionsview_tickets, respond_to_tickets
RBAC's value is managing authorization at scale: instead of tracking "can alice view tickets, can alice respond to tickets, can alice escalate tickets..." individually for every user, you assign alice a role, and the role's permission set is defined and updated once, centrally. For an AI agent, this means a tool's execution should check the current user's actual role-derived permissions (fetched from your authoritative identity/authorization system) before executing, not trust anything about permissions that might appear in the model's own context or reasoning.
OAuth — delegated, scoped access without credential sharing
1. User clicks "Connect your calendar" in your AI assistant's settings
2. User is redirected to their calendar provider's own login page (NOT yours —
your AI assistant never sees the user's actual calendar-provider password)
3. User approves a SPECIFIC, SCOPED set of permissions ("read calendar events,"
NOT "full account access")
4. Calendar provider issues your AI assistant a scoped ACCESS TOKEN
5. Your AI assistant's tool calls use this token — which only grants the
specifically approved scope, and can be revoked by the user at any time
without changing their actual passwordThis is directly relevant to AI agent tool design (Part 3.3/10.1): when an agent needs to act on a user's behalf against a third-party service, OAuth's scoped-token model is what lets you request (and the user explicitly approve) exactly the narrow capability the specific tool needs — directly implementing Part 9.2's least-privilege principle at the third-party-integration layer, rather than requesting broad, unscoped access "to be safe" or, worse, asking the user to hand over their actual password.
A JWT/OIDC pitfall worth flagging here explicitly: signature verification is not the whole check
OIDC's ID token (an authentication-specific JWT, section 4 above) and any JWT-based access token both need more than a valid signature to be safely accepted: a verifier must also pin the expected signing algorithm explicitly rather than trusting the algorithm the token's own header claims to use (closing the alg: none and RS256→HS256-downgrade-via-public-key-as-HMAC-secret attacks), and explicitly validate the audience and issuer claims (a token correctly signed by a trusted IdP but issued for a different application, or from a different tenant/environment, must still be rejected). Part 10.1's chapter carries the full explanation and a complete, safe jwt.decode(..., algorithms=[...], audience=..., issuer=...) call — treat that as this chapter's companion on the specific mechanics of a safe decode, since the authorization model here (RBAC roles, section 4) is only as trustworthy as the token verification feeding it.
5. Simple mental model
Authentication is checking someone's ID at a building's front desk — confirming who they are. Authorization is the specific keycard permissions that ID holder's badge actually has — which floors and rooms it opens, distinct from simply knowing who the person is. RBAC is defining keycard permission templates by job title ("all support agents get this exact keycard profile") rather than custom-configuring every single employee's keycard individually. OAuth is like giving a valet a special valet key that only starts the car and opens the door, not the trunk or the glovebox — delegated, scoped access without handing over your actual full house/car key.
6. Real-world example
An AI assistant integrates with a customer's CRM to look up account details on behalf of support agents using the assistant. Using OAuth with a narrowly-scoped "read account details" permission (rather than requesting broad CRM admin access, or worse, storing an individual support agent's actual CRM password) means that even if the AI assistant's own infrastructure were ever compromised, the attacker would only gain the specific, limited access the OAuth scope actually granted — not full administrative control of the customer's CRM. This is a direct, concrete illustration of Part 9.2's excessive-agency principle applied specifically to third-party integration design.
7. Architecture diagram — vulnerable vs. secure
Vulnerable (a breach of the AI system = a breach of the user's full account on the third-party service):
AI systemstores user's actual password/full credentials
Third-party service (CRM)
Secure (a breach only exposes the narrow, revocable scope the token actually grants):
AI systemstores ONLY the token, never the password
Third-party service (CRM)
8. Production considerations
- Every tool call touching user-specific or sensitive data must independently verify current authorization, fetched from your authoritative identity/authorization system at call time — never inferred from stale context or, worse, trusted from anything the model itself asserts.
- Use OAuth (or an equivalent scoped-delegation mechanism) for any third-party integration an agent needs, rather than storing and using a user's actual credentials directly — Part 9.2's least-privilege principle applied to external integrations specifically.
- Design RBAC roles around actual job functions, reviewed periodically as roles and responsibilities evolve — a role definition that's grown overly broad over time ("just add this permission for now") quietly erodes the least-privilege benefit RBAC exists to provide.
- Revoke and rotate OAuth tokens appropriately (on user request, on employee offboarding, on a defined expiration) — a scoped token that's never revoked or rotated is a long-lived risk that partially undermines OAuth's revocability advantage over static credentials.
9. Common mistakes
- Confusing authentication with authorization — verifying who someone is and assuming that alone determines what they can do, missing the separate, necessary authorization check.
- Storing a user's actual third-party credentials directly instead of using OAuth's scoped-token delegation, creating unnecessary, avoidable blast radius if the AI system is ever compromised.
- RBAC role definitions that have grown overly broad over time through incremental, unreviewed additions ("just give this role access to X too, for now"), quietly eroding least-privilege.
- Checking authorization once at the start of a long agent run and trusting it for the entire run's duration, rather than re-verifying at each consequential tool call — a user's permissions can change mid-session (Part 5.7's stale-authorization warning applies directly here).
10. Security considerations — mitigation summary
Enforce authorization at every tool call, independently, against a current, authoritative source — never inferred or cached indefinitely. Use OAuth's scoped delegation for third-party integrations rather than storing raw credentials. Design and periodically audit RBAC roles for least-privilege drift. Treat token revocation/rotation as a first-class operational practice, not an afterthought.
11. Performance considerations
- Fetching current authorization state on every tool call adds a real, small latency cost (typically a fast cache-backed lookup, Part 1.6) — worth the cost given the alternative (stale or cached authorization) risks exactly the security gap Part 5.7's authorization-staleness warning describes.
12. Cost considerations
- Identity/authorization infrastructure (whether self-built or a managed identity provider) is a real, distinct infrastructure cost line item — generally small relative to the risk it mitigates, and rarely a place to cut corners for cost savings given the severity of authorization failures.
13. When to use it
Every production AI system handling any user-specific or sensitive data, and every integration with a third-party service acting on a user's behalf — essentially universal for enterprise AI systems.
14. When NOT to over-apply it
A genuinely single-user, fully-trusted internal tool with no multi-user data separation and no third-party integration has less need for the full RBAC/OAuth machinery — though basic authentication remains relevant even here, and the underlying discipline (verify authorization at the point of action) scales down cheaply even when the full formal infrastructure isn't warranted.
15. Alternatives and trade-offs
| Approach | Good for | Weak point |
|---|---|---|
| RBAC | Manageable authorization at organizational scale | Can drift toward overly broad roles without periodic review |
| Attribute-based access control (ABAC) | More fine-grained, context-sensitive authorization than RBAC | More complex to design and reason about |
| OAuth for third-party delegation | Scoped, revocable access without credential sharing | Requires the third-party service to support OAuth; more integration complexity than storing a raw credential |
| Storing raw third-party credentials (anti-pattern) | Simpler initial integration | Unnecessary, avoidable blast radius on compromise |
16. Practical Python/code example
python
async def authorized_tool_call(tool_fn, current_user_id: str, required_permission: str, **kwargs):
"""
Wraps any tool call with a fresh, per-call authorization check against the
authoritative permission source, never trusting cached or inferred authorization.
Args:
tool_fn: The tool implementation to call if authorized.
current_user_id (str): The authenticated user making this request.
required_permission (str): The specific permission this tool call requires.
**kwargs: Arguments to pass to the tool.
Returns:
The tool's result, or a rejection if unauthorized.
"""
user_permissions = await fetch_current_permissions(current_user_id) # fresh lookup, not cached indefinitely
if required_permission not in user_permissions:
return {"error": f"user lacks required permission: {required_permission}"}
return await tool_fn(**kwargs)17. Production-quality example
An OAuth-scoped third-party integration tool, directly implementing section 7's secure architecture:
python
import logging
logger = logging.getLogger("oauth_integration")
class CRMIntegrationTool:
"""A CRM lookup tool using an OAuth-scoped access token, never the user's
actual CRM credentials."""
def __init__(self, oauth_token_store, current_user_id: str):
"""
Args:
oauth_token_store: Store of per-user OAuth tokens, scoped and revocable.
current_user_id (str): The user this tool instance is scoped to.
"""
self._token_store = oauth_token_store
self._current_user_id = current_user_id
async def get_account_details(self, account_id: str) -> dict:
"""
Looks up CRM account details using the current user's scoped OAuth token.
Args:
account_id (str): The CRM account to look up.
Returns:
dict: Account details, or an error if the token is missing/revoked/expired.
"""
token = await self._token_store.get_valid_token(self._current_user_id, scope="crm:read")
if token is None:
logger.warning("no valid CRM OAuth token for user=%s", self._current_user_id)
return {"error": "CRM integration not connected or authorization expired"}
async with httpx.AsyncClient() as client:
response = await client.get(
f"https://crm.example.com/api/accounts/{account_id}",
headers={"Authorization": f"Bearer {token}"},
)
response.raise_for_status()
return response.json()18. Short exercise
A customer's AI assistant currently stores each employee's actual CRM username and password to perform lookups on their behalf. Using this chapter's OAuth model, describe the specific migration steps and the concrete security improvement each step provides.
19. Interview questions
- Explain the difference between authentication and authorization with a concrete example of a system that has one but not the other.
- Why is OAuth's scoped-token delegation preferable to storing a user's actual third-party credentials, specifically for an AI agent's tool access?
- Why should authorization be re-verified at every consequential tool call rather than checked once at the start of an agent run?
20. FDE/customer scenario
Customer: "Our AI assistant needs to check employees' calendars — should we just have it use each employee's login credentials?"
No — the credible, secure recommendation is OAuth-based delegated access with a narrow, specific scope ("read calendar events" only, not full account access), which the employee explicitly approves once and can revoke at any time, and which limits the blast radius of any future AI-system compromise to exactly that narrow scope — a direct, concrete application of this chapter's core principle over the much riskier (and, for most calendar providers, entirely avoidable) alternative of directly handling employee passwords.
Key takeaways
- Authentication (who) and authorization (what they can do) are distinct checks, and an agent's tool calls need both verified per-action, not assumed from a single upfront check.
- RBAC manages authorization at scale via roles, but requires periodic review to prevent least-privilege drift.
- OAuth's scoped, revocable delegation is the correct pattern for AI agents acting on a user's behalf against third-party services — never store or use raw user credentials directly.
Things you should be able to explain
- The distinction between authentication and authorization, with a concrete example.
- Why OAuth's scoped tokens are safer than storing raw third-party credentials for agent tool access.
Things you should be able to build
- A fresh-lookup authorization wrapper for tool calls and an OAuth-scoped third-party integration tool.
Common mistakes
- Confusing authentication with authorization.
- Storing raw third-party credentials instead of using OAuth delegation.
- Checking authorization once per session instead of per consequential action.
Recommended next chapter
05-secrets-and-api-security.md