@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
TypeScript
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 {};