
Okta/Azure AD + multi-user agents: patterns for SSO, RBAC, and audit logs when agents take actions
Most teams wiring agents into Okta or Azure AD discover the same thing: SSO is the easy part. The hard part is getting clean patterns for RBAC, per‑user authorization, and audit logs once agents start taking real actions in systems like Google Workspace, Slack, GitHub, or Salesforce.
Quick Answer: Multi-user agents behind Okta/Azure AD work best when you treat the IdP as the source of identity and roles, enforce authorization in the agent runtime (not prompts), and route every tool call through an auditable, user-scoped execution layer. Arcade’s MCP runtime gives you this pattern out of the box with SSO, RBAC, and audit logs wired to each action.
Frequently Asked Questions
How should I think about SSO for multi-user agents with Okta or Azure AD?
Short Answer: Treat your agent runtime as an OAuth/OIDC client of Okta/Azure AD, use SSO to authenticate humans, and then map those identities to user-specific agent sessions and tool credentials.
Expanded Explanation:
For multi-user agents, Okta/Azure AD handle who the user is, not what the agent can do. Your IdP issues an ID token (and optionally access tokens) that identify the user, plus group/role claims. The agent runtime (Arcade, in this pattern) consumes those tokens, establishes a user session, and then drives just‑in‑time OAuth to downstream systems (Gmail, Calendar, Slack, GitHub, Salesforce) on behalf of that user.
Instead of embedding long‑lived secrets in prompts or service accounts, the runtime maintains the mapping:
- Okta/Azure AD user → Arcade user
- Arcade user → per‑app OAuth grants (e.g., Gmail, Slack)
- Per‑app grants → concrete tools (e.g.,
Google.SendEmail,Slack.PostMessage)
SSO is the entry point; the authorization model for agent actions lives in the runtime.
Key Takeaways:
- Use Okta/Azure AD for identity and login; use the agent runtime for tool authorization.
- Each human user gets a distinct agent “persona” and credential set, not a shared bot identity.
How do I wire the end-to-end flow: SSO → agent → tools with user-specific permissions?
Short Answer: Authenticate with Okta/Azure AD, create or look up the Arcade user, then drive per-user OAuth for tools and execute MCP tools under that user’s identity.
Expanded Explanation:
In practice, this is a two-tier auth flow:
- Tier 1 – IdP SSO: Your front-end or orchestrator redirects to Okta/Azure AD. Once the user authenticates, you get an OIDC ID token with their subject (
sub), email, and group/role claims. - Tier 2 – Tool auth via Arcade: You pass the IdP identity into Arcade. Arcade creates/looks up the user and handles downstream OAuth flows (e.g., Google, Slack) for that user. Tokens are stored and refreshed behind Arcade’s walls, never exposed to the LLM.
Once that’s in place, every tool call from the agent looks like “run this MCP tool as user X with OAuth grant Y,” enforced by Arcade.
Steps:
- Set up SSO in your app:
- Register your app in Okta/Azure AD as an OIDC client.
- Configure redirect URIs to your backend or agent gateway.
- Map IdP users into Arcade:
- On successful SSO, call Arcade’s SDK (e.g.,
client.auth.start(...)) with the IdP subject/email. - Store the mapping between your app’s user ID and Arcade’s user ID.
- On successful SSO, call Arcade’s SDK (e.g.,
- Attach tools and run the agent:
- Initiate OAuth for tools (Google, Slack, etc.) via Arcade’s built-in flows.
- Configure your MCP client (Cursor, Claude, LangGraph, etc.) to talk to Arcade, and execute tools under that user context.
What’s the right pattern: service-account bots vs user-specific permissions for agents?
Short Answer: For multi-user agents, user-specific permissions via OAuth + IdP identity are the right pattern; service-account bots are a dead end for anything that has to respect least privilege and real-world access controls.
Expanded Explanation:
Service accounts are tempting: one credential, works in the demo. They break down immediately in production:
- Every action looks like it came from the same “bot” user.
- Permissions don’t match the real user’s access (e.g., the bot can read calendars or repos the human never could).
- Security teams lose visibility; you lose attribution. When something goes wrong, there’s no clear “who clicked send.”
User-specific permissions flip this model: each agent action carries the identity of the human, enforced by the runtime. Arcade integrates with your existing OAuth flows, so when the agent sends an email, it’s the user’s Gmail token; when it updates a record in Salesforce, it’s that user’s scoped access. No more “god-mode” bots.
Comparison Snapshot:
- Service-account bots:
- Single credential, broad access, hard to audit.
- Fast to prototype, unsafe at scale.
- User-specific permissions via Arcade + IdP:
- Each user has scoped OAuth grants aligned with their real access.
- Every action is attributable and auditable.
- Best for:
- Anything customer-facing, multi-tenant, or regulated (sales agents, internal copilots, support agents) where you care about least privilege and clean audit trails.
How do I enforce RBAC and permission gates for agents using Okta/Azure AD roles?
Short Answer: Pull roles/groups from Okta/Azure AD, map them to Arcade policies, then gate tools and actions at the runtime level—not in the prompt.
Expanded Explanation:
Okta/Azure AD already know your roles and groups (e.g., SalesManager, SupportAgent, Engineering). The key is to translate those identities into concrete permissions on tools and actions:
- IdP grants: roles and groups in the ID token or via the Graph API.
- Arcade policies: which MCP tools, operations, and scopes are allowed for each role.
- Runtime enforcement: every tool call checks “is this user allowed to call
Google.SendEmailwith these parameters?” before executing.
This turns RBAC into code, not vibes. You don’t rely on “hey, agent, please don’t email executives” in a system prompt. You encode “SupportAgent can only email within @customer.com domains” and let the runtime enforce it.
What You Need:
- A consistent mapping from IdP roles/groups → Arcade roles/policies (e.g., via claim mapping or SCIM).
- Runtime-level authorization checks attached to tool execution (Arcade MCP runtime with permission gates on tools like
Gmail.ListEmails,Slack.PostMessage,Salesforce.UpdateRecord).
How should I handle audit logs when agents take actions as users?
Short Answer: Centralize audit logging in the runtime so that every tool call includes who (IdP identity), what (tool + parameters), where (target system), and when (timestamp), and make those logs queryable for security and compliance.
Expanded Explanation:
Once an agent can actually change real systems, auditability stops being a “nice to have.” You need to answer, with confidence:
- Who triggered this Slack message, calendar invite, or Salesforce update?
- What did the agent see and what did it send?
- Which model/tool version and which runtime path did it take?
The right pattern is to let the runtime (Arcade) own that audit trail:
- Every MCP tool execution logs: user ID (from Okta/Azure AD via Arcade), tool name, parameters, target resource, result, timestamps, and error metadata.
- Logs live outside the LLM context and can be streamed to your SIEM (Splunk, Datadog, etc.).
- You can correlate: Okta/Azure AD sign-in events → Arcade execution logs → downstream app logs (e.g., Gmail, Slack).
This satisfies security review questions like “Show me every email this agent sent as user X last week” without scraping chat transcripts.
Why It Matters:
- Security teams get traceability for every change driven by agents, not just “it came from the bot.”
- You can detect and respond to misuse or misconfiguration quickly, without guessing which user or tool was involved.
Quick Recap
For Okta/Azure AD + multi-user agents, the winning pattern is: IdP for identity and roles, Arcade’s MCP runtime for user-specific tool authorization and execution, and strict runtime-enforced RBAC and audit logs for every action. Agents stop being opaque bots with god-mode service accounts and become predictable, governable actors that operate within your existing SSO and security model.