NDOVU · AUDIO EXPLAINER · LISTEN
Keys: space/K play-pause · J/L jump 10s · arrows on the waveform nudge 5s
The full briefing transcript, timed to the audio. Click any line to jump there; the current line lights up while you listen.
HostPicture an AI assistant at work. This morning you signed into it with your company login, single sign-on, the usual. Now it needs your chat history from a chat app made by a different vendor. The chat app won't take the assistant's word for who you are. The identity provider that vouched for you at sign-on has seen none of this either. No approval, no policy check, nothing in its logs. That gap is what Cross-App Access closes. In one line: when one app calls another company's API for you, the call should pass through the identity provider both apps already trust, not around it.
HostThis pattern travels under four names. The OAuth working group's draft calls the token at its center an Identity Assertion JWT Authorization Grant, said as I, D, JAG. The pattern itself is Cross-App Access, written X, A, A, the name on oauth.net and most vendor explainers. In the Model Context Protocol world, the same move is Enterprise-Managed Authorization. And older material says identity chaining. Four names, one pattern. This episode sticks to Cross-App Access and ID-JAG.
HostOne scope line before the mechanics. This pattern is about acting for a user: you, delegated to an app or an agent. An agent acting on its own behalf, no user anywhere in the loop, is a different problem with different specs, and it is deliberately not in this episode.
HostThe shape is stable and worth memorizing now. Your identity provider issues a signed grant naming one downstream app. That app's authorization server trades the grant for an ordinary access token. Two hops. Everything else is detail.
HostEnterprises funnel sign-in through one identity provider. Every work app signs in there, with OpenID Connect or SAML. The draft's own example lives in that world: a wiki app wants to read your chat history at a chat app from another vendor. Both already sign in through the company IdP.
HostFour roles. The client, which is the wiki. The IdP authorization server, your employer's identity provider. The resource authorization server, the chat app's own. And the resource server, the chat API.
HostThree registrations connect them. Wiki to company IdP, for sign-on. Wiki to chat's authorization server, for API access. The quiet one that makes everything work: chat's authorization server already trusts the company IdP, because your single sign-on trust extends there.
HostGeography matters. The wiki and your IdP sit in one trust domain. Chat's two servers sit in another. The ID-JAG is the object built to cross that line, signed by your IdP, consumed by chat's server. The chat API itself never talks to your IdP at all.
HostThe wiki authenticates to the company IdP, no exceptions, and presents what it got at sign-on, your ID token, as the subject token. In the same request it names its audience: chat's authorization server, by issuer identifier, exactly one value.
HostThe IdP checks three things before it signs anything. That the subject token is one it really issued for sign-on, not some token being recycled. That it actually has the trust relationship the audience claims. Its own policy, which is the administrator's judgment about which users reach which apps. Then it returns the grant, signed.
HostOne wire quirk to know. The grant arrives in the accesstoken field, because Token Exchange requires that field name. The response marks it clearly anyway: a distinct issued token type, and a token type of N, A, nothing to bear yet. Keep the distinction, because the whole pattern depends on it. A grant is a permission slip. An access token is the thing you hand to an API.
HostThe grant is a JWT with explicit typing, a header that names exactly this kind of token. Seven claims are required. Issuer and audience, the two ends of this one trust relationship. Subject, you, in the IdP's own namespace. Client ID, the wiki's registered identity at chat's server. J, T, I, expiry, and issued-at, which make the grant trackable and perishable.
HostTwo parts earn special emphasis. The audience claim must be exactly the receiving server's issuer, one value, which closes audience injection. Subject resolution is the point of the whole document: the grant carries your email, or the chat side's own ID for you, so chat can map you to a local account. That includes provisioning one on first contact, for a user who has never signed in there before.
HostThe wiki takes the grant to chat's authorization server, to its token endpoint, as a jwt-bearer assertion. That's an older, published shape: here is a signed assertion from someone you trust, trade it for tokens.
HostChat's server runs its checks. The type header. The signature, against your IdP's published keys. The audience. The client. The expiry. Any of those fails, the answer is invalidgrant. A perfectly valid grant for a user without access gets accessdenied instead.
HostWhat comes back is an ordinary access token, and that's the payoff. The chat API sees a normal bearer token issued by its own server. No refresh token should come back with it. The grant is the reusable thing here; the client can re-submit the same grant until it expires and get fresh access tokens.
HostThe obvious alternative would be your IdP issuing chat access tokens directly. The draft refuses that shape. An identity provider must not honor its own grant by minting access tokens, unless it is explicitly configured to, and then no more generously than direct issuance would allow.
HostThe reason is control. Chat's authorization server keeps independent command of its tokens, its scopes, its local policy. If IdPs minted everyone's tokens, every API would end up coupled to a growing list of foreign issuers. Your IdP centralizes identity, sign-on trust, and the decision to broker access. It stops there.
HostBoth sides advertise support in their metadata, and the advertisement is coupled: a server cannot claim this grant profile without carrying the jwt-bearer grant type among its grant types. Claiming support without the coupling is the failure mode that rule exists to catch.
HostA few boundaries to carry with you. Replay protection, one grant used once, is optional, so two compliant servers can behave differently. The decision that matters most, which users may reach which apps, is never a protocol outcome. It is administrator policy at the IdP. Where the protocol ends and the deployment begins is the line between validating a grant and trusting a system.
HostIf you want to watch these rules fire, the site this episode lives on has a validator. Paste a real grant and it walks the checks one by one, each with its citation. The mint tab is a stub enterprise IdP whose toggles break a grant on purpose, one rule family at a time, so you can see exactly what each check catches.
HostThat's Cross-App Access. Your identity provider vouches once, signs a grant for one downstream app, and that app's server trades it for ordinary access. Four names, four roles, two hops, one rule: the grant crosses the trust boundary, the access token never does.