---
title: "Enterprise-Managed Authorization for your MCP server: Setting Up and Testing XAA in Auth0"
description: "Configure Auth0 as your XAA Resource App and trace every token exchange step by step."
authors:
  - name: "Miguel Pedregosa"
    url: "https://auth0.com/blog/authors/miguel-pedregosa/"
date: "Aug 20, 2026"
category: "Developers"
tags: ["xaa", "cross-app-access"]
url: "https://auth0.com/blog/setting-up-testing-cross-app-access-auth0/"
---

# Enterprise-Managed Authorization for your MCP server: Setting Up and Testing XAA in Auth0

<style>
    
  /* Increases spacing between bullet points */   
    li {padding-bottom: .7em; }
/* Style a table. Add borders, center table, and reduce font size. */
  table {
    width: 90%;
    margin: 2.4rem auto !important;
    border-collapse: collapse;
    font-size: .9em;
  }
  table, td, th {
    border: 1px solid;
  }
  table th {
    line-height: normal;
    padding: .8em;
  }
  td {
    padding: .8em;
    line-height: normal;
  }

</style>
You want to connect Claude, Cursor or other AI agents to the MCP servers, APIs and tools of your application. But your customers do not want individual users to take the decision on which AI agents can connect to which tools — they want that to be centrally managed, by their IT admin team. Traditional OAuth cannot give you that: it will require every user to click through a consent screen for each connected app, leaving your customers with [no central place to audit or revoke access](https://auth0.com/blog/why-ai-agents-need-their-own-permission-model).

This is the gap that **MCP's Enterprise-Managed Auth** extension closes, thanks to its underlying protocol, **Cross App Access (XAA)**. XAA moves the authorization decision to the enterprise identity provider, it makes the flow seamless for end-users and frees them from taking consent decisions that do not belong to them. In this post, we will explore the details of the XAA flow to understand how it works, how to set it up in Auth0, and what you can get out of it.

<div class="alert alert-info alert-icon">
  <i class="icon-budicon-487 icon-info"></i>
  <b>Note: The Cross App Access protocol can be used to grant access to MCP Servers as well as any other type of API. We will use the term “API” throughout this document as interchangeable for MCP Server. If you want to know more about how to configure Auth0 as Authorization Server for your MCP Server, see the [Authorization for Your MCP Server](https://auth0.com/ai/docs/mcp/get-started/authorization-for-your-mcp-server) documentation.</b><br> 
</div>

## XAA’s Three Roles

<picture>
<img src="https://images.ctfassets.net/23aumh6u8s0i/5nVXFxjguc7LsKJPJptgvC/25ad32f26d3592ab2e09fc9ae8a20179/XAARequestingAppResourceAppFlow.png" alt="XAA Requesting App and Resource App Flow" style="width:100%; margin: 1em auto; border: solid black 0px; border-radius: 0px;">
</picture>

XAA involves three parties:

| Role | Who it is in our example | What it does |
| :---- | :---- | :---- |
| **Requesting App** | Claude, or another AI agent | Wants to call your API on the user's behalf |
| **Enterprise IdP** | Okta, or any Identity Provider (IdP) that supports XAA | Authenticates the user *and* authorizes the app-to-app or agent-to-app access. This is the policy enforcement point. |
| **Resource App** | Your API, with **Auth0** as its Authorization Server | Trusts the IdP and issues an access token for the API |

In this post, we will only explore Auth0 as **Resource App Authorization Server**. Here Auth0 acts as an authorization server that *trusts an assertion minted by an external IdP* and, in return, issues access token for the Requesting App to access your API.

## The XAA flow, in a nutshell

Let’s have a look at the actual machinery powering XAA: a series of token exchanges that allow the seamless yet secure connection of Agents to MCP servers and APIs. Further down in this post, you can find a guide on how to run the flow yourself, along with detailed examples of each protocol request and response.

### XAA Flow with an OIDC IdP

<picture>
<img src="https://images.ctfassets.net/23aumh6u8s0i/69KtsJ3ZU0bGwvlzG9NmdJ/d938bd0b556567e73384e0136c265fdd/CrossAppAccessXAAFlowOIDCIdP.png" alt="XAA Flow with an OIDC IdP" style="width:100%; margin: 1em auto; border: solid black 0px; border-radius: 0px;">
</picture>

### XAA Flow with a SAML IdP

<picture>
<img src="https://images.ctfassets.net/23aumh6u8s0i/5hmzVmshMXqBlWQlMRqHNq/81377cb02cc07efb1ff5602411dcf346/CrossAppAccessXAAFlowSAMLIdP.png" alt="XAA Flow with a SAML IdP" style="width:100%; margin: 1em auto; border: solid black 0px; border-radius: 0px;">
</picture>

**1. Authentication (user sign-in).** The user authenticates against the enterprise IdP using either OIDC or SAML, obtaining either an ID Token or a SAML Assertion.

**1.1. SAML Interoperability Layer (SAML only).** When using SAML, we need to move from the SAML protocol to OAuth, where XAA is implemented. For this, XAA provides an interoperability layer in which the Requesting App exchanges a SAML Assertion for an OAuth Refresh Token. Once the Requesting App has a Refresh Token, the flow can continue.

**2. Request an ID-JAG.** An authentication artifact is exchanged against the Enterprise IdP to get an ID-JAG. Either an ID Token or a Refresh Token may be used for this. The token is exchanged for an **Identity Assertion JWT Authorization Grant (ID-JAG)** scoped to your Resource App. During this exchange, enterprise policies are enforced: Okta will mint the assertion only if the admin's XAA policy allows *the* Requesting App to access *the* Resource App for *this* user.

**3. Request an Access Token.** The Requesting App presents the ID-JAG to the Auth0 Authorization Server. Auth0 validates the assertion's signature against the IdP's keys, checks that it was issued for this tenant, applies your resource-level rules, and issues a normal Auth0 Access Token.

**4. Call the API.** The Requesting App calls your API with the issued Access Token, and your API validates it exactly as it validates any other Auth0 token. Your API code does not change — it does not even know XAA was involved.

<div class="alert alert-info alert-icon">
  <i class="icon-budicon-487 icon-info"></i>
  <b>Under the hood this chaining of assertions is standardized by the [Identity Assertion Authorization Grant (ID-JAG)](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/) draft specification.</b><br> 
</div>

## Cross App Access in Action

It is now turn to run it and get into the details! To understand, send and see each protocol request and response, step by step, we will use the [Auth0 XAA Inspector](https://github.com/auth0-samples/auth0-cross-app-access-inspector) as the Requesting App. This is a small open-source Node/React app that can execute the XAA flow and print the raw HTTP request and the resulting token at every step.

<picture>
<img src="https://images.ctfassets.net/23aumh6u8s0i/1wyXWOGimpcnr7XuT4r1U0/5d56446006d2091a074410529e463e03/Auth0CrossAppAccessInspector.png" alt="Auth0 XAA Inspector" style="width:100%; margin: 1em auto; border: solid black 0px; border-radius: 0px;">
</picture>

We will use **Okta** as enterprise IdP, and **Auth0** as Resource App Authorization server, but the Inspector App will work with any other spec-compliant providers. That is the magic of an open protocol!

Here are the necessary setup steps.
<div class="alert alert-info alert-icon">
  <i class="icon-budicon-487 icon-info"></i>
  <b>Note: XAA is an OAuth/OIDC flow, but supports a [SAML compatibility layer](https://www.ietf.org/archive/id/draft-ietf-oauth-identity-assertion-authz-grant-04.html#name-saml-20-subject-token-inter) for SAML IdPs. In this section, we cover the XAA flow for a SAML IdP, as SAML is prevalent among enterprise software. Auth0 supports XAA for Okta, OIDC and SAML enterprise connections. The OIDC flow works in a very similar way; find more information in [Cross App Access](https://auth0.com/docs/ai-agents-mcp/cross-app-access) documentation.</b><br> 
</div>

### What to configure in your Okta Org

In order to configure your Okta Org, you can follow [the Okta as SAML IdP documentation](https://auth0.com/docs/ai-agents-mcp/cross-app-access/idp/okta-as-saml-idp) or [Okta’s guide](https://developer.okta.com/blog/2026/07/17/xaa-saml-requester).

You will need:

- A **SAML application** to model the Resource Application, with **XAA enabled**.  
- A **SAML application** to model the Requesting Application.  
- An **AI Agent** to model the agent executing XAA for the Requesting Application. Configured for the Requesting and Resource App combination.

### What to configure in Auth0

Becoming the Resource App is **no-code** — **a single toggle** configuration on your Enterprise Connection and desired client.

You will need:

- An **API** representing the resource (your audience and scopes)  
- A **Requesting Application** client representing the app allowed to present ID-JAGs, with **Cross App Access enabled**  
- A SAML **Enterprise Connection** pointing to the IdP’s SAML Resource Application, with **Cross App Access enabled** so that Auth0 trusts the IdP's assertions.

See the [Auth0 XAA documentation](https://auth0.com/docs/ai-agents-mcp/cross-app-access/set-up-xaa-test-environment) for the detailed click-by-click configuration path. In particular, you will need the [Okta as SAML IdP](https://auth0.com/docs/ai-agents-mcp/cross-app-access/idp/okta-as-saml-idp) guide.

### What to configure in XAA Inspector

Configuring your Inspector App is done by configuring the `.env` file. Make a copy of `.env.example` and fill in the necessary parameters. You can follow the [README](https://github.com/auth0-samples/auth0-cross-app-access-inspector/blob/main/README.md) to better understand this process, but here is a quick overview:

| Environment Variable | Value |
| :---- | :---- |
| OKTA\_ISSUER | This is the issuer for your Okta Org authorization server. If you are using an Integrator Org, it will be something like: `https://integrator-12345.okta.com` |
| OKTA\_TOKEN\_CLIENT_ID | The Client ID for the Okta AI Agent used to model the Requesting App |
| OKTA\_PRIVATE\_KEY | The Private Key used by the Requesting App to authenticate via Private Key JWT against Okta, in PEM format. Should be a single-line string with escaped newline characters. Something like: `-----BEGIN PRIVATE KEY-----\n…\n…\n-----END PRIVATE KEY-----` |
| OKTA\_PRIVATE\_KEY\_KID | Key ID for the above private key |
| SAML\_SP\_ENTITY\_ID, SAML\_SP\_ACS\_URL, SAML\_IDP\_SSO\_URL, SAML\_IDP\_ISSUER, SAML\_IDP\_CERT | These are your standard SAML configuration parameters on the SP side. Sample values can be found in the Inspector’s README. |
| SAML\_IDJAG\_SCOPE | Space-separated list of scopes to be requested |
| AUTH0\_DOMAIN | Your Auth0 tenant domain. Just the domain, no protocol or path. Unless you are using Custom Domains, it looks like `my-tenant.eu.auth0.com` |
| AUTH0\_CLIENT\_ID | The Client ID for the Requesting App in Auth0. In our examples, it is a sample CIMD URL we provide for demo purposes:  `https://raw.githubusercontent.com/auth0-samples/auth0-cross-app-access-inspector/main/public/cimd.json` |
| AUTH0\_AUDIENCE | The Auth0 authorization server issuer identifier. Should look like `https://my-tenant.eu.auth0.com/` Note that Auth0 requires the trailing slash. |
| AUTH0\_RESOURCE | The API identifier in Auth0 |

<div class="alert alert-info alert-icon">
  <i class="icon-budicon-487 icon-info"></i>
  <b>For this demonstration, we will use CIMD to register the XAA Inspector client in Auth0. This will allow us to streamline the configuration of the Requesting App Auth0 client. If you want to know more about CIMD, read [the Register Applications with CIMD documentation](https://auth0.com/docs/get-started/auth0-overview/create-applications/register-applications-with-cimd) or the post [Client ID Metadata Documents Are the Future of MCP Client Registration](https://auth0.com/blog/cimd-vs-dcr-mcp-registration/).</b><br> 
</div>

## Running the XAA flow

We are now ready to run the XAA flow and watch the token exchanges in detail. Let’s navigate to the XAA Inspector and pick the **SAML** toggle. For each step, a panel will show the outgoing request and the returned token.

**Step 1: Sign in.** Authenticate against Okta; the Inspector extracts the signed `<Assertion>` from the SAML Response.  

<picture>
<img src="https://images.ctfassets.net/23aumh6u8s0i/2RBriWc8NIOGd6sTz1LQ8E/c7ac57bd8e942a3742536518e015b3c8/Auth0CrossAppAccessInspectorSAMLSignIn.png" alt="XAA Inspector extracts signed assertion from SAML Response" style="width:100%; margin: 1em auto; border: solid black 0px; border-radius: 0px;">
</picture>

**Step 2: SAML Compatibility Layer.** The Inspector exchanges the SAML assertion for a refresh token at Okta. Note this request uses `grant_type=urn:ietf:params:oauth:grant-type:token-exchange` ([RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693)) with `subject_token_type=urn:ietf:params:oauth:token-type:saml2` (the presented token type, a SAML assertion) and `requested_token_type=urn:ietf:params:oauth:token-type:refresh_token` (the requested token type, an OAuth Refresh Token). The SAML assertion itself is sent in the `subject_token` parameter, in Base-64 encoding.

<picture>
<img src="https://images.ctfassets.net/23aumh6u8s0i/2bDwJxZkzQgndMFQO673RH/b01e073eb1a4187720f18de91304b5d4/ExchangeSAMLAssertionforRefreshToken.png" alt="Exchange SAML Assertion for a Refresh Token" style="width:100%; margin: 1em auto; border: solid black 0px; border-radius: 0px;">
</picture>

**Step 3: Get the ID-JAG.** The Inspector exchanges the refresh token at Okta to request an ID-JAG scoped to your Auth0 tenant. At this point, Okta enforces the enterprise policy gates — Okta will only issue the assertion if the XAA policy is configured in Okta to allow the Inspector access to your Resource App for this user. The Requesting App requests a set of scopes it wants to use in the Resource App, these scopes may or may not be granted by the IdP depending on its internal policies. It also requests an specific `audience`, which points to the Authorization Server gating the protected resources. Depending on the IdP implementation, the target API may also be requested through the `resource` parameter. Note how the Token Exchange Grant is used again on this request. Expand it and check the claims:

<picture>
<img src="https://images.ctfassets.net/23aumh6u8s0i/4IIDXOEJlLP8d2TvZcnx67/c1bd984590eddf183911a9361ab454fa/ExchangeRefreshTokenForIDJAGAssertion.png" alt="Exchange Refresh Token For a ID-JAG Assertion" style="width:100%; margin: 1em auto; border: solid black 0px; border-radius: 0px;">
</picture>
<picture>
<img src="https://images.ctfassets.net/23aumh6u8s0i/2WPXufbef15BbSa73PFeTu/fb6e781a7933ebdeb6298cbd272dbbf6/ExchangeRefreshTokenForIDJAGAssertion-2.png" alt="Exchange Refresh Token For a ID-JAG Assertion" style="width:100%; margin: 1em auto; border: solid black 0px; border-radius: 0px;">
</picture> 

Here we can see the key piece of this puzzle: the ID-JAG. The ID-JAG is an assertion that authorizes cross-domain access to resources. It is the mechanism that allows cross-domain trust, because it is trusted by all the different parties involved. Some of the more relevant claims are:

- `iss`: identifies the token issuer, the Okta Authorization Server in our case.  
- `aud`: identifies the token audience, which is the Auth0 tenant.   
- `sub`: uniquely identifies the user. This claim is always present.  
- `sub_id`: identifies the user in the SAML namespace, with all the usual `NameID` properties required to identify users in the SAML protocol.  
- `client_id`: the identifier of the Requesting App, in our case a CIMD identifier.   
- `scope`: indicates the granular authorization details granted to the Requesting App. Note granted scopes may have been scoped down by the IdP’s policies.

**Step 4: Exchange for an Auth0 access token.** The Inspector presents the ID-JAG to your Auth0 tenant via the JWT-bearer grant. Auth0 validates the signature and audience, applies your rules, and returns a standard Auth0 access token. 

Note a `resource` parameter is specified in this request. The `resource` parameter identifies the target API the Requesting App wants to access. Depending on the implementation of the IdP, the resource may be requested in the ID-JAG request and included as an ID-JAG claim. A default resource is also configurable in Auth0 by configuring the Default Audience tenant setting.

<picture>
<img src="https://images.ctfassets.net/23aumh6u8s0i/1QnSqLxYLqv6cXUL6ZPQLO/7846e154823cfe3b54ff42486d2b3f19/ObtainResourceAppAccessToken.png" alt="Obtain Resource App Access Token" style="width:100%; margin: 1em auto; border: solid black 0px; border-radius: 0px;">
</picture>
<picture>
<img src="https://images.ctfassets.net/23aumh6u8s0i/7ISTGmqizKKDlKDRAlHU4E/6518eae44ede3e9333eed069568c7106/ObtainResourceAppAccessToken-2.png" alt="Obtain Resource App Access Token" style="width:100%; margin: 1em auto; border: solid black 0px; border-radius: 0px;">
</picture>
 
We can see here how the Access Token issued by Auth0 has the usual content one would expect from an Access Token. In our scenario:

- `iss`: identifies the Auth0 tenant that issued the token  
- `aud`: identifies the Resource App this AT is intended for  
- `client_id`: identifies the Requesting App, note it is a CIMD identifier

<div class="alert alert-info alert-icon">
  <i class="icon-budicon-487 icon-info"></i>
  <b>Auth0 Organizations are also supported in this flow. If you want Auth0 to issue Organization-scoped Access Tokens, see [the Add Organization Support documentation](https://auth0.com/docs/ai-agents-mcp/cross-app-access/idp/add-organization-support).</b><br> 
</div>

**Step 5: Call the API.** Use the Access Token to call the Resource App API. Your API validates it like any other Auth0 token. The flow is now complete: a user signed in once at Okta, and an agent reached your API on their behalf, with [zero consent prompts and full central control](https://auth0.com/blog/closing-audit-gap-human-to-agent-delegation).

## Scaling Distribution via the Okta Integration Network (OIN)

While your Resource App can evaluate identity assertions from any spec-compliant IdP, listing your implementation in the Okta Integration Network (OIN) simplifies deployment for enterprise admins who already rely on Okta's identity architecture.

Publishing an XAA integration to the OIN offers two key structural advantages:

* **Out-of-the-Box Interoperability:** Your APIs and MCP servers become immediately reachable by popular Requesting Applications (such as Anthropic’s Claude, Cursor, VS Code, Docker, and Zoom) without requiring custom connection logic for each agent.  
* **Streamlined Enterprise Discovery:** Enterprise IT administrators can discover, audit, and provision your application's XAA capabilities directly from their existing Okta Admin Console.

### Publishing your integration to the OIN

Once you have verified the XAA flow in your Auth0 tenant, moving to a live OIN catalog listing involves the following steps:

1. Review the metadata requirements in the [OIN Submission Guide for XAA](https://developer.okta.com/blog/2026/07/06/submit-oin-xaa?_gl=1*1g77kya*_gcl_aw*R0NMLjE3ODM0NTc1NTAuQ2p3S0NBand4N0xTQmhCM0Vpd0FqY29keEtCV1hEUUx6RHN2OE1ibTIydFRrX08wWXFFWkY2bzUwMVpEd0RzOHMwSjN6WWJDNXJraWVCb0MtTThRQXZEX0J3RQ..*_gcl_au*Nzc2MTQ3Njc5LjE3ODQ0Nzk5NjA.*_ga*Mzc1NDE0ODkyLjE3MjcxMDc5NTc.*_ga_QKMSDV5369*czE3ODcwODEyMjIkbzcxMiRnMCR0MTc4NzA4MTIyMyRqNTkkbDAkaDA.#getting-listed-in-the-okta-integration-network-oin).  
2. Configure and test your client definitions inside an Okta preview tenant.  
3. Submit the integration package for verification via the Okta Developer Portal.

After approval, your application will appear as a pre-built XAA-enabled integration in the public OIN catalog.

## Want to Learn More?

If you want to dig into XAA in more detail, you can learn more by checking out the [Auth0 XAA documentation.](https://auth0.com/docs/ai-agents-mcp/cross-app-access)