UNPKG

@microsoft/teams.apps

Version:

<p> <a href="https://www.npmjs.com/package/@microsoft/teams.apps" target="_blank"> <img src="https://img.shields.io/npm/v/@microsoft/teams.apps/latest" /> </a> <a href="https://www.npmjs.com/package/@microsoft/teams.apps?activeTab=code

137 lines • 12.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OauthHandlers = void 0; const teams_graph_1 = require("@microsoft/teams.graph"); const constants_1 = require("../diagnostics/constants"); const telemetry_1 = require("./telemetry"); /** * Default handlers for the SSO sign-in invoke activities * (`signin/tokenExchange`, `signin/verifyState`, `signin/failure`). * * Previously a set of `this: App`-bound free functions; now a collaborator the * {@link App} constructs and registers as system routes. The handlers are arrow * class fields so they can be passed directly as route callbacks. */ class OauthHandlers { getFlows; client; events; graphBaseUrl; usesRegisteredFlows; constructor(getFlows, client, events, graphBaseUrl, usesRegisteredFlows = () => true) { this.getFlows = getFlows; this.client = client; this.events = events; this.graphBaseUrl = graphBaseUrl; this.usesRegisteredFlows = usesRegisteredFlows; } onTokenExchange = async (ctx) => { const { activity } = ctx; const value = activity.value; if (!value?.connectionName?.trim()) { return { status: 400 }; } const registeredFlow = this.findFlow(value.connectionName); const flow = registeredFlow ?? (this.usesRegisteredFlows() ? undefined : this.getFlows()[0]); if (!flow) { return { status: 400 }; } const connectionName = registeredFlow?.connectionName ?? value.connectionName; if (!registeredFlow) { ctx.log.warn(`default connection name "${flow.connectionName}" does not match activity connection name "${connectionName}"`); } const response = await flow.exchangeToken(ctx, value, token => this.completeSignIn(flow, ctx, token, connectionName), error => this.events.emit('error', { error, activity }), connectionName); return response; }; onVerifyState = async (ctx) => { const { activity } = ctx; const flows = this.getOrderedFlows(ctx, false); for (const flow of flows) { const response = await flow.verifyState(ctx, activity.value?.state, token => this.completeSignIn(flow, ctx, token), error => this.events.emit('error', { error, activity })); if (response) { return response; } } return { status: 404 }; }; /** * Default handler for signin/failure invoke activities. * * Teams sends a signin/failure invoke when SSO token exchange fails * (e.g., due to a misconfigured Entra app registration). This handler * logs the failure details and emits an error event so developers are * notified rather than having the failure silently swallowed. * * Known failure codes (sent by the Teams client): * - `installappfailed`: Failed to install the app in the user's personal scope (non-silent). * - `authrequestfailed`: The SSO auth request failed after app installation (non-silent). * - `installedappnotfound`: The bot app is not installed for the user or group chat. * - `invokeerror`: A generic error occurred during the SSO invoke flow. * - `resourcematchfailed`: The token exchange resource URI on the OAuthCard does not * match the Application ID URI in the Entra app registration's "Expose an API" section. * - `oauthcardnotvalid`: The bot's OAuthCard could not be parsed. * - `tokenmissing`: AAD token acquisition failed. * - `userconsentrequired`: The user needs to consent (handled via OAuth card fallback, * does not typically reach the bot). * - `interactionrequired`: User interaction is required (handled via OAuth card fallback, * does not typically reach the bot). */ onSignInFailure = async (ctx) => { const { log, activity, next } = ctx; const failure = activity.value ?? {}; const { code, message } = failure; const pendingFlows = this.getOrderedFlows(ctx, true).filter(flow => flow.getPending(ctx, true) !== undefined); const flows = pendingFlows.length > 0 ? [pendingFlows[0]] : this.getFlows(); const connectionName = flows[0]?.connectionName ?? ''; return (0, telemetry_1.traceOAuthOperation)(constants_1.APP_SPAN_NAMES.oauth, connectionName, constants_1.APP_OAUTH_OPERATION.signinFailure, async (_span, telemetry) => { telemetry.failureCode = code; log.warn(`sign-in failed for user "${activity.from.id}" in conversation "${activity.conversation.id}": ${code ?? 'unknown'} — ${message ?? 'unknown'}. ` + 'If the code is \'resourcematchfailed\', verify that your Entra app registration has \'Expose an API\' configured ' + 'with the correct Application ID URI matching your OAuth connection\'s Token Exchange URL.'); for (const flow of flows) { flow.clearPending(ctx); await flow.fail(ctx, failure); } this.events.emit('error', { error: new Error(`Sign-in failure: ${code ?? 'unknown'} — ${message ?? 'unknown'}`), activity, }); await next(ctx); telemetry.result = constants_1.APP_OAUTH_RESULT.notified; telemetry.responseStatus = 200; return { status: 200 }; }); }; findFlow(connectionName) { if (!connectionName) { return undefined; } const normalized = connectionName.trim().toLowerCase(); return this.getFlows().find(flow => flow.connectionName.trim().toLowerCase() === normalized); } applyUserToken(ctx, token) { ctx.userToken = token.token; ctx.isSignedIn = true; ctx.userGraph = new teams_graph_1.Client(this.client.clone({ token: token.token, }), { baseUrlRoot: this.graphBaseUrl }); } async completeSignIn(flow, ctx, token, connectionName = flow.connectionName) { this.applyUserToken(ctx, token); await flow.complete(ctx, token); await this.events.emitAsync('signin', { ...ctx, connectionName, token, isSignedIn: true, }); await ctx.next(ctx); } getOrderedFlows(ctx, ssoOnly) { return [...this.getFlows()].sort((left, right) => (right.getPending(ctx, ssoOnly) ?? 0) - (left.getPending(ctx, ssoOnly) ?? 0)); } } exports.OauthHandlers = OauthHandlers; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFuZGxlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvb2F1dGgvaGFuZGxlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBUUEsd0RBQStEO0FBRy9ELHdEQUlrQztBQUlsQywyQ0FBa0Q7QUFJbEQ7Ozs7Ozs7R0FPRztBQUNILE1BQWEsYUFBYTtJQUVMO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFMbkIsWUFDbUIsUUFBNkMsRUFDN0MsTUFBa0IsRUFDbEIsTUFBd0MsRUFDeEMsWUFBcUIsRUFDckIsc0JBQXFDLEdBQUcsRUFBRSxDQUFDLElBQUk7UUFKL0MsYUFBUSxHQUFSLFFBQVEsQ0FBcUM7UUFDN0MsV0FBTSxHQUFOLE1BQU0sQ0FBWTtRQUNsQixXQUFNLEdBQU4sTUFBTSxDQUFrQztRQUN4QyxpQkFBWSxHQUFaLFlBQVksQ0FBUztRQUNyQix3QkFBbUIsR0FBbkIsbUJBQW1CLENBQTRCO0lBQzlELENBQUM7SUFFTCxlQUFlLEdBQUcsS0FBSyxFQUNyQixHQUFvRyxFQUNwRyxFQUFFO1FBQ0YsTUFBTSxFQUFFLFFBQVEsRUFBRSxHQUFHLEdBQUcsQ0FBQztRQUN6QixNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDO1FBRTdCLElBQUksQ0FBQyxLQUFLLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxFQUFFLENBQUM7WUFDbkMsT0FBTyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQztRQUN6QixDQUFDO1FBRUQsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDM0QsTUFBTSxJQUFJLEdBQUcsY0FBYztZQUN6QixDQUFDLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2hFLElBQUksQ0FB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