Cross App Access (XAA)
Beta
Cross App Access support is in beta. The configuration model and policy options may change before general availability.
Cross App Access (XAA) lets one application reach another application's API on a user's behalf through the identity provider both apps already trust — instead of running a separate, point-to-point OAuth connection between them. For AI agents and MCP, that means an agent can call a protected upstream MCP server for a user without the user re-consenting to every app pair, and without credentials sprawling outside the identity provider's view.
The Zuplo MCP Gateway sits in the middle of this flow and runs the XAA token exchange for you. An MCP client connects to the gateway with ordinary MCP OAuth; the gateway, acting as the XAA requesting app, mints the cross-app grant from your identity provider and redeems it at the upstream's authorization server. Neither the MCP client nor the upstream MCP server has to implement XAA itself.
The problem XAA solves
Single sign-on (SSO) solves login: a user authenticates once with an identity provider (Okta, Microsoft Entra, Auth0) and gets into every connected app. SSO does not solve app-to-app API access. When one app needs to call another app's API on the user's behalf, the two apps today run a direct OAuth flow between themselves. The IETF draft describes this as a connection that "bypasses the trusted identity provider" and is "invisible to the identity provider managing the ecosystem."
AI agents make this gap urgent. An agent in one app increasingly needs to reach into other SaaS apps' data on the user's behalf. The naive approach produces:
- Consent-screen sprawl — the user re-authorizes every agent against every downstream app individually.
- Credential sprawl — long-lived tokens scattered per app pair, invisible to IT.
- No central governance — security teams can't see or control what connects to what, and offboarding means hunting access down service by service.
XAA routes app-to-app access back through the identity provider both apps already trust. The IdP becomes the single place where IT decides which app can talk to which app, enforces conditional-access policy, and audits every delegation — while the upstream app's authorization server stays the access-token issuer. The trust boundary isn't broken; it's brokered.
How the flow works
XAA is defined by the Identity Assertion JWT Authorization Grant (ID-JAG) —
draft-ietf-oauth-identity-assertion-authz-grant. It chains two OAuth exchanges
across two authorization servers:
- Identity assertion → ID-JAG, at the identity provider, using
RFC 8693 token exchange. The
requesting app presents the user's ID token (the identity assertion) and asks
for a grant scoped to one specific target authorization server. The IdP
evaluates policy and returns a short-lived, audience-restricted ID-JAG —
a signed JWT with the header
typ: oauth-id-jag+jwt. - ID-JAG → access token, at the upstream's resource authorization server,
using the
RFC 7523 JWT bearer grant. The
requesting app presents the ID-JAG as an
assertionand receives a normal access token for the upstream API.
The ID-JAG is a grant, not an access token — it can't call an API directly. It exists only to be redeemed in the second exchange.
When the Zuplo gateway fronts an XAA-protected upstream, the gateway plays the requesting app for both exchanges:
Step by step, for a tool call to an XAA-protected upstream route:
- The MCP client connects to the gateway route with ordinary MCP OAuth — discovery, PKCE, and a bearer token issued by the gateway. This leg is not XAA. During the gateway's browser-login step, the user authenticates with the identity provider, and the gateway captures the user's IdP identity assertion.
- On a tool call, the gateway exchanges the user's ID token at the IdP for an ID-JAG audience-restricted to the upstream's resource authorization server (RFC 8693 token exchange).
- The gateway redeems the ID-JAG at the upstream resource authorization server for an upstream access token (RFC 7523 JWT bearer grant).
- The gateway forwards the tool call to the upstream MCP server with
Authorization: Bearer <upstream access token>and caches the upstream token per user for subsequent calls.
In requesting-app mode, the client → gateway leg is plain OAuth
This is the most common point of confusion. In the flow above, the MCP client never speaks XAA — it runs the standard MCP authorization flow against the gateway, and all ID-JAG exchanges happen on the gateway's outbound side. A client doesn't need any XAA support to benefit from it.
What the gateway does for you
In the XAA flow the gateway plays the requesting app, so the MCP client and the upstream MCP server are each insulated from the protocol:
- The MCP client does nothing new. It runs the same MCP OAuth flow it would for any gateway route. Claude, Cursor, ChatGPT, VS Code, and any spec-compliant client work unchanged.
- The two-exchange dance — the RFC 8693 token exchange at the IdP and the RFC 7523 JWT-bearer redemption at the upstream — runs inside the gateway. You configure endpoints and credentials; the gateway mints, redeems, caches, and refreshes.
- Per-user identity is preserved end to end. The IdP sees the specific user, the upstream sees a token minted for that user, and gateway analytics record the same subject.
Glossary
- Identity assertion — Proof the IdP authenticated the user, carried as an
OIDC ID token (
urn:ietf:params:oauth:token-type:id_token) or SAML 2.0 assertion. It's the input to the XAA flow. - ID-JAG (Identity Assertion JWT Authorization Grant) — A short-lived signed
JWT the IdP mints, audience-restricted to one resource authorization server.
Used once to obtain an access token there. JWT header
typ: oauth-id-jag+jwt; token typeurn:ietf:params:oauth:token-type:id-jag. It is not an access token. - Identity provider (IdP) — The SSO authority both apps trust (Okta, Entra,
Auth0). In XAA it also brokers cross-app access by issuing ID-JAGs after
evaluating policy. Identified by
issin the ID-JAG. - Resource authorization server — The target app's OAuth server. It
consumes the ID-JAG via the JWT-bearer grant and issues the real access token.
Identified by
audin the ID-JAG. In Zuplo's outbound flow, this is the upstream's server, not the gateway. - Requesting app — The party that obtains and redeems the ID-JAG. When the gateway fronts an XAA-protected upstream, the gateway is the requesting app.
- Token exchange (RFC 8693) — The grant used at the IdP to swap the identity assertion for the ID-JAG.
- JWT bearer grant (RFC 7523) — The grant used at the resource authorization server to redeem the ID-JAG for an access token.
When to use XAA
Reach for XAA when:
- An upstream MCP server is protected by an enterprise resource authorization server that accepts ID-JAGs (the "enterprise-managed authorization" pattern), and you want the gateway to broker access through your IdP rather than running a separate OAuth client per upstream.
- You need central governance — one place in the IdP to grant, audit, and revoke which apps can reach which APIs on a user's behalf.
For an upstream that uses plain per-user or shared OAuth (Linear, Notion, Stripe, and most SaaS MCP servers today), use upstream OAuth instead — XAA isn't required.
Try it and configure it
- Quickstart — see XAA work end to end in minutes using Okta's hosted xaa.dev playground, with no identity tenant required.
- Configuration reference — every
idJagoption on the token-exchange policy.
Learn more
- Identity Assertion JWT Authorization Grant (IETF draft) — the ID-JAG specification. Note this is an active draft, not yet a finalized RFC.
- MCP authorization spec and the Enterprise-Managed Authorization extension — where ID-JAG plugs into MCP.
- Okta — Cross App Access — Okta's explainer and walkthrough.
- How the MCP Gateway works — the gateway's two OAuth surfaces and request lifecycle.