Okta Cross App Access (XAA / ID-JAG) in Nirmata AIControls: standards-based authorization for AI agents

18 August 2026

Okta Cross App Access (XAA / ID-JAG) in Nirmata AIControls: standards-based authorization for AI agents

AIControls now performs the ID-JAG token exchanges on your agents’ behalf — so agents need no protocol code — and policy-checks, budgets, and attributes every delegated MCP and LLM call to the human it acts for. ID-JAG answers may this agent act for this user? AIControls answers what did it actually do?

Cross App Access (XAA) is Okta’s deployment of the IETF Identity Assertion JWT Authorization Grant (ID-JAG, draft-ietf-oauth-identity-assertion-authz-grant-04): the enterprise IdP — not the end user — decides which agent may reach which resource.

Nirmata AIControls supports the profile on both sides of the gateway: as the requesting client performing the exchanges for ID-JAG-unaware agents, and as the authorization server (RFC 7591 DCR, RFC 7523 grant validation, RFC 7009 revocation, RFC 8414/9728 metadata) protecting the MCP servers and LLM endpoints it fronts. Every delegated call it carries is CEL-policy-checked, budgeted, and written to an audit record attributed to the delegating human — the layer a token exchange alone can’t provide.

Why per-user consent breaks for agent fleets

An agent working one task crosses identity domains constantly — from your IdP’s world into a SaaS vendor’s MCP server, dozens of times per session. Per-user OAuth consent was designed for a person connecting one app to another, occasionally; applied to agent fleets it produces grant sprawl IT never sees, scopes set by whatever a user clicked through, and downstream access that survives offboarding. ID-JAG’s design premise — argued by Okta’s Aaron Parecki, an author of the draft alongside Karl McGuinness and Ping Identity’s Brian Campbell — is that in the enterprise, app-to-app connectivity is an administrator’s decision, not an end-user consent event. 

The Identity Assertion JWT Authorization Grant is an active Internet-Draft on the Standards Track. What makes it deployable today is that the profile is young but the machinery it assembles is not: an RFC 8693 token exchange at the enterprise IdP turns the user’s identity into a short-lived, single-audience identity assertion grant (minted only if the admin approved the app-to-app connection), and an RFC 7523 jwt-bearer grant at the resource’s authorization server turns that assertion into an ordinary scoped access token. No browser, no consent screen. The draft and the MCP Enterprise Managed Authorization extension cover the protocol in depth — this post is about what AIControls does with it.

AIControls (Gateway) performs legs 2–3 on the agent’s behalf and enforces policy on step 4 — the agent never sees a browser, a consent screen, or either exchange. The ID-JAG is minted only if the admin approved the app-to-app connection. 

How AIControls supports XAA / ID-JAG

AIControls (Gateway) sits in front of both MCP servers and LLM endpoints, and implements both protocol roles — the same delegated identity that authorizes a tool call rides along on every model request the agent makes through the gateway.

As the requesting client — agents need zero ID-JAG code

For governed egress to third-party MCP servers, the gateway performs both legs server-side on every delegated call path. Agents authenticate to the gateway exactly as they already do; the exchange is invisible to them. Configuration is UI-driven — IdP and resource token endpoints, client authentication, audience, and scopes are set per upstream server in the AIControls console:

MCP server registration in the AIControls UI with Cross App Access auth selected — endpoints, client auth method, scopes. 

Details that matter in production: client authentication supports private_key_jwt (Okta’s preferred method), client_secret_basic, and client_secret_post; requested scopes carry through both legs, so the token that reaches the vendor is scoped to what the admin configured, not what a consent screen once allowed; and the real-world divergences between authorization servers — audience vs. resource vs. both in leg 1, separately registered resource clients vs. unauthenticated leg 2 — are explicit settings rather than guesses. 

As the ID-JAG authorization server — protecting what the gateway fronts

External agents — an Okta-registered chatbot, a SaaS app’s agent runtime — reach your MCP servers and proxied LLM endpoints through the same standards, with AIControls terminating the resource side:

Endpoint Spec What AIControls does
/.well-known/oauth-authorization-server RFC 8414 Publishes AS metadata — token endpoint, grant types, JWKS — so clients configure themselves
/.well-known/oauth-protected-resource RFC 9728 Publishes protected-resource metadata for the fronted MCP servers and LLM endpoints
Registration endpoint RFC 7591 Dynamic client registration — agents self-register; admins approve and scope them
Token endpoint RFC 7523 Validates ID-JAG assertions against the federated IdP’s JWKS (issuer, audience, expiry, replay) and issues scoped access tokens
Revocation endpoint RFC 7009 Cuts an agent off immediately, without waiting for token expiry

To be clear about what registration means here: registration is not authorization. An agent that self-registers via DCR has an identity, nothing more — whether any ID-JAG is ever minted for it remains the admin’s decision at the IdP, which is exactly the post’s thesis applied to onboarding.

Two deliberate design choices:

  • Access tokens are short-lived with no refresh tokens — every renewal must re-present a fresh ID-JAG, so a revocation at the IdP propagates within one token lifetime instead of living on in a refresh grant.
  • And issuer/audience validation is per fronted server — a token minted for one MCP server is rejected by every other one.

The corollary is worth stating because it’s the first question in the room: delegated access ends when the delegation can no longer be renewed. A scheduled agent or overnight batch job cannot ride a user’s ID-JAG past the IdP’s willingness to re-mint it — by design. Autonomous work belongs under the agent’s own first-party machine identity, governed and budgeted in its own right; XAA is specifically the on-behalf-of path.

The token arriving is where most gateways stop — and where AIControls starts.

What runs on every delegated call

Authorization answers may this agent act for this user against this resource? The question auditors and security teams actually ask is what did it do? Because AIControls is the enforcement point, every delegated call passes through the same pipeline as first-party traffic:

Policy: Kyverno CEL policies — Git-tracked and PR-reviewable, with full boolean logic over identity, group membership, time windows, and cost state — evaluate each call before it reaches the tool or model. XAA-delegated calls carry the delegating user’s identity into the policy context:

# A sales assistant may read CRM records, but exporting customer data 
# is reserved for approved data stewards 
matchConditions: 
  - expression: object.mcp.tool != "" 
validations: 
  - expression: >- 
      !(object.mcp.tool in ['export_contacts', 'bulk_download_records']) || 
      object.user.email in params.approvedDataStewards 
    message: "Exporting customer data requires an approved data steward"

And this is the payoff — the audit row that decision produces, attributed to a named human, not an opaque client id:

// Illustrative audit record — replace with a real (sanitized) row before publish 
{ 
    "time": "2026-08-18T14:12:09Z", 
    "decision": "deny", 
    "policy": "crm-export-guard", 
    "tool": "export_contacts", 
    "agent": "Renewals Assistant", // resolved from the registered client_id 
    "user": "avery.chen@acme.example", // the delegating human, asserted in leg 1 
    "session": "ses_9f2c…" 
}

LLM traffic, not just tools: The same delegated identity governs the agent’s model calls. Model-scope policies (object.llm.model in [‘claude-sonnet-5’, …]) keep a finance team’s contract-review agent on the approved model list; prompt and response scanning catches customer PII leaving in a marketing agent’s prompts; and per-model cost lands under the delegating user, so each department’s agent spend is accountable like its people’s.

Decisions beyond allow/deny: Five enforcement modes — allow, audit, warn, deny, and require-approval — not a binary. A require-approval policy parks the call in a real human-in-the-loop queue with Slack/webhook dispatch, timeouts, and persistence, so “agent wants to issue a customer refund above $5,000” or “agent wants to send a campaign to the full contact list” becomes a reviewed event rather than a blocked or blindly-allowed one.

Budgets and limits: Token budgets, spend attribution, and anomaly detection apply to delegated traffic exactly as to an employee’s own session. An agent misbehaving on a user’s behalf trips the same wires the user would. And when a cap trips mid-session, the person (or agent) doesn’t hit a dead end: the gateway’s deny reply carries an inline exception offer — replyingrequest exception: <reason>’ files a time-boxed exception request for an administrator to approve, without leaving the tool.

Your Okta org already knows which agents exist. Which are governed?

That gap — between the agents and MCP servers registered in your IdP and the ones actually fronted by policy — is the operational problem in every XAA rollout, and it’s a Monday-morning problem, not a protocol one. AIControls reads the Okta org and closes the loop:

Discovery panel — Okta-registered AI agents and MCP servers not yet governed, with their app metadata.

Onboarding flow — one action per discovered agent: registered client, policy scope, team attribution. 

End to end: connect Okta → discover → onboard → attach policy → the agent’s first session appears grouped under its delegating user.

Where Cross App Access stands today

Okta began rolling Cross App Access out to customers in August 2026, with Auth0 B2B SaaS in early access since late July. Keycloak has experimental receiver-side support behind –features=identity-assertion-jwt — explicitly not for production; issuer-side is not implemented.

The ecosystem is filling in on both sides of the exchange, which is the actual news:

  • Requesting apps (AI clients): Claude, Cursor, Docker, VS Code, Zoom.
  • Resource apps: Asana, Atlassian, Canva, Datadog, Figma, Glean, Granola, Linear, Serval, Slack, Supabase, Zoom.
  • Identity infrastructure and gateways: Aquera, Archestra.AI, Cloudflare, Keycard, Keycloak, MintMCP, Scalekit, Stytch by Twilio, AIControls by Nirmata, WorkOS, Zuplo.
  • Early adopters: Anthropic, Webflow, HubSpot, Ramp.

Several names on that infrastructure list broker the same token flow AIControls does — that part is becoming table stakes, and that’s healthy. What runs on top of the flow is where implementations diverge, and it’s where AIControls is differentiated: policy as reviewable code (CEL in Git, not toggles in a console), five enforcement modes including a real approval queue, and cost and audit attribution that lands every delegated call under a named human. A token broker can tell you the exchange succeeded; AIControls can tell you what the agent did with it.

Try it

Get started with AIControls in less than 5 mins. Try the demo mode for a zero-setup tour of sessions/audit.

Introducing Nirmata Runtime for Kyverno: Kernel-Level Enforcement for AI Workloads

Latest

From the blog

The latest industry news, interviews, technologies, and resources.

View all blogs
Introducing Nirmata Runtime for Kyverno: Kernel-Level Enforcement for AI Workloads
Introducing Nirmata Runtime for Kyverno: Kernel-Level Enforcement for AI Workloads

Nirmata created Kyverno and donated it to the CNCF in 2020. Kyverno is now a graduated CNCF project and…

Introducing the Remediator Agent: Turning Kyverno Policy Violations into Pull Requests, Automatically.
Introducing the Remediator Agent: Turning Kyverno Policy Violations into Pull Requests, Automatically.

The AI Governance Market Is Here. Most of the Problem Remains Unsolved.