What is Cross App Access (XAA) for MCP?

The MCP spec describes this flow as Enterprise-Managed Authorization, an optional extension for clients and servers that both use enterprise single sign-on. It does not use the term Cross App Access (XAA). The identity provider decides whether an MCP client may act for a user on a server, and the client then gets an access token without per-server authorization.
Checked against the MCP Enterprise-Managed Authorization extension, revision 2026-07-28, as of 2026-11-06. The spec builds on the IETF Identity Assertion JWT Authorization Grant draft, draft-ietf-oauth-identity-assertion-authz-grant-04. This post covers only what the MCP spec states about that draft.
Why per-server authorization does not scale
Without an enterprise profile, each user connects an MCP client to each MCP server and authorizes it there. The enterprise-managed profile removes that step where both sides support it. The spec gives three benefits: end users stop connecting each server by hand, admins gain visibility and control over which servers are used, and clients get access tokens without repeated user interaction.
The profile is an optional extension. It sits in the MCP authorization extensions repository at the Stable stage. The extension README describes it as optional: implementations choose to adopt it. For a platform team, the practical result is that access is decided by IdP policy at each token issuance, in one place, instead of in each developer’s client settings.
How the sign-in to token flow works
The spec describes the flow in six steps. Each step’s output feeds the next one.
- The user signs in to the MCP client through the enterprise IdP, using OpenID Connect or SAML. The IdP may require MFA before it grants access.
- The client sends a token exchange request to the IdP, with the ID token (or a refresh token it got from SAML) and the MCP server it wants to reach. The IdP returns an ID-JAG.
- The IdP evaluates the administrator’s policy for this client, user, server and scopes. If access is granted, the ID-JAG is issued. If not, the IdP returns an OAuth token error.
- The client presents the ID-JAG to the server’s authorization server with the JWT bearer grant.
- The authorization server validates the ID-JAG and issues an access token that is audience-restricted to that MCP server.
- The client calls the MCP server with the access token.
The token exchange request and the ID-JAG
The client makes the exchange at the IdP’s token endpoint. Section 4 requires client authentication on this request when the IdP requires it for the client’s OpenID Connect sign-in. The spec’s example authenticates with a client secret. The example below removes that secret, so it applies only to a client whose IdP accepts an unauthenticated exchange. It was not run against an IdP.
POST /oauth2/token HTTP/1.1
Host: acme.idp.example
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&requested_token_type=urn:ietf:params:oauth:token-type:id-jag
&audience=https://auth.chat.example/
&resource=https://mcp.chat.example/
&scope=chat.read+chat.history
&subject_token=eyJraWQiOiJzMTZ0cVNtODhwREo4VGZCXzdrSEtQ...
&subject_token_type=urn:ietf:params:oauth:token-type:id_token
&client_id=2ec954a1d60620116d36d9ceb7
The audience and resource parameters carry the rules that matter most. The spec sets them as follows.
| Field | Where it appears | Rule in this profile |
|---|---|---|
audience |
Token exchange request | MUST be the issuer identifier of the resource authorization server |
resource |
Token exchange request | OPTIONAL. If set, MUST be the MCP server’s Resource Identifier from RFC 9728 |
resource |
ID-JAG claims | MUST contain the MCP server’s Resource Identifier, if the claim is present |
aud and access token audience |
Access token | The access token MUST be audience-restricted to the server named in the ID-JAG’s resource claim |
The spec’s example ID-JAG has the header "typ": "oauth-id-jag+jwt" and carries iss (the IdP), sub, aud, resource, client_id, exp, iat and scope. The example response sets expires_in to 300 seconds. That is the example’s value, not a rule, so check your IdP’s configured lifetime.
Before you rely on it
Work through these before you point a production agent at a server that uses this flow.
- Check the server’s authorization server metadata for
urn:ietf:params:oauth:grant-profile:id-jaginauthorization_grant_profiles_supported. - Register the MCP client with the enterprise IdP for single sign-on. Expect the IdP to reject unregistered clients.
- Write the policy rule in the IdP for this client and server, with the scopes you want to allow.
- Test with a user the policy should reject. The exchange should return an OAuth token error, and the client should not fall back to a different grant.
- Confirm the access token the server accepts is limited to that server’s audience.
What the IdP can and cannot see
The IdP sees token issuance, not the tool traffic. That split decides what policy can do and what audit has to cover.
| Question | Enterprise IdP | MCP traffic |
|---|---|---|
| Which users may use which client with which server | Yes, through IdP policy | No |
| Which scopes a user may request | Yes, if the server defines granular scopes | No |
| Which tools an agent called, with what arguments | No, per spec section 7.2 | Yes, but only the server and client see it |
The spec’s own example is useful: a policy might let engineering users read from a source control server through an AI code editor, while marketing users get read and write access to an internal documentation app. The IdP enforces that at issuance. It does not stop a permitted agent from misusing a tool it was allowed to call.
Enforcing this with AIControls
AIControls supports IdP integration for XAA. The AIControls platform page covers current scope. For the identity model behind the flow, read how to map AI agents and humans to one identity model with OIDC, and for the earlier Okta-specific post, Okta Cross App Access (XAA / ID-JAG) in AIControls. For the wider MCP picture, see the MCP security guide.
Frequently asked questions
Do users still have to authorize each MCP server one by one?
Not when the enterprise-managed profile is in use. The MCP extension says it removes the need for end users to connect and authorize the MCP client to each MCP server by hand, and it removes the need for user interaction when the client obtains new access tokens. The profile applies when the MCP client and server are both enabled for single sign-on through an enterprise identity provider, and the client checks the server's metadata for the ID-JAG grant profile.
Can the identity provider see the MCP tool calls my agents make?
No. The MCP spec limits the identity provider's visibility to the act of issuing the access token. It does not extend to the MCP traffic between the client and the server. The IdP can decide who may use which client with which server, and which scopes a user may request if the server defines granular scopes.
Does the MCP client need to be registered with my identity provider?
In most enterprise deployments, yes. The MCP spec says the IdP policy will usually allow users to sign in only to pre-registered clients, so the client is likely to need registration for single sign-on. If the client is not pre-registered with the resource authorization server, it can use its Client ID Metadata Document as its client ID, and optionally authenticate with private_key_jwt.
How does a client know that an MCP server supports this flow?
It checks the server's authorization server metadata. If the authorization_grant_profiles_supported field includes urn:ietf:params:oauth:grant-profile:id-jag, the client can use this profile. The spec defines that discovery method in section 6. The client must also be enabled for single sign-on through an enterprise identity provider, as section 1.1 describes.