OktaAkanksha BhasinTutorial
Build a Secure TypeScript MCP Client with Cross App Access (XAA)
Summary
The post presents a tutorial for building a TypeScript Model Context Protocol (MCP) client that uses Cross App Access (XAA) to securely bridge enterprise apps across trust domains. The sample app is an employee onboarding dashboard that signs in through an identity provider, exchanges identity for an Identity Assertion JWT Authorization Grant (ID-JAG), trades it for an access token, and fetches data from a protected MCP server. The tutorial uses the MCP TypeScript SDK’s CrossAppAccessProvider to automate the four-step XAA flow, including token exchange and retry on 401 responses. Developers test against xaa.dev, a free playground that hosts the IdP, authorization server, and a todo MCP server. The post explains key concepts like ID-JAG claims, separate client credentials per trust domain, and how XAA enables AI agents and enterprise apps to act on behalf of users without OAuth consent screens.
Context
Enterprise apps often need to share data across trust domains, requiring OAuth consent screens or shared service accounts. Cross App Access (XAA) removes that step by using an identity provider to vouch for the user under a pre-set policy. This tutorial demonstrates building a TypeScript MCP client that implements the XAA flow using the MCP TypeScript SDK and the xaa.dev playground.
Approach / What changed
Build a TypeScript MCP requesting app that uses the MCP TypeScript SDK’s CrossAppAccessProvider to automate the XAA flow. The app registers on xaa.dev, signs users in via OpenID Connect with PKCE, exchanges the ID token for an ID-JAG, trades the ID-JAG for an access token, and fetches data from a protected MCP server. The provider handles discovery, token exchange, and retry on 401 responses.
Takeaways
Cross App Access (XAA) uses an Identity Assertion JWT Authorization Grant (ID-JAG) to carry identity across trust domains, eliminating the need for OAuth consent screens or shared service accounts.
The MCP TypeScript SDK’s CrossAppAccessProvider automates the four-step XAA flow: it sends a request without a token, receives a 401 with a WWW-Authenticate header, discovers the authorization server metadata, calls an assertion callback to get an ID-JAG, exchanges it for an access token, and retries the request.
When registering an XAA app, you receive separate client credentials for the IdP and the resource’s authorization server; using the wrong credentials results in an invalid_client error.
FAQ
What is an ID-JAG and what claims does it contain?
An ID-JAG (Identity Assertion JWT Authorization Grant) is a delegation token that carries the user's identity across trust domains. It contains claims like iss (issuer), sub (subject), aud (audience), exp (expiration), and the user's identity claims from the original ID token.
Why does XAA require separate client credentials per trust domain?
The IdP and the resource's authorization server are separate trust domains, so your app holds a separate identity at each. Using the main client's credentials at the resource's authorization server results in an invalid_client error.
How does CrossAppAccessProvider handle token expiration?
When the access token expires, the next 401 response triggers the same sequence again: discovery, assertion callback, token exchange, and retry, without any additional code from the developer.
Source and freshness
- Source
- developer.okta.com
- Published
- Added to Yomu
Summaries are generated from the original by a language model. Check the original before relying on it.
Keep reading
Related reading
The Good Stuff
Paid picks we use ourselves. Links carry a referral code — a subscription through one earns us a commission at no extra cost to you.
The best engineering reads, once a week
One useful email. Unsubscribe anytime.