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

198 lines (197 loc) • 10.3 kB
import { AxiosError } from 'axios'; import { ActivityLike, InvokeResponse, ISignInFailureInvokeActivity, ISignInTokenExchangeInvokeActivity, ISignInVerifyStateInvokeActivity, SignInFailure, TokenExchangeResource, TokenPostResource, TokenResponse } from '@microsoft/teams.api'; import type { IActivityContext } from '../contexts'; import type { IPlugin } from '../types'; import type { PluginAdditionalContext } from '../types/app-routing'; /** * Options used when an OAuth flow starts an interactive sign-in. */ export type OAuthSignInOptions = { /** * Text displayed on the OAuth card. * * When omitted, the SDK uses `Please Sign In...`. */ readonly oauthCardText?: string; /** * Text displayed on the OAuth card's sign-in button. * * When omitted, the SDK uses `Sign In`. */ readonly signInButtonText?: string; /** * Overrides the sign-in URL returned by the Bot Framework token service. * * Leave undefined to use the service-provided URL. * * @deprecated Use the sign-in URL returned by the Bot Framework token service. */ readonly signInLink?: string; /** * OAuth connection used for this sign-in. * * Leave undefined to use the activity context's default connection. An * {@link OAuthFlow} always supplies its own connection name. * * @deprecated Register the connection with `app.addOAuthFlow(...)`. Registered * flows always use their own connection name. */ readonly connectionName?: string; /** * Builds a custom sign-in activity instead of the SDK's OAuth card. * * The token exchange resource is undefined in channels because Teams cannot * complete silent token exchange there. Other undefined resources were not * returned by the token service and should be omitted from custom cards. * * @deprecated Use the SDK-generated OAuth card. Customize its text with * `oauthCardText` and `signInButtonText`. */ readonly overrideSignInActivity?: (tokenExchangeResource?: TokenExchangeResource, tokenPostResource?: TokenPostResource, signInLink?: string) => ActivityLike; }; type OAuthSignInInitiatedHandler = (context: IActivityContext, connectionName: string, supportsSso: boolean) => void | Promise<void>; /** @internal Gets a cached token or emits an OAuth sign-in card. */ export declare function startOAuthSignIn(context: IActivityContext, connectionName: string, options?: OAuthSignInOptions, onSignInInitiated?: OAuthSignInInitiatedHandler): Promise<string | undefined>; /** * Called after an interactive OAuth flow obtains a token. * * Cached tokens returned directly by {@link OAuthFlow.signIn} do not invoke * this callback. */ export type OAuthSignInCompleteHandler<TPlugin extends IPlugin = IPlugin> = (context: IActivityContext<ISignInTokenExchangeInvokeActivity | ISignInVerifyStateInvokeActivity, PluginAdditionalContext<TPlugin>>, token: TokenResponse) => void | Promise<void>; /** * Called when an OAuth flow cannot complete sign-in. * * `failure` contains the Teams client payload for `signin/failure` invokes. * It is undefined for token-service or token-exchange failures. */ export type OAuthSignInFailureHandler<TPlugin extends IPlugin = IPlugin> = (context: IActivityContext<ISignInFailureInvokeActivity | ISignInTokenExchangeInvokeActivity | ISignInVerifyStateInvokeActivity, PluginAdditionalContext<TPlugin>>, failure?: SignInFailure) => void | Promise<void>; /** * High-level OAuth lifecycle for one Bot Framework OAuth connection. * * Flows are registered through `AppOptions.oauthFlows` or * `app.addOAuthFlow(...)` so inbound sign-in invokes can be dispatched to the * correct connection. Apps without registered flows retain their legacy * default connection as the same flow type for backward compatibility. */ export declare class OAuthFlow<TPlugin extends IPlugin = IPlugin> { readonly connectionName: string; private readonly options; private static readonly PENDING_TTL_MS; private static readonly MAX_PENDING_ENTRIES; private static readonly EXCHANGE_TTL_MS; private static readonly MAX_EXCHANGE_ENTRIES; private static readonly EXCHANGE_STATE_KEY; private signInCompleteHandler?; private signInFailureHandler?; private readonly pendingSignIns; private readonly pendingSsoSignIns; private readonly tokenExchangeLocks; private readonly processedExchanges; /** * Creates an OAuth flow for a connection. * * Applications should use `AppOptions.oauthFlows` or * `app.addOAuthFlow(...)` so the flow is registered for inbound invokes. * @param connectionName OAuth connection name configured on the bot. * @param options Optional default card options. */ constructor(connectionName: string, options?: OAuthSignInOptions); /** * Registers the callback invoked after interactive sign-in completes. * * Calling this method again replaces the previous callback. */ onSignInComplete(handler: OAuthSignInCompleteHandler<TPlugin>): this; /** * Registers the callback invoked when interactive sign-in fails. * * Calling this method again replaces the previous callback. */ onSignInFailure(handler: OAuthSignInFailureHandler<TPlugin>): this; /** * Silently gets the current user's token for this connection. * * Returns undefined when the token service returns no token or reports `404`. * Other transport and service failures, including `400` and `412`, propagate. */ getToken(context: IActivityContext): Promise<string | undefined>; /** * Gets a cached token or sends an OAuth card to start interactive sign-in. * * Returns the cached token string when already signed in. Returns undefined * after sending a card; completion is then delivered to the registered * callback and the existing app `signin` event. Cached-token lookup errors * other than `404` propagate without sending a card. */ signIn(context: IActivityContext, options?: OAuthSignInOptions): Promise<string | undefined>; /** * Revokes the current user's token for this connection. */ signOut(context: IActivityContext): Promise<void>; /** * Returns whether a token is currently available for this connection. */ isSignedIn(context: IActivityContext): Promise<boolean>; /** @internal Invokes the registered completion callback. */ complete(context: IActivityContext<ISignInTokenExchangeInvokeActivity | ISignInVerifyStateInvokeActivity, PluginAdditionalContext<TPlugin>>, token: TokenResponse): Promise<void>; /** @internal Invokes the registered failure callback. */ fail(context: IActivityContext<ISignInFailureInvokeActivity | ISignInTokenExchangeInvokeActivity | ISignInVerifyStateInvokeActivity, PluginAdditionalContext<TPlugin>>, failure?: SignInFailure): Promise<void>; /** @internal Exchanges an SSO token for this flow. */ exchangeToken(context: IActivityContext<ISignInTokenExchangeInvokeActivity, PluginAdditionalContext<TPlugin>>, value: ISignInTokenExchangeInvokeActivity['value'], onSuccess: (token: TokenResponse) => void | Promise<void>, onError: (error: AxiosError) => void, connectionName?: string): Promise<InvokeResponse<'signin/tokenExchange'>>; /** @internal Attempts to redeem a verify-state code for this flow. */ verifyState(context: IActivityContext<ISignInVerifyStateInvokeActivity, PluginAdditionalContext<TPlugin>>, state: string | undefined, onSuccess: (token: TokenResponse) => void | Promise<void>, onError: (error: AxiosError) => void): Promise<InvokeResponse<'signin/verifyState'> | undefined>; /** @internal Records this flow as the source of an interactive sign-in. */ recordPending(context: IActivityContext, supportsSso: boolean): void; /** @internal Gets when this flow most recently initiated sign-in. */ getPending(context: IActivityContext, ssoOnly: boolean): number | undefined; /** @internal Clears pending sign-in attribution for this flow. */ clearPending(context: IActivityContext): void; private setPendingValue; private deletePendingValue; private pendingStateKey; private pendingMap; private pendingContextKey; private prunePending; private tokenExchangeFailure; private isExchangeProcessed; private markExchangeProcessed; private pruneProcessedExchanges; private getExchangeState; } /** * OAuth configuration for an app. * * @deprecated Register connections with `app.addOAuthFlow(...)` and use the * returned flow for token lookup, sign-in, status, and sign-out operations. * This configuration remains supported for legacy context OAuth behavior. */ export type OAuthSettings = { /** * the OAuth connection name to use for * authentication * * This legacy default cannot be combined with `AppOptions.oauthFlows` or * `app.addOAuthFlow(...)`. Deprecated context OAuth helpers may omit the * connection name to use this default; explicitly supplied connection names * continue to override it. When omitted, the same behavior uses `graph`. * @default `graph` * @deprecated Register the connection with `app.addOAuthFlow(...)`. */ readonly defaultConnectionName?: string; /** * whether to eagerly look up the user's OAuth token on every inbound activity. * the token is used to compute `ctx.isSignedIn` and `ctx.userToken`, and to authenticate * `ctx.userGraph` (which is always constructed regardless of this setting). * when left unset, this is auto-detected: enabled only when an OAuth connection is * explicitly configured via `defaultConnectionName`, so apps that never use user OAuth * do not pay for a wasted token request on every turn. * set explicitly to `true` or `false` to override the auto-detection. * @deprecated Use `OAuthFlow.getToken(...)` or `OAuthFlow.isSignedIn(...)` * only when the handler needs the user's OAuth state. */ readonly fetchUserToken?: boolean; }; /** @internal Defaults retained for deprecated context OAuth behavior. */ export declare const DEFAULT_OAUTH_SETTINGS: Required<Pick<OAuthSettings, 'defaultConnectionName'>>; export {};