Skip to content

Alternative: XAA as OAuthClientProvider with Layer 2 utilities#1531

Draft
pcarleton wants to merge 13 commits intomainfrom
paulc/xaa-as-provider
Draft

Alternative: XAA as OAuthClientProvider with Layer 2 utilities#1531
pcarleton wants to merge 13 commits intomainfrom
paulc/xaa-as-provider

Conversation

@pcarleton
Copy link
Member

@pcarleton pcarleton commented Feb 13, 2026

Alternative implementation for PR #1328

This is an alternative approach to #1328 (SEP-990 Enterprise Managed OAuth). Instead of a standalone middleware, this implements Cross-App Access as an OAuthClientProvider with composable Layer 2 utilities.

Design

Layer 2: crossAppAccess.ts (~130 lines)

  • requestJwtAuthorizationGrant() — standalone RFC 8693 token exchange utility
  • discoverAndRequestJwtAuthGrant() — convenience wrapper with IDP discovery

Layer 3: CrossAppAccessProvider in authExtensions.ts

Usage

const provider = new CrossAppAccessProvider({
    assertion: async (ctx) => requestJwtAuthorizationGrant({
        tokenEndpoint: 'https://idp.example.com/token',
        audience: ctx.authorizationServerUrl,
        resource: ctx.resourceUrl,
        idToken: await getIdToken(),
        clientId: 'my-idp-client',
        clientSecret: 'my-idp-secret',
        scope: ctx.scope,
        fetchFn: ctx.fetchFn
    }),
    clientId: 'my-mcp-client',
    clientSecret: 'my-mcp-secret'
});

const transport = new StreamableHTTPClientTransport(serverUrl, {
    authProvider: provider
});

Key decisions

  • Assertion callback decouples IDP interaction from the provider — callers can use the Layer 2 utility for standard flows or bring their own JAG source
  • saveResourceUrl added to OAuthClientProvider (same pattern as saveAuthorizationServerUrl in feat: expose discoverOAuthServerInfo() and add provider caching for auth server URL #1527) so providers can access orchestrator-discovered state
  • No qs dependency — uses URLSearchParams like the rest of the codebase

Depends on

Conformance

Passes auth/cross-app-access-complete-flow scenario (9/9 checks).

sagar-okta and others added 7 commits January 21, 2026 11:54
Replaces the standalone middleware approach from PR #1328 with:

- CrossAppAccessProvider in authExtensions.ts: plugs into withOAuth for
  token caching, 401 retry, client_secret_basic, and Zod validation
- assertion callback: receives orchestrator context (AS URL, resource URL,
  scope, fetchFn), returns JAG string. Decouples IDP interaction from provider
- requestJwtAuthorizationGrant in crossAppAccess.ts: standalone Layer 2
  utility for RFC 8693 token exchange (ID token → JAG)
- saveResourceUrl on OAuthClientProvider: orchestrator saves resource URL
  so providers can use it in prepareTokenRequest

Removes: withCrossAppAccess middleware, xaaUtil.ts (597 lines), qs dependency
Adds: conformance test scenario (auth/cross-app-access-complete-flow) - passes 9/9
@changeset-bot
Copy link

changeset-bot bot commented Feb 13, 2026

⚠️ No Changeset found

Latest commit: 2f95627

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

- Delete xaa-util.test.ts (tests for removed xaaUtil.ts)
- Revert docs/client.md withCrossAppAccess documentation
- Remove qs and @types/qs dependencies from package.json
- Remove qs from pnpm-workspace.yaml catalog
- Revert middleware.test.ts withCrossAppAccess test additions
Replace hand-rolled typeof checks and generic Error throws with:
- JagTokenExchangeResponseSchema (Zod) for response validation
- parseErrorResponse() for error responses (typed OAuthError)

Consistent with how auth.ts validates all other OAuth responses.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants