MCPcopy Index your code
hub / github.com/codeaashu/claude-code / performMCPXaaAuth

Function performMCPXaaAuth

src/services/mcp/auth.ts:664–845  ·  view source on GitHub ↗

* XAA (Cross-App Access) auth. * * One IdP browser login is reused across all XAA-configured MCP servers: * 1. Acquire an id_token from the IdP (cached in keychain by issuer; if * missing/expired, runs a standard OIDC authorization_code+PKCE flow * — this is the one browser pop) * 2. Run

(
  serverName: string,
  serverConfig: McpSSEServerConfig | McpHTTPServerConfig,
  onAuthorizationUrl: (url: string) => void,
  abortSignal?: AbortSignal,
  skipBrowserOpen?: boolean,
)

Source from the content-addressed store, hash-verified

662 * All errors are actionable — they tell the user what to run.
663 */
664async function performMCPXaaAuth(
665 serverName: string,
666 serverConfig: McpSSEServerConfig | McpHTTPServerConfig,
667 onAuthorizationUrl: (url: string) => void,
668 abortSignal?: AbortSignal,
669 skipBrowserOpen?: boolean,
670): Promise<void> {
671 if (!serverConfig.oauth?.xaa) {
672 throw new Error('XAA: oauth.xaa must be set') // guarded by caller
673 }
674
675 // IdP config comes from user-level settings, not per-server.
676 const idp = getXaaIdpSettings()
677 if (!idp) {
678 throw new Error(
679 "XAA: no IdP connection configured. Run 'claude mcp xaa setup --issuer <url> --client-id <id> --client-secret' to configure.",
680 )
681 }
682
683 const clientId = serverConfig.oauth?.clientId
684 if (!clientId) {
685 throw new Error(
686 `XAA: server '${serverName}' needs an AS client_id. Re-add with --client-id.`,
687 )
688 }
689
690 const clientConfig = getMcpClientConfig(serverName, serverConfig)
691 const clientSecret = clientConfig?.clientSecret
692 if (!clientSecret) {
693 // Diagnostic context for serverKey mismatch debugging. Only computed
694 // on the error path so there's no perf cost on success.
695 const wantedKey = getServerKey(serverName, serverConfig)
696 const haveKeys = Object.keys(
697 getSecureStorage().read()?.mcpOAuthClientConfig ?? {},
698 )
699 const headersForLogging = Object.fromEntries(
700 Object.entries(serverConfig.headers ?? {}).map(([k, v]) =>
701 k.toLowerCase() === 'authorization' ? [k, '[REDACTED]'] : [k, v],
702 ),
703 )
704 logMCPDebug(
705 serverName,
706 `XAA: secret lookup miss. wanted=${wantedKey} have=[${haveKeys.join(', ')}] configHeaders=${jsonStringify(headersForLogging)}`,
707 )
708 throw new Error(
709 `XAA: AS client secret not found for '${serverName}'. Re-add with --client-secret.`,
710 )
711 }
712
713 logMCPDebug(serverName, 'XAA: starting cross-app access flow')
714
715 // IdP client secret lives in a separate keychain slot (keyed by IdP issuer),
716 // NOT the AS secret — different trust domain. Optional: if absent, PKCE-only.
717 const idpClientSecret = getIdpClientSecret(idp.issuer)
718
719 // Acquire id_token (cached or via one OIDC browser pop at the IdP).
720 // Peek the cache first so we can report idTokenCacheHit in analytics before
721 // acquireIdpIdToken potentially writes a fresh one.

Callers 1

performMCPOAuthFlowFunction · 0.85

Calls 15

getXaaIdpSettingsFunction · 0.85
getMcpClientConfigFunction · 0.85
getServerKeyFunction · 0.85
getSecureStorageFunction · 0.85
logMCPDebugFunction · 0.85
jsonStringifyFunction · 0.85
getIdpClientSecretFunction · 0.85
getCachedIdpIdTokenFunction · 0.85
acquireIdpIdTokenFunction · 0.85
discoverOidcFunction · 0.85
performCrossAppAccessFunction · 0.85
clearIdpIdTokenFunction · 0.85

Tested by

no test coverage detected