@microsoft/teamsfx 0.3.0-alpha.def66483.0 → 0.3.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT license.
3
3
  import { __awaiter } from "tslib";
4
- import { ActivityTypes, CardFactory, Channels, MessageFactory, ActionTypes, verifyStateOperationName, StatusCodes, tokenExchangeOperationName, } from "botbuilder-core";
4
+ import { ActivityTypes, CardFactory, Channels, MessageFactory, ActionTypes, verifyStateOperationName, StatusCodes, tokenExchangeOperationName, TeamsInfo, } from "botbuilder";
5
5
  import { Dialog, } from "botbuilder-dialogs";
6
6
  import { config } from "../core/configurationProvider";
7
7
  import { OnBehalfOfUserCredential } from "../credential/onBehalfOfUserCredential";
@@ -214,7 +214,10 @@ export class TeamsBotSsoPrompt extends Dialog {
214
214
  sendOAuthCardAsync(context) {
215
215
  return __awaiter(this, void 0, void 0, function* () {
216
216
  internalLogger.verbose("Send OAuth card to get SSO token");
217
- const signInResource = this.getSignInResource();
217
+ const account = yield TeamsInfo.getMember(context, context.activity.from.id);
218
+ internalLogger.verbose("Get Teams member account user principal name: " + account.userPrincipalName);
219
+ const loginHint = account.userPrincipalName ? account.userPrincipalName : "";
220
+ const signInResource = this.getSignInResource(loginHint);
218
221
  const card = CardFactory.oauthCard("", "Teams SSO Sign In", "Sign In", signInResource.signInLink, signInResource.tokenExchangeResource);
219
222
  card.content.buttons[0].type = ActionTypes.Signin;
220
223
  const msg = MessageFactory.attachment(card);
@@ -229,7 +232,7 @@ export class TeamsBotSsoPrompt extends Dialog {
229
232
  *
230
233
  * @internal
231
234
  */
232
- getSignInResource() {
235
+ getSignInResource(loginHint) {
233
236
  var _a, _b, _c, _d, _e;
234
237
  internalLogger.verbose("Get sign in authentication configuration");
235
238
  const missingConfigurations = [];
@@ -250,7 +253,7 @@ export class TeamsBotSsoPrompt extends Dialog {
250
253
  internalLogger.error(errorMsg);
251
254
  throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);
252
255
  }
253
- const signInLink = `${config.authentication.initiateLoginEndpoint}?scope=${encodeURI(this.settings.scopes.join(" "))}&clientId=${config.authentication.clientId}&tenantId=${config.authentication.tenantId}`;
256
+ const signInLink = `${config.authentication.initiateLoginEndpoint}?scope=${encodeURI(this.settings.scopes.join(" "))}&clientId=${config.authentication.clientId}&tenantId=${config.authentication.tenantId}&loginHint=${loginHint}`;
254
257
  internalLogger.verbose("Sign in link: " + signInLink);
255
258
  const tokenExchangeResource = {
256
259
  id: uuidv4(),
@@ -1 +1 @@
1
- {"version":3,"file":"teamsBotSsoPrompt.js","sourceRoot":"","sources":["../../../src/bot/teamsBotSsoPrompt.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;;AAGlC,OAAO,EAEL,aAAa,EACb,WAAW,EACX,QAAQ,EACR,cAAc,EAGd,WAAW,EACX,wBAAwB,EACxB,WAAW,EAEX,0BAA0B,GAE3B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,MAAM,GAKP,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE3E,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;AAC5C;;;;GAIG;AACH,MAAM,2BAA2B;IAW/B,YAAY,EAAU,EAAE,aAAqB;QAC3C,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;CACF;AA4BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,MAAM,OAAO,iBAAkB,SAAQ,MAAM;IAC3C;;;;;;;;;;OAUG;IACH,YAAY,QAAgB,EAAU,QAAmC;QACvE,KAAK,CAAC,QAAQ,CAAC,CAAC;QADoB,aAAQ,GAAR,QAAQ,CAA2B;QAEvE,kBAAkB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACpC,cAAc,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IAC3D,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACU,WAAW,CAAC,EAAiB;;;YACxC,cAAc,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;YAClD,IAAI,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;YAE9B,0BAA0B;YAC1B,MAAM,eAAe,GAAG,MAAM,CAAC;YAC/B,IAAI,OAAO,GAAW,eAAe,CAAC;YACtC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE;gBACzB,IAAI,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,QAAQ,EAAE;oBAC5C,MAAM,QAAQ,GAAG,yEAAyE,CAAC;oBAC3F,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;oBAC/B,MAAM,IAAI,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,gBAAgB,CAAC,CAAC;iBAC/D;gBACD,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,CAAC,EAAE;oBAC9B,MAAM,QAAQ,GACZ,4EAA4E,CAAC;oBAC/E,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;oBAC/B,MAAM,IAAI,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,gBAAgB,CAAC,CAAC;iBAC/D;gBACD,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;aACjC;YAED,IAAI,IAAI,CAAC,QAAQ,CAAC,mBAAmB,KAAK,SAAS,EAAE;gBACnD,IAAI,CAAC,QAAQ,CAAC,mBAAmB,GAAG,IAAI,CAAC;aAC1C;YACD,MAAM,KAAK,GAA2B,MAAA,EAAE,CAAC,YAAY,0CAAE,KAA+B,CAAC;YACvF,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC;YACjB,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC;YACnB,KAAK,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC;YAE/C,mCAAmC;YACnC,MAAM,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;YAC1C,OAAO,MAAM,CAAC,SAAS,CAAC;;KACzB;IAED;;;;;;;;;;;;;;;;;OAiBG;IACU,cAAc,CAAC,EAAiB;;;YAC3C,cAAc,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;YACrD,IAAI,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;YAE9B,oBAAoB;YACpB,MAAM,KAAK,GAA2B,MAAA,EAAE,CAAC,YAAY,0CAAE,KAA+B,CAAC;YACvF,MAAM,SAAS,GAAY,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,KAAK,aAAa,CAAC,OAAO,CAAC;YAC9E,MAAM,qBAAqB,GACzB,SAAS;gBACT,IAAI,CAAC,yBAAyB,CAAC,EAAE,CAAC,OAAO,CAAC;gBAC1C,IAAI,CAAC,4BAA4B,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;YAEhD,oGAAoG;YACpG,2FAA2F;YAC3F,MAAM,WAAW,GAAY,qBAAqB,IAAI,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC;YAC3F,IAAI,WAAW,EAAE;gBACf,cAAc,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;gBAC/D,OAAO,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;aACtC;iBAAM;gBACL,IACE,IAAI,CAAC,yBAAyB,CAAC,EAAE,CAAC,OAAO,CAAC;oBAC1C,IAAI,CAAC,4BAA4B,CAAC,EAAE,CAAC,OAAO,CAAC,EAC7C;oBACA,kBAAkB;oBAClB,MAAM,UAAU,GACd,MAAM,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;oBAEhC,IAAI,UAAU,CAAC,SAAS,EAAE;wBACxB,OAAO,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;qBAC7C;iBACF;qBAAM,IAAI,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,mBAAmB,EAAE;oBACzD,cAAc,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;oBACvE,OAAO,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;iBACtC;gBAED,OAAO,MAAM,CAAC,SAAS,CAAC;aACzB;;KACF;IAED;;;;;OAKG;IACK,oBAAoB,CAAC,EAAiB;QAC5C,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,OAAO,EAAE;YACrD,MAAM,QAAQ,GAAG,YAAY,CAC3B,YAAY,CAAC,2BAA2B,EACxC,sBAAsB,CACvB,CAAC;YACF,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC/B,MAAM,IAAI,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,mBAAmB,CAAC,CAAC;SAClE;IACH,CAAC;IAED;;;;;OAKG;IACW,kBAAkB,CAAC,OAAoB;;YACnD,cAAc,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC;YAE3D,MAAM,cAAc,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAChD,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAChC,EAAE,EACF,mBAAmB,EACnB,SAAS,EACT,cAAc,CAAC,UAAU,EACzB,cAAc,CAAC,qBAAqB,CACrC,CAAC;YACD,IAAI,CAAC,OAAqB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC;YACjE,MAAM,GAAG,GAAsB,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YAE/D,cAAc;YACd,MAAM,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAClC,CAAC;KAAA;IAED;;;;;;OAMG;IACK,iBAAiB;;QACvB,cAAc,CAAC,OAAO,CAAC,0CAA0C,CAAC,CAAC;QACnE,MAAM,qBAAqB,GAAa,EAAE,CAAC;QAE3C,IAAI,CAAC,CAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,cAAc,0CAAE,qBAAqB,CAAA,EAAE;YAClD,qBAAqB,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;SACrD;QAED,IAAI,CAAC,CAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,cAAc,0CAAE,QAAQ,CAAA,EAAE;YACrC,qBAAqB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SACxC;QAED,IAAI,CAAC,CAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,cAAc,0CAAE,QAAQ,CAAA,EAAE;YACrC,qBAAqB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SACxC;QAED,IAAI,CAAC,CAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,cAAc,0CAAE,gBAAgB,CAAA,EAAE;YAC7C,qBAAqB,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;SAChD;QAED,IAAI,qBAAqB,CAAC,MAAM,IAAI,CAAC,EAAE;YACrC,MAAM,QAAQ,GAAG,YAAY,CAC3B,YAAY,CAAC,oBAAoB,EACjC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAChC,WAAW,CACZ,CAAC;YACF,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC/B,MAAM,IAAI,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,oBAAoB,CAAC,CAAC;SACnE;QAED,MAAM,UAAU,GAAG,GAAG,MAAM,CAAC,cAAe,CAAC,qBAAqB,UAAU,SAAS,CACnF,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAC/B,aAAa,MAAM,CAAC,cAAe,CAAC,QAAQ,aAAa,MAAM,CAAC,cAAe,CAAC,QAAQ,EAAE,CAAC;QAE5F,cAAc,CAAC,OAAO,CAAC,gBAAgB,GAAG,UAAU,CAAC,CAAC;QAEtD,MAAM,qBAAqB,GAA0B;YACnD,EAAE,EAAE,MAAM,EAAE;YACZ,GAAG,EAAE,CAAA,MAAA,MAAM,CAAC,cAAc,0CAAE,gBAAgB,CAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAG,iBAAiB;SACrF,CAAC;QAEF,cAAc,CAAC,OAAO,CAAC,+BAA+B,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAEpF,OAAO;YACL,UAAU,EAAE,UAAU;YACtB,qBAAqB,EAAE,qBAAqB;SAC7C,CAAC;IACJ,CAAC;IAED;;OAEG;IACW,cAAc,CAC1B,EAAiB;;YAEjB,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;YAC3B,IAAI,aAAyD,CAAC;YAE9D,IAAI,IAAI,CAAC,4BAA4B,CAAC,OAAO,CAAC,EAAE;gBAC9C,cAAc,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;gBACzD,oDAAoD;gBACpD,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE;oBACpF,MAAM,UAAU,GACd,6IAA6I,CAAC;oBAEhJ,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBAChC,MAAM,OAAO,CAAC,YAAY,CACxB,IAAI,CAAC,8BAA8B,CAAC,WAAW,CAAC,WAAW,EAAE,UAAU,CAAC,CACzE,CAAC;iBACH;qBAAM;oBACL,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC;oBAC9C,MAAM,UAAU,GAA6B,IAAI,wBAAwB,CAAC,QAAQ,CAAC,CAAC;oBACpF,IAAI,cAAkC,CAAC;oBACvC,IAAI;wBACF,cAAc,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;wBAEjE,IAAI,cAAc,EAAE;4BAClB,MAAM,OAAO,CAAC,YAAY,CACxB,IAAI,CAAC,8BAA8B,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CACnF,CAAC;4BAEF,MAAM,kBAAkB,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC;4BAClD,aAAa,GAAG;gCACd,QAAQ,EAAE,QAAQ;gCAClB,kBAAkB,EAAE,IAAI,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;gCACrE,cAAc,EAAE,EAAE;gCAClB,KAAK,EAAE,cAAc,CAAC,KAAK;gCAC3B,UAAU,EAAE,cAAc,CAAC,kBAAkB,CAAC,QAAQ,EAAE;6BACzD,CAAC;yBACH;qBACF;oBAAC,OAAO,KAAK,EAAE;wBACd,MAAM,UAAU,GAAG,4DAA4D,CAAC;wBAChF,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;wBAChC,MAAM,OAAO,CAAC,YAAY,CACxB,IAAI,CAAC,8BAA8B,CACjC,WAAW,CAAC,mBAAmB,EAC/B,UAAU,EACV,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAC1B,CACF,CAAC;qBACH;iBACF;aACF;iBAAM,IAAI,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC,EAAE;gBAClD,cAAc,CAAC,OAAO,CAAC,0CAA0C,CAAC,CAAC;gBACnE,MAAM,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;gBAC1C,MAAM,OAAO,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;aAC7F;YAED,OAAO,aAAa,KAAK,SAAS;gBAChC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE;gBAC3C,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAC3B,CAAC;KAAA;IAED;;OAEG;IACK,8BAA8B,CACpC,MAAc,EACd,aAAqB,EACrB,EAAW;QAEX,MAAM,cAAc,GAAsB;YACxC,IAAI,EAAE,kBAAkB;YACxB,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,2BAA2B,CAAC,EAAY,EAAE,aAAa,CAAC,EAAE;SACtF,CAAC;QACF,OAAO,cAA0B,CAAC;IACpC,CAAC;IAED;;OAEG;IACK,yBAAyB,CAAC,OAAoB;QACpD,MAAM,QAAQ,GAAa,OAAO,CAAC,QAAQ,CAAC;QAE5C,OAAO,QAAQ,CAAC,IAAI,KAAK,aAAa,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,wBAAwB,CAAC;IAC9F,CAAC;IAED;;OAEG;IACK,4BAA4B,CAAC,OAAoB;QACvD,MAAM,QAAQ,GAAa,OAAO,CAAC,QAAQ,CAAC;QAE5C,OAAO,QAAQ,CAAC,IAAI,KAAK,aAAa,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,0BAA0B,CAAC;IAChG,CAAC;IAED;;OAEG;IACK,sBAAsB,CAAC,GAAQ;QACrC,OAAO,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { AccessToken } from \"@azure/identity\";\nimport {\n Activity,\n ActivityTypes,\n CardFactory,\n Channels,\n MessageFactory,\n TurnContext,\n OAuthCard,\n ActionTypes,\n verifyStateOperationName,\n StatusCodes,\n TokenExchangeInvokeRequest,\n tokenExchangeOperationName,\n TokenExchangeResource,\n} from \"botbuilder-core\";\nimport {\n Dialog,\n DialogContext,\n DialogTurnResult,\n PromptOptions,\n PromptRecognizerResult,\n} from \"botbuilder-dialogs\";\nimport { TeamsBotSsoPromptTokenResponse } from \"./teamsBotSsoPromptTokenResponse\";\nimport { config } from \"../core/configurationProvider\";\nimport { OnBehalfOfUserCredential } from \"../credential/onBehalfOfUserCredential\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { ErrorWithCode, ErrorCode, ErrorMessage } from \"../core/errors\";\nimport { internalLogger } from \"../util/logger\";\nimport { validateScopesType, formatString, parseJwt } from \"../util/utils\";\n\nconst invokeResponseType = \"invokeResponse\";\n/**\n * Response body returned for a token exchange invoke activity.\n *\n * @beta\n */\nclass TokenExchangeInvokeResponse {\n /**\n * Response id\n */\n id: string;\n\n /**\n * Detailed error message\n */\n failureDetail: string;\n\n constructor(id: string, failureDetail: string) {\n this.id = id;\n this.failureDetail = failureDetail;\n }\n}\n\n/**\n * Settings used to configure an TeamsBotSsoPrompt instance.\n *\n * @beta\n */\nexport interface TeamsBotSsoPromptSettings {\n /**\n * The array of strings that declare the desired permissions and the resources requested.\n */\n scopes: string[];\n\n /**\n * (Optional) number of milliseconds the prompt will wait for the user to authenticate.\n * Defaults to a value `900,000` (15 minutes.)\n */\n timeout?: number;\n\n /**\n * (Optional) value indicating whether the TeamsBotSsoPrompt should end upon receiving an\n * invalid message. Generally the TeamsBotSsoPrompt will end the auth flow when receives user\n * message not related to the auth flow. Setting the flag to false ignores the user's message instead.\n * Defaults to value `true`\n */\n endOnInvalidMessage?: boolean;\n}\n\n/**\n * Creates a new prompt that leverage Teams Single Sign On (SSO) support for bot to automatically sign in user and\n * help receive oauth token, asks the user to consent if needed.\n *\n * @remarks\n * The prompt will attempt to retrieve the users current token of the desired scopes and store it in\n * the token store.\n *\n * User will be automatically signed in leveraging Teams support of Bot Single Sign On(SSO):\n * https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/auth-aad-sso-bots\n *\n * @example\n * When used with your bots `DialogSet` you can simply add a new instance of the prompt as a named\n * dialog using `DialogSet.add()`. You can then start the prompt from a waterfall step using either\n * `DialogContext.beginDialog()` or `DialogContext.prompt()`. The user will be prompted to sign in as\n * needed and their access token will be passed as an argument to the callers next waterfall step:\n *\n * ```JavaScript\n * const { ConversationState, MemoryStorage } = require('botbuilder');\n * const { DialogSet, WaterfallDialog } = require('botbuilder-dialogs');\n * const { TeamsBotSsoPrompt } = require('@microsoft/teamsfx');\n *\n * const convoState = new ConversationState(new MemoryStorage());\n * const dialogState = convoState.createProperty('dialogState');\n * const dialogs = new DialogSet(dialogState);\n *\n * loadConfiguration();\n * dialogs.add(new TeamsBotSsoPrompt('TeamsBotSsoPrompt', {\n * scopes: [\"User.Read\"],\n * }));\n *\n * dialogs.add(new WaterfallDialog('taskNeedingLogin', [\n * async (step) => {\n * return await step.beginDialog('TeamsBotSsoPrompt');\n * },\n * async (step) => {\n * const token = step.result;\n * if (token) {\n *\n * // ... continue with task needing access token ...\n *\n * } else {\n * await step.context.sendActivity(`Sorry... We couldn't log you in. Try again later.`);\n * return await step.endDialog();\n * }\n * }\n * ]));\n * ```\n *\n * @beta\n */\nexport class TeamsBotSsoPrompt extends Dialog {\n /**\n * Constructor of TeamsBotSsoPrompt.\n *\n * @param dialogId Unique ID of the dialog within its parent `DialogSet` or `ComponentDialog`.\n * @param settings Settings used to configure the prompt.\n *\n * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.\n *\n * @beta\n */\n constructor(dialogId: string, private settings: TeamsBotSsoPromptSettings) {\n super(dialogId);\n validateScopesType(settings.scopes);\n internalLogger.info(\"Create a new Teams Bot SSO Prompt\");\n }\n\n /**\n * Called when a prompt dialog is pushed onto the dialog stack and is being activated.\n * @remarks\n * If the task is successful, the result indicates whether the prompt is still\n * active after the turn has been processed by the prompt.\n *\n * @param dc The DialogContext for the current turn of the conversation.\n *\n * @throws {@link ErrorCode|InvalidParameter} when timeout property in teams bot sso prompt settings is not number or is not positive.\n * @throws {@link ErrorCode|ChannelNotSupported} when bot channel is not MS Teams.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.\n *\n * @returns A `Promise` representing the asynchronous operation.\n *\n * @beta\n */\n public async beginDialog(dc: DialogContext): Promise<DialogTurnResult> {\n internalLogger.info(\"Begin Teams Bot SSO Prompt\");\n this.ensureMsTeamsChannel(dc);\n\n // Initialize prompt state\n const default_timeout = 900000;\n let timeout: number = default_timeout;\n if (this.settings.timeout) {\n if (typeof this.settings.timeout != \"number\") {\n const errorMsg = \"type of timeout property in teamsBotSsoPromptSettings should be number.\";\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InvalidParameter);\n }\n if (this.settings.timeout <= 0) {\n const errorMsg =\n \"value of timeout property in teamsBotSsoPromptSettings should be positive.\";\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InvalidParameter);\n }\n timeout = this.settings.timeout;\n }\n\n if (this.settings.endOnInvalidMessage === undefined) {\n this.settings.endOnInvalidMessage = true;\n }\n const state: teamsBotSsoPromptState = dc.activeDialog?.state as teamsBotSsoPromptState;\n state.state = {};\n state.options = {};\n state.expires = new Date().getTime() + timeout;\n\n // Send OAuth card to get SSO token\n await this.sendOAuthCardAsync(dc.context);\n return Dialog.EndOfTurn;\n }\n\n /**\n * Called when a prompt dialog is the active dialog and the user replied with a new activity.\n *\n * @remarks\n * If the task is successful, the result indicates whether the dialog is still\n * active after the turn has been processed by the dialog.\n * The prompt generally continues to receive the user's replies until it accepts the\n * user's reply as valid input for the prompt.\n *\n * @param dc The DialogContext for the current turn of the conversation.\n *\n * @returns A `Promise` representing the asynchronous operation.\n *\n * @throws {@link ErrorCode|ChannelNotSupported} when bot channel is not MS Teams.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.\n *\n * @beta\n */\n public async continueDialog(dc: DialogContext): Promise<DialogTurnResult> {\n internalLogger.info(\"Continue Teams Bot SSO Prompt\");\n this.ensureMsTeamsChannel(dc);\n\n // Check for timeout\n const state: teamsBotSsoPromptState = dc.activeDialog?.state as teamsBotSsoPromptState;\n const isMessage: boolean = dc.context.activity.type === ActivityTypes.Message;\n const isTimeoutActivityType: boolean =\n isMessage ||\n this.isTeamsVerificationInvoke(dc.context) ||\n this.isTokenExchangeRequestInvoke(dc.context);\n\n // If the incoming Activity is a message, or an Activity Type normally handled by TeamsBotSsoPrompt,\n // check to see if this TeamsBotSsoPrompt Expiration has elapsed, and end the dialog if so.\n const hasTimedOut: boolean = isTimeoutActivityType && new Date().getTime() > state.expires;\n if (hasTimedOut) {\n internalLogger.warn(\"End Teams Bot SSO Prompt due to timeout\");\n return await dc.endDialog(undefined);\n } else {\n if (\n this.isTeamsVerificationInvoke(dc.context) ||\n this.isTokenExchangeRequestInvoke(dc.context)\n ) {\n // Recognize token\n const recognized: PromptRecognizerResult<TeamsBotSsoPromptTokenResponse> =\n await this.recognizeToken(dc);\n\n if (recognized.succeeded) {\n return await dc.endDialog(recognized.value);\n }\n } else if (isMessage && this.settings.endOnInvalidMessage) {\n internalLogger.warn(\"End Teams Bot SSO Prompt due to invalid message\");\n return await dc.endDialog(undefined);\n }\n\n return Dialog.EndOfTurn;\n }\n }\n\n /**\n * Ensure bot is running in MS Teams since TeamsBotSsoPrompt is only supported in MS Teams channel.\n * @param dc dialog context\n * @throws {@link ErrorCode|ChannelNotSupported} if bot channel is not MS Teams\n * @internal\n */\n private ensureMsTeamsChannel(dc: DialogContext) {\n if (dc.context.activity.channelId != Channels.Msteams) {\n const errorMsg = formatString(\n ErrorMessage.OnlyMSTeamsChannelSupported,\n \"Teams Bot SSO Prompt\"\n );\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.ChannelNotSupported);\n }\n }\n\n /**\n * Send OAuthCard that tells Teams to obtain an authentication token for the bot application.\n * For details see https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/auth-aad-sso-bots.\n *\n * @internal\n */\n private async sendOAuthCardAsync(context: TurnContext): Promise<void> {\n internalLogger.verbose(\"Send OAuth card to get SSO token\");\n\n const signInResource = this.getSignInResource();\n const card = CardFactory.oauthCard(\n \"\",\n \"Teams SSO Sign In\",\n \"Sign In\",\n signInResource.signInLink,\n signInResource.tokenExchangeResource\n );\n (card.content as OAuthCard).buttons[0].type = ActionTypes.Signin;\n const msg: Partial<Activity> = MessageFactory.attachment(card);\n\n // Send prompt\n await context.sendActivity(msg);\n }\n\n /**\n * Get sign in resource.\n *\n * @throws {@link ErrorCode|InvalidConfiguration} if client id, tenant id or initiate login endpoint is not found in config.\n *\n * @internal\n */\n private getSignInResource() {\n internalLogger.verbose(\"Get sign in authentication configuration\");\n const missingConfigurations: string[] = [];\n\n if (!config?.authentication?.initiateLoginEndpoint) {\n missingConfigurations.push(\"initiateLoginEndpoint\");\n }\n\n if (!config?.authentication?.clientId) {\n missingConfigurations.push(\"clientId\");\n }\n\n if (!config?.authentication?.tenantId) {\n missingConfigurations.push(\"tenantId\");\n }\n\n if (!config?.authentication?.applicationIdUri) {\n missingConfigurations.push(\"applicationIdUri\");\n }\n\n if (missingConfigurations.length != 0) {\n const errorMsg = formatString(\n ErrorMessage.InvalidConfiguration,\n missingConfigurations.join(\", \"),\n \"undefined\"\n );\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);\n }\n\n const signInLink = `${config.authentication!.initiateLoginEndpoint}?scope=${encodeURI(\n this.settings.scopes.join(\" \")\n )}&clientId=${config.authentication!.clientId}&tenantId=${config.authentication!.tenantId}`;\n\n internalLogger.verbose(\"Sign in link: \" + signInLink);\n\n const tokenExchangeResource: TokenExchangeResource = {\n id: uuidv4(),\n uri: config.authentication?.applicationIdUri!.replace(/\\/$/, \"\") + \"/access_as_user\",\n };\n\n internalLogger.verbose(\"Token exchange resource uri: \" + tokenExchangeResource.uri);\n\n return {\n signInLink: signInLink,\n tokenExchangeResource: tokenExchangeResource,\n };\n }\n\n /**\n * @internal\n */\n private async recognizeToken(\n dc: DialogContext\n ): Promise<PromptRecognizerResult<TeamsBotSsoPromptTokenResponse>> {\n const context = dc.context;\n let tokenResponse: TeamsBotSsoPromptTokenResponse | undefined;\n\n if (this.isTokenExchangeRequestInvoke(context)) {\n internalLogger.verbose(\"Receive token exchange request\");\n // Received activity is not a token exchange request\n if (!(context.activity.value && this.isTokenExchangeRequest(context.activity.value))) {\n const warningMsg =\n \"The bot received an InvokeActivity that is missing a TokenExchangeInvokeRequest value. This is required to be sent with the InvokeActivity.\";\n\n internalLogger.warn(warningMsg);\n await context.sendActivity(\n this.getTokenExchangeInvokeResponse(StatusCodes.BAD_REQUEST, warningMsg)\n );\n } else {\n const ssoToken = context.activity.value.token;\n const credential: OnBehalfOfUserCredential = new OnBehalfOfUserCredential(ssoToken);\n let exchangedToken: AccessToken | null;\n try {\n exchangedToken = await credential.getToken(this.settings.scopes);\n\n if (exchangedToken) {\n await context.sendActivity(\n this.getTokenExchangeInvokeResponse(StatusCodes.OK, \"\", context.activity.value.id)\n );\n\n const ssoTokenExpiration = parseJwt(ssoToken).exp;\n tokenResponse = {\n ssoToken: ssoToken,\n ssoTokenExpiration: new Date(ssoTokenExpiration * 1000).toISOString(),\n connectionName: \"\",\n token: exchangedToken.token,\n expiration: exchangedToken.expiresOnTimestamp.toString(),\n };\n }\n } catch (error) {\n const warningMsg = \"The bot is unable to exchange token. Ask for user consent.\";\n internalLogger.info(warningMsg);\n await context.sendActivity(\n this.getTokenExchangeInvokeResponse(\n StatusCodes.PRECONDITION_FAILED,\n warningMsg,\n context.activity.value.id\n )\n );\n }\n }\n } else if (this.isTeamsVerificationInvoke(context)) {\n internalLogger.verbose(\"Receive Teams state verification request\");\n await this.sendOAuthCardAsync(dc.context);\n await context.sendActivity({ type: invokeResponseType, value: { status: StatusCodes.OK } });\n }\n\n return tokenResponse !== undefined\n ? { succeeded: true, value: tokenResponse }\n : { succeeded: false };\n }\n\n /**\n * @internal\n */\n private getTokenExchangeInvokeResponse(\n status: number,\n failureDetail: string,\n id?: string\n ): Activity {\n const invokeResponse: Partial<Activity> = {\n type: invokeResponseType,\n value: { status, body: new TokenExchangeInvokeResponse(id as string, failureDetail) },\n };\n return invokeResponse as Activity;\n }\n\n /**\n * @internal\n */\n private isTeamsVerificationInvoke(context: TurnContext): boolean {\n const activity: Activity = context.activity;\n\n return activity.type === ActivityTypes.Invoke && activity.name === verifyStateOperationName;\n }\n\n /**\n * @internal\n */\n private isTokenExchangeRequestInvoke(context: TurnContext): boolean {\n const activity: Activity = context.activity;\n\n return activity.type === ActivityTypes.Invoke && activity.name === tokenExchangeOperationName;\n }\n\n /**\n * @internal\n */\n private isTokenExchangeRequest(obj: any): obj is TokenExchangeInvokeRequest {\n return obj.hasOwnProperty(\"token\");\n }\n}\n\n/**\n * @internal\n */\ninterface teamsBotSsoPromptState {\n state: any;\n options: PromptOptions;\n expires: number; // Timestamp of when the prompt will timeout.\n}\n"]}
1
+ {"version":3,"file":"teamsBotSsoPrompt.js","sourceRoot":"","sources":["../../../src/bot/teamsBotSsoPrompt.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;;AAGlC,OAAO,EAEL,aAAa,EACb,WAAW,EACX,QAAQ,EACR,cAAc,EAGd,WAAW,EACX,wBAAwB,EACxB,WAAW,EAEX,0BAA0B,EAE1B,SAAS,GAEV,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,MAAM,GAKP,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE3E,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;AAC5C;;;;GAIG;AACH,MAAM,2BAA2B;IAW/B,YAAY,EAAU,EAAE,aAAqB;QAC3C,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;CACF;AA4BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,MAAM,OAAO,iBAAkB,SAAQ,MAAM;IAC3C;;;;;;;;;;OAUG;IACH,YAAY,QAAgB,EAAU,QAAmC;QACvE,KAAK,CAAC,QAAQ,CAAC,CAAC;QADoB,aAAQ,GAAR,QAAQ,CAA2B;QAEvE,kBAAkB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACpC,cAAc,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IAC3D,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACU,WAAW,CAAC,EAAiB;;;YACxC,cAAc,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;YAClD,IAAI,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;YAE9B,0BAA0B;YAC1B,MAAM,eAAe,GAAG,MAAM,CAAC;YAC/B,IAAI,OAAO,GAAW,eAAe,CAAC;YACtC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE;gBACzB,IAAI,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,QAAQ,EAAE;oBAC5C,MAAM,QAAQ,GAAG,yEAAyE,CAAC;oBAC3F,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;oBAC/B,MAAM,IAAI,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,gBAAgB,CAAC,CAAC;iBAC/D;gBACD,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,CAAC,EAAE;oBAC9B,MAAM,QAAQ,GACZ,4EAA4E,CAAC;oBAC/E,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;oBAC/B,MAAM,IAAI,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,gBAAgB,CAAC,CAAC;iBAC/D;gBACD,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;aACjC;YAED,IAAI,IAAI,CAAC,QAAQ,CAAC,mBAAmB,KAAK,SAAS,EAAE;gBACnD,IAAI,CAAC,QAAQ,CAAC,mBAAmB,GAAG,IAAI,CAAC;aAC1C;YACD,MAAM,KAAK,GAA2B,MAAA,EAAE,CAAC,YAAY,0CAAE,KAA+B,CAAC;YACvF,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC;YACjB,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC;YACnB,KAAK,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC;YAE/C,mCAAmC;YACnC,MAAM,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;YAC1C,OAAO,MAAM,CAAC,SAAS,CAAC;;KACzB;IAED;;;;;;;;;;;;;;;;;OAiBG;IACU,cAAc,CAAC,EAAiB;;;YAC3C,cAAc,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;YACrD,IAAI,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;YAE9B,oBAAoB;YACpB,MAAM,KAAK,GAA2B,MAAA,EAAE,CAAC,YAAY,0CAAE,KAA+B,CAAC;YACvF,MAAM,SAAS,GAAY,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,KAAK,aAAa,CAAC,OAAO,CAAC;YAC9E,MAAM,qBAAqB,GACzB,SAAS;gBACT,IAAI,CAAC,yBAAyB,CAAC,EAAE,CAAC,OAAO,CAAC;gBAC1C,IAAI,CAAC,4BAA4B,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;YAEhD,oGAAoG;YACpG,2FAA2F;YAC3F,MAAM,WAAW,GAAY,qBAAqB,IAAI,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC;YAC3F,IAAI,WAAW,EAAE;gBACf,cAAc,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;gBAC/D,OAAO,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;aACtC;iBAAM;gBACL,IACE,IAAI,CAAC,yBAAyB,CAAC,EAAE,CAAC,OAAO,CAAC;oBAC1C,IAAI,CAAC,4BAA4B,CAAC,EAAE,CAAC,OAAO,CAAC,EAC7C;oBACA,kBAAkB;oBAClB,MAAM,UAAU,GACd,MAAM,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;oBAEhC,IAAI,UAAU,CAAC,SAAS,EAAE;wBACxB,OAAO,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;qBAC7C;iBACF;qBAAM,IAAI,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,mBAAmB,EAAE;oBACzD,cAAc,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;oBACvE,OAAO,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;iBACtC;gBAED,OAAO,MAAM,CAAC,SAAS,CAAC;aACzB;;KACF;IAED;;;;;OAKG;IACK,oBAAoB,CAAC,EAAiB;QAC5C,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,OAAO,EAAE;YACrD,MAAM,QAAQ,GAAG,YAAY,CAC3B,YAAY,CAAC,2BAA2B,EACxC,sBAAsB,CACvB,CAAC;YACF,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC/B,MAAM,IAAI,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,mBAAmB,CAAC,CAAC;SAClE;IACH,CAAC;IAED;;;;;OAKG;IACW,kBAAkB,CAAC,OAAoB;;YACnD,cAAc,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC;YAE3D,MAAM,OAAO,GAAwB,MAAM,SAAS,CAAC,SAAS,CAC5D,OAAO,EACP,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CACzB,CAAC;YACF,cAAc,CAAC,OAAO,CACpB,gDAAgD,GAAG,OAAO,CAAC,iBAAiB,CAC7E,CAAC;YAEF,MAAM,SAAS,GAAW,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC;YACrF,MAAM,cAAc,GAAG,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;YACzD,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAChC,EAAE,EACF,mBAAmB,EACnB,SAAS,EACT,cAAc,CAAC,UAAU,EACzB,cAAc,CAAC,qBAAqB,CACrC,CAAC;YACD,IAAI,CAAC,OAAqB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC;YACjE,MAAM,GAAG,GAAsB,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YAE/D,cAAc;YACd,MAAM,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAClC,CAAC;KAAA;IAED;;;;;;OAMG;IACK,iBAAiB,CAAC,SAAiB;;QACzC,cAAc,CAAC,OAAO,CAAC,0CAA0C,CAAC,CAAC;QACnE,MAAM,qBAAqB,GAAa,EAAE,CAAC;QAE3C,IAAI,CAAC,CAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,cAAc,0CAAE,qBAAqB,CAAA,EAAE;YAClD,qBAAqB,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;SACrD;QAED,IAAI,CAAC,CAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,cAAc,0CAAE,QAAQ,CAAA,EAAE;YACrC,qBAAqB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SACxC;QAED,IAAI,CAAC,CAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,cAAc,0CAAE,QAAQ,CAAA,EAAE;YACrC,qBAAqB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SACxC;QAED,IAAI,CAAC,CAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,cAAc,0CAAE,gBAAgB,CAAA,EAAE;YAC7C,qBAAqB,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;SAChD;QAED,IAAI,qBAAqB,CAAC,MAAM,IAAI,CAAC,EAAE;YACrC,MAAM,QAAQ,GAAG,YAAY,CAC3B,YAAY,CAAC,oBAAoB,EACjC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAChC,WAAW,CACZ,CAAC;YACF,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC/B,MAAM,IAAI,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,oBAAoB,CAAC,CAAC;SACnE;QAED,MAAM,UAAU,GAAG,GAAG,MAAM,CAAC,cAAe,CAAC,qBAAqB,UAAU,SAAS,CACnF,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAC/B,aAAa,MAAM,CAAC,cAAe,CAAC,QAAQ,aAC3C,MAAM,CAAC,cAAe,CAAC,QACzB,cAAc,SAAS,EAAE,CAAC;QAE1B,cAAc,CAAC,OAAO,CAAC,gBAAgB,GAAG,UAAU,CAAC,CAAC;QAEtD,MAAM,qBAAqB,GAA0B;YACnD,EAAE,EAAE,MAAM,EAAE;YACZ,GAAG,EAAE,CAAA,MAAA,MAAM,CAAC,cAAc,0CAAE,gBAAgB,CAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAG,iBAAiB;SACrF,CAAC;QAEF,cAAc,CAAC,OAAO,CAAC,+BAA+B,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAEpF,OAAO;YACL,UAAU,EAAE,UAAU;YACtB,qBAAqB,EAAE,qBAAqB;SAC7C,CAAC;IACJ,CAAC;IAED;;OAEG;IACW,cAAc,CAC1B,EAAiB;;YAEjB,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;YAC3B,IAAI,aAAyD,CAAC;YAE9D,IAAI,IAAI,CAAC,4BAA4B,CAAC,OAAO,CAAC,EAAE;gBAC9C,cAAc,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;gBACzD,oDAAoD;gBACpD,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE;oBACpF,MAAM,UAAU,GACd,6IAA6I,CAAC;oBAEhJ,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBAChC,MAAM,OAAO,CAAC,YAAY,CACxB,IAAI,CAAC,8BAA8B,CAAC,WAAW,CAAC,WAAW,EAAE,UAAU,CAAC,CACzE,CAAC;iBACH;qBAAM;oBACL,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC;oBAC9C,MAAM,UAAU,GAA6B,IAAI,wBAAwB,CAAC,QAAQ,CAAC,CAAC;oBACpF,IAAI,cAAkC,CAAC;oBACvC,IAAI;wBACF,cAAc,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;wBAEjE,IAAI,cAAc,EAAE;4BAClB,MAAM,OAAO,CAAC,YAAY,CACxB,IAAI,CAAC,8BAA8B,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CACnF,CAAC;4BAEF,MAAM,kBAAkB,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC;4BAClD,aAAa,GAAG;gCACd,QAAQ,EAAE,QAAQ;gCAClB,kBAAkB,EAAE,IAAI,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;gCACrE,cAAc,EAAE,EAAE;gCAClB,KAAK,EAAE,cAAc,CAAC,KAAK;gCAC3B,UAAU,EAAE,cAAc,CAAC,kBAAkB,CAAC,QAAQ,EAAE;6BACzD,CAAC;yBACH;qBACF;oBAAC,OAAO,KAAK,EAAE;wBACd,MAAM,UAAU,GAAG,4DAA4D,CAAC;wBAChF,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;wBAChC,MAAM,OAAO,CAAC,YAAY,CACxB,IAAI,CAAC,8BAA8B,CACjC,WAAW,CAAC,mBAAmB,EAC/B,UAAU,EACV,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAC1B,CACF,CAAC;qBACH;iBACF;aACF;iBAAM,IAAI,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC,EAAE;gBAClD,cAAc,CAAC,OAAO,CAAC,0CAA0C,CAAC,CAAC;gBACnE,MAAM,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;gBAC1C,MAAM,OAAO,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;aAC7F;YAED,OAAO,aAAa,KAAK,SAAS;gBAChC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE;gBAC3C,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAC3B,CAAC;KAAA;IAED;;OAEG;IACK,8BAA8B,CACpC,MAAc,EACd,aAAqB,EACrB,EAAW;QAEX,MAAM,cAAc,GAAsB;YACxC,IAAI,EAAE,kBAAkB;YACxB,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,2BAA2B,CAAC,EAAY,EAAE,aAAa,CAAC,EAAE;SACtF,CAAC;QACF,OAAO,cAA0B,CAAC;IACpC,CAAC;IAED;;OAEG;IACK,yBAAyB,CAAC,OAAoB;QACpD,MAAM,QAAQ,GAAa,OAAO,CAAC,QAAQ,CAAC;QAE5C,OAAO,QAAQ,CAAC,IAAI,KAAK,aAAa,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,wBAAwB,CAAC;IAC9F,CAAC;IAED;;OAEG;IACK,4BAA4B,CAAC,OAAoB;QACvD,MAAM,QAAQ,GAAa,OAAO,CAAC,QAAQ,CAAC;QAE5C,OAAO,QAAQ,CAAC,IAAI,KAAK,aAAa,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,0BAA0B,CAAC;IAChG,CAAC;IAED;;OAEG;IACK,sBAAsB,CAAC,GAAQ;QACrC,OAAO,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { AccessToken } from \"@azure/identity\";\nimport {\n Activity,\n ActivityTypes,\n CardFactory,\n Channels,\n MessageFactory,\n TurnContext,\n OAuthCard,\n ActionTypes,\n verifyStateOperationName,\n StatusCodes,\n TokenExchangeInvokeRequest,\n tokenExchangeOperationName,\n TokenExchangeResource,\n TeamsInfo,\n TeamsChannelAccount,\n} from \"botbuilder\";\nimport {\n Dialog,\n DialogContext,\n DialogTurnResult,\n PromptOptions,\n PromptRecognizerResult,\n} from \"botbuilder-dialogs\";\nimport { TeamsBotSsoPromptTokenResponse } from \"./teamsBotSsoPromptTokenResponse\";\nimport { config } from \"../core/configurationProvider\";\nimport { OnBehalfOfUserCredential } from \"../credential/onBehalfOfUserCredential\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { ErrorWithCode, ErrorCode, ErrorMessage } from \"../core/errors\";\nimport { internalLogger } from \"../util/logger\";\nimport { validateScopesType, formatString, parseJwt } from \"../util/utils\";\n\nconst invokeResponseType = \"invokeResponse\";\n/**\n * Response body returned for a token exchange invoke activity.\n *\n * @beta\n */\nclass TokenExchangeInvokeResponse {\n /**\n * Response id\n */\n id: string;\n\n /**\n * Detailed error message\n */\n failureDetail: string;\n\n constructor(id: string, failureDetail: string) {\n this.id = id;\n this.failureDetail = failureDetail;\n }\n}\n\n/**\n * Settings used to configure an TeamsBotSsoPrompt instance.\n *\n * @beta\n */\nexport interface TeamsBotSsoPromptSettings {\n /**\n * The array of strings that declare the desired permissions and the resources requested.\n */\n scopes: string[];\n\n /**\n * (Optional) number of milliseconds the prompt will wait for the user to authenticate.\n * Defaults to a value `900,000` (15 minutes.)\n */\n timeout?: number;\n\n /**\n * (Optional) value indicating whether the TeamsBotSsoPrompt should end upon receiving an\n * invalid message. Generally the TeamsBotSsoPrompt will end the auth flow when receives user\n * message not related to the auth flow. Setting the flag to false ignores the user's message instead.\n * Defaults to value `true`\n */\n endOnInvalidMessage?: boolean;\n}\n\n/**\n * Creates a new prompt that leverage Teams Single Sign On (SSO) support for bot to automatically sign in user and\n * help receive oauth token, asks the user to consent if needed.\n *\n * @remarks\n * The prompt will attempt to retrieve the users current token of the desired scopes and store it in\n * the token store.\n *\n * User will be automatically signed in leveraging Teams support of Bot Single Sign On(SSO):\n * https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/auth-aad-sso-bots\n *\n * @example\n * When used with your bots `DialogSet` you can simply add a new instance of the prompt as a named\n * dialog using `DialogSet.add()`. You can then start the prompt from a waterfall step using either\n * `DialogContext.beginDialog()` or `DialogContext.prompt()`. The user will be prompted to sign in as\n * needed and their access token will be passed as an argument to the callers next waterfall step:\n *\n * ```JavaScript\n * const { ConversationState, MemoryStorage } = require('botbuilder');\n * const { DialogSet, WaterfallDialog } = require('botbuilder-dialogs');\n * const { TeamsBotSsoPrompt } = require('@microsoft/teamsfx');\n *\n * const convoState = new ConversationState(new MemoryStorage());\n * const dialogState = convoState.createProperty('dialogState');\n * const dialogs = new DialogSet(dialogState);\n *\n * loadConfiguration();\n * dialogs.add(new TeamsBotSsoPrompt('TeamsBotSsoPrompt', {\n * scopes: [\"User.Read\"],\n * }));\n *\n * dialogs.add(new WaterfallDialog('taskNeedingLogin', [\n * async (step) => {\n * return await step.beginDialog('TeamsBotSsoPrompt');\n * },\n * async (step) => {\n * const token = step.result;\n * if (token) {\n *\n * // ... continue with task needing access token ...\n *\n * } else {\n * await step.context.sendActivity(`Sorry... We couldn't log you in. Try again later.`);\n * return await step.endDialog();\n * }\n * }\n * ]));\n * ```\n *\n * @beta\n */\nexport class TeamsBotSsoPrompt extends Dialog {\n /**\n * Constructor of TeamsBotSsoPrompt.\n *\n * @param dialogId Unique ID of the dialog within its parent `DialogSet` or `ComponentDialog`.\n * @param settings Settings used to configure the prompt.\n *\n * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.\n *\n * @beta\n */\n constructor(dialogId: string, private settings: TeamsBotSsoPromptSettings) {\n super(dialogId);\n validateScopesType(settings.scopes);\n internalLogger.info(\"Create a new Teams Bot SSO Prompt\");\n }\n\n /**\n * Called when a prompt dialog is pushed onto the dialog stack and is being activated.\n * @remarks\n * If the task is successful, the result indicates whether the prompt is still\n * active after the turn has been processed by the prompt.\n *\n * @param dc The DialogContext for the current turn of the conversation.\n *\n * @throws {@link ErrorCode|InvalidParameter} when timeout property in teams bot sso prompt settings is not number or is not positive.\n * @throws {@link ErrorCode|ChannelNotSupported} when bot channel is not MS Teams.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.\n *\n * @returns A `Promise` representing the asynchronous operation.\n *\n * @beta\n */\n public async beginDialog(dc: DialogContext): Promise<DialogTurnResult> {\n internalLogger.info(\"Begin Teams Bot SSO Prompt\");\n this.ensureMsTeamsChannel(dc);\n\n // Initialize prompt state\n const default_timeout = 900000;\n let timeout: number = default_timeout;\n if (this.settings.timeout) {\n if (typeof this.settings.timeout != \"number\") {\n const errorMsg = \"type of timeout property in teamsBotSsoPromptSettings should be number.\";\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InvalidParameter);\n }\n if (this.settings.timeout <= 0) {\n const errorMsg =\n \"value of timeout property in teamsBotSsoPromptSettings should be positive.\";\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InvalidParameter);\n }\n timeout = this.settings.timeout;\n }\n\n if (this.settings.endOnInvalidMessage === undefined) {\n this.settings.endOnInvalidMessage = true;\n }\n const state: teamsBotSsoPromptState = dc.activeDialog?.state as teamsBotSsoPromptState;\n state.state = {};\n state.options = {};\n state.expires = new Date().getTime() + timeout;\n\n // Send OAuth card to get SSO token\n await this.sendOAuthCardAsync(dc.context);\n return Dialog.EndOfTurn;\n }\n\n /**\n * Called when a prompt dialog is the active dialog and the user replied with a new activity.\n *\n * @remarks\n * If the task is successful, the result indicates whether the dialog is still\n * active after the turn has been processed by the dialog.\n * The prompt generally continues to receive the user's replies until it accepts the\n * user's reply as valid input for the prompt.\n *\n * @param dc The DialogContext for the current turn of the conversation.\n *\n * @returns A `Promise` representing the asynchronous operation.\n *\n * @throws {@link ErrorCode|ChannelNotSupported} when bot channel is not MS Teams.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.\n *\n * @beta\n */\n public async continueDialog(dc: DialogContext): Promise<DialogTurnResult> {\n internalLogger.info(\"Continue Teams Bot SSO Prompt\");\n this.ensureMsTeamsChannel(dc);\n\n // Check for timeout\n const state: teamsBotSsoPromptState = dc.activeDialog?.state as teamsBotSsoPromptState;\n const isMessage: boolean = dc.context.activity.type === ActivityTypes.Message;\n const isTimeoutActivityType: boolean =\n isMessage ||\n this.isTeamsVerificationInvoke(dc.context) ||\n this.isTokenExchangeRequestInvoke(dc.context);\n\n // If the incoming Activity is a message, or an Activity Type normally handled by TeamsBotSsoPrompt,\n // check to see if this TeamsBotSsoPrompt Expiration has elapsed, and end the dialog if so.\n const hasTimedOut: boolean = isTimeoutActivityType && new Date().getTime() > state.expires;\n if (hasTimedOut) {\n internalLogger.warn(\"End Teams Bot SSO Prompt due to timeout\");\n return await dc.endDialog(undefined);\n } else {\n if (\n this.isTeamsVerificationInvoke(dc.context) ||\n this.isTokenExchangeRequestInvoke(dc.context)\n ) {\n // Recognize token\n const recognized: PromptRecognizerResult<TeamsBotSsoPromptTokenResponse> =\n await this.recognizeToken(dc);\n\n if (recognized.succeeded) {\n return await dc.endDialog(recognized.value);\n }\n } else if (isMessage && this.settings.endOnInvalidMessage) {\n internalLogger.warn(\"End Teams Bot SSO Prompt due to invalid message\");\n return await dc.endDialog(undefined);\n }\n\n return Dialog.EndOfTurn;\n }\n }\n\n /**\n * Ensure bot is running in MS Teams since TeamsBotSsoPrompt is only supported in MS Teams channel.\n * @param dc dialog context\n * @throws {@link ErrorCode|ChannelNotSupported} if bot channel is not MS Teams\n * @internal\n */\n private ensureMsTeamsChannel(dc: DialogContext) {\n if (dc.context.activity.channelId != Channels.Msteams) {\n const errorMsg = formatString(\n ErrorMessage.OnlyMSTeamsChannelSupported,\n \"Teams Bot SSO Prompt\"\n );\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.ChannelNotSupported);\n }\n }\n\n /**\n * Send OAuthCard that tells Teams to obtain an authentication token for the bot application.\n * For details see https://docs.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/auth-aad-sso-bots.\n *\n * @internal\n */\n private async sendOAuthCardAsync(context: TurnContext): Promise<void> {\n internalLogger.verbose(\"Send OAuth card to get SSO token\");\n\n const account: TeamsChannelAccount = await TeamsInfo.getMember(\n context,\n context.activity.from.id\n );\n internalLogger.verbose(\n \"Get Teams member account user principal name: \" + account.userPrincipalName\n );\n\n const loginHint: string = account.userPrincipalName ? account.userPrincipalName : \"\";\n const signInResource = this.getSignInResource(loginHint);\n const card = CardFactory.oauthCard(\n \"\",\n \"Teams SSO Sign In\",\n \"Sign In\",\n signInResource.signInLink,\n signInResource.tokenExchangeResource\n );\n (card.content as OAuthCard).buttons[0].type = ActionTypes.Signin;\n const msg: Partial<Activity> = MessageFactory.attachment(card);\n\n // Send prompt\n await context.sendActivity(msg);\n }\n\n /**\n * Get sign in resource.\n *\n * @throws {@link ErrorCode|InvalidConfiguration} if client id, tenant id or initiate login endpoint is not found in config.\n *\n * @internal\n */\n private getSignInResource(loginHint: string) {\n internalLogger.verbose(\"Get sign in authentication configuration\");\n const missingConfigurations: string[] = [];\n\n if (!config?.authentication?.initiateLoginEndpoint) {\n missingConfigurations.push(\"initiateLoginEndpoint\");\n }\n\n if (!config?.authentication?.clientId) {\n missingConfigurations.push(\"clientId\");\n }\n\n if (!config?.authentication?.tenantId) {\n missingConfigurations.push(\"tenantId\");\n }\n\n if (!config?.authentication?.applicationIdUri) {\n missingConfigurations.push(\"applicationIdUri\");\n }\n\n if (missingConfigurations.length != 0) {\n const errorMsg = formatString(\n ErrorMessage.InvalidConfiguration,\n missingConfigurations.join(\", \"),\n \"undefined\"\n );\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);\n }\n\n const signInLink = `${config.authentication!.initiateLoginEndpoint}?scope=${encodeURI(\n this.settings.scopes.join(\" \")\n )}&clientId=${config.authentication!.clientId}&tenantId=${\n config.authentication!.tenantId\n }&loginHint=${loginHint}`;\n\n internalLogger.verbose(\"Sign in link: \" + signInLink);\n\n const tokenExchangeResource: TokenExchangeResource = {\n id: uuidv4(),\n uri: config.authentication?.applicationIdUri!.replace(/\\/$/, \"\") + \"/access_as_user\",\n };\n\n internalLogger.verbose(\"Token exchange resource uri: \" + tokenExchangeResource.uri);\n\n return {\n signInLink: signInLink,\n tokenExchangeResource: tokenExchangeResource,\n };\n }\n\n /**\n * @internal\n */\n private async recognizeToken(\n dc: DialogContext\n ): Promise<PromptRecognizerResult<TeamsBotSsoPromptTokenResponse>> {\n const context = dc.context;\n let tokenResponse: TeamsBotSsoPromptTokenResponse | undefined;\n\n if (this.isTokenExchangeRequestInvoke(context)) {\n internalLogger.verbose(\"Receive token exchange request\");\n // Received activity is not a token exchange request\n if (!(context.activity.value && this.isTokenExchangeRequest(context.activity.value))) {\n const warningMsg =\n \"The bot received an InvokeActivity that is missing a TokenExchangeInvokeRequest value. This is required to be sent with the InvokeActivity.\";\n\n internalLogger.warn(warningMsg);\n await context.sendActivity(\n this.getTokenExchangeInvokeResponse(StatusCodes.BAD_REQUEST, warningMsg)\n );\n } else {\n const ssoToken = context.activity.value.token;\n const credential: OnBehalfOfUserCredential = new OnBehalfOfUserCredential(ssoToken);\n let exchangedToken: AccessToken | null;\n try {\n exchangedToken = await credential.getToken(this.settings.scopes);\n\n if (exchangedToken) {\n await context.sendActivity(\n this.getTokenExchangeInvokeResponse(StatusCodes.OK, \"\", context.activity.value.id)\n );\n\n const ssoTokenExpiration = parseJwt(ssoToken).exp;\n tokenResponse = {\n ssoToken: ssoToken,\n ssoTokenExpiration: new Date(ssoTokenExpiration * 1000).toISOString(),\n connectionName: \"\",\n token: exchangedToken.token,\n expiration: exchangedToken.expiresOnTimestamp.toString(),\n };\n }\n } catch (error) {\n const warningMsg = \"The bot is unable to exchange token. Ask for user consent.\";\n internalLogger.info(warningMsg);\n await context.sendActivity(\n this.getTokenExchangeInvokeResponse(\n StatusCodes.PRECONDITION_FAILED,\n warningMsg,\n context.activity.value.id\n )\n );\n }\n }\n } else if (this.isTeamsVerificationInvoke(context)) {\n internalLogger.verbose(\"Receive Teams state verification request\");\n await this.sendOAuthCardAsync(dc.context);\n await context.sendActivity({ type: invokeResponseType, value: { status: StatusCodes.OK } });\n }\n\n return tokenResponse !== undefined\n ? { succeeded: true, value: tokenResponse }\n : { succeeded: false };\n }\n\n /**\n * @internal\n */\n private getTokenExchangeInvokeResponse(\n status: number,\n failureDetail: string,\n id?: string\n ): Activity {\n const invokeResponse: Partial<Activity> = {\n type: invokeResponseType,\n value: { status, body: new TokenExchangeInvokeResponse(id as string, failureDetail) },\n };\n return invokeResponse as Activity;\n }\n\n /**\n * @internal\n */\n private isTeamsVerificationInvoke(context: TurnContext): boolean {\n const activity: Activity = context.activity;\n\n return activity.type === ActivityTypes.Invoke && activity.name === verifyStateOperationName;\n }\n\n /**\n * @internal\n */\n private isTokenExchangeRequestInvoke(context: TurnContext): boolean {\n const activity: Activity = context.activity;\n\n return activity.type === ActivityTypes.Invoke && activity.name === tokenExchangeOperationName;\n }\n\n /**\n * @internal\n */\n private isTokenExchangeRequest(obj: any): obj is TokenExchangeInvokeRequest {\n return obj.hasOwnProperty(\"token\");\n }\n}\n\n/**\n * @internal\n */\ninterface teamsBotSsoPromptState {\n state: any;\n options: PromptOptions;\n expires: number; // Timestamp of when the prompt will timeout.\n}\n"]}
@@ -14,6 +14,10 @@ export var ErrorCode;
14
14
  * Invalid configuration error.
15
15
  */
16
16
  ErrorCode["InvalidConfiguration"] = "InvalidConfiguration";
17
+ /**
18
+ * Invalid certificate error.
19
+ */
20
+ ErrorCode["InvalidCertificate"] = "InvalidCertificate";
17
21
  /**
18
22
  * Internal error.
19
23
  */
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC;;;GAGG;AACH,MAAM,CAAN,IAAY,SAkDX;AAlDD,WAAY,SAAS;IACnB;;OAEG;IACH,kDAAqC,CAAA;IAErC;;OAEG;IACH,0DAA6C,CAAA;IAE7C;;OAEG;IACH,4CAA+B,CAAA;IAE/B;;OAEG;IACH,wDAA2C,CAAA;IAE3C;;OAEG;IACH,wDAA2C,CAAA;IAE3C;;OAEG;IACH,4CAA+B,CAAA;IAE/B;;OAEG;IACH,gDAAmC,CAAA;IAEnC;;OAEG;IACH,oDAAuC,CAAA;IAEvC;;OAEG;IACH,0CAA6B,CAAA;IAE7B;;OAEG;IACH,gDAAmC,CAAA;AACrC,CAAC,EAlDW,SAAS,KAAT,SAAS,QAkDpB;AAED;;GAEG;AACH,MAAM,OAAO,YAAY;;AACvB,6BAA6B;AACb,iCAAoB,GAAG,uCAAuC,CAAC;AAC/D,mCAAsB,GAAG,mCAAmC,CAAC;AAC7D,2CAA8B,GAAG,4CAA4C,CAAC;AAC9E,yCAA4B,GAC1C,2DAA2D,CAAC;AAC9C,iDAAoC,GAClD,8CAA8C,CAAC;AAEjD,4BAA4B;AACZ,uCAA0B,GAAG,kCAAkC,CAAC;AAChE,sCAAyB,GAAG,+BAA+B,CAAC;AAE5E,iBAAiB;AACD,6CAAgC,GAC9C,uDAAuD,CAAC;AAE1D,4BAA4B;AACZ,wCAA2B,GAAG,2CAA2C,CAAC;AAG5F;;;;GAIG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAQtC;;;;;;;OAOG;IACH,YAAY,OAAgB,EAAE,IAAgB;QAC5C,IAAI,CAAC,IAAI,EAAE;YACT,KAAK,CAAC,OAAO,CAAC,CAAC;YACf,OAAO;SACR;QAED,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * Error code to trace the error types.\n * @beta\n */\nexport enum ErrorCode {\n /**\n * Invalid parameter error.\n */\n InvalidParameter = \"InvalidParameter\",\n\n /**\n * Invalid configuration error.\n */\n InvalidConfiguration = \"InvalidConfiguration\",\n\n /**\n * Internal error.\n */\n InternalError = \"InternalError\",\n\n /**\n * Channel is not supported error.\n */\n ChannelNotSupported = \"ChannelNotSupported\",\n\n /**\n * Runtime is not supported error.\n */\n RuntimeNotSupported = \"RuntimeNotSupported\",\n\n /**\n * User failed to finish the AAD consent flow failed.\n */\n ConsentFailed = \"ConsentFailed\",\n\n /**\n * The user or administrator has not consented to use the application error.\n */\n UiRequiredError = \"UiRequiredError\",\n\n /**\n * Token is not within its valid time range error.\n */\n TokenExpiredError = \"TokenExpiredError\",\n\n /**\n * Call service (AAD or simple authentication server) failed.\n */\n ServiceError = \"ServiceError\",\n\n /**\n * Operation failed.\n */\n FailedOperation = \"FailedOperation\",\n}\n\n/**\n * @internal\n */\nexport class ErrorMessage {\n // InvalidConfiguration Error\n static readonly InvalidConfiguration = \"{0} in configuration is invalid: {1}.\";\n static readonly ConfigurationNotExists = \"Configuration does not exist. {0}\";\n static readonly ResourceConfigurationNotExists = \"{0} resource configuration does not exist.\";\n static readonly MissingResourceConfiguration =\n \"Missing resource configuration with type: {0}, name: {1}.\";\n static readonly AuthenticationConfigurationNotExists =\n \"Authentication configuration does not exist.\";\n\n // RuntimeNotSupported Error\n static readonly BrowserRuntimeNotSupported = \"{0} is not supported in browser.\";\n static readonly NodejsRuntimeNotSupported = \"{0} is not supported in Node.\";\n\n // Internal Error\n static readonly FailToAcquireTokenOnBehalfOfUser =\n \"Failed to acquire access token on behalf of user: {0}\";\n\n // ChannelNotSupported Error\n static readonly OnlyMSTeamsChannelSupported = \"{0} is only supported in MS Teams Channel\";\n}\n\n/**\n * Error class with code and message thrown by the SDK.\n *\n * @beta\n */\nexport class ErrorWithCode extends Error {\n /**\n * Error code\n *\n * @readonly\n */\n code: string | undefined;\n\n /**\n * Constructor of ErrorWithCode.\n *\n * @param {string} message - error message.\n * @param {ErrorCode} code - error code.\n *\n * @beta\n */\n constructor(message?: string, code?: ErrorCode) {\n if (!code) {\n super(message);\n return;\n }\n\n super(message);\n Object.setPrototypeOf(this, ErrorWithCode.prototype);\n this.name = `${new.target.name}.${code}`;\n this.code = code;\n }\n}\n"]}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC;;;GAGG;AACH,MAAM,CAAN,IAAY,SAuDX;AAvDD,WAAY,SAAS;IACnB;;OAEG;IACH,kDAAqC,CAAA;IAErC;;OAEG;IACH,0DAA6C,CAAA;IAE7C;;OAEG;IACH,sDAAyC,CAAA;IAEzC;;OAEG;IACH,4CAA+B,CAAA;IAE/B;;OAEG;IACH,wDAA2C,CAAA;IAE3C;;OAEG;IACH,wDAA2C,CAAA;IAE3C;;OAEG;IACH,4CAA+B,CAAA;IAE/B;;OAEG;IACH,gDAAmC,CAAA;IAEnC;;OAEG;IACH,oDAAuC,CAAA;IAEvC;;OAEG;IACH,0CAA6B,CAAA;IAE7B;;OAEG;IACH,gDAAmC,CAAA;AACrC,CAAC,EAvDW,SAAS,KAAT,SAAS,QAuDpB;AAED;;GAEG;AACH,MAAM,OAAO,YAAY;;AACvB,6BAA6B;AACb,iCAAoB,GAAG,uCAAuC,CAAC;AAC/D,mCAAsB,GAAG,mCAAmC,CAAC;AAC7D,2CAA8B,GAAG,4CAA4C,CAAC;AAC9E,yCAA4B,GAC1C,2DAA2D,CAAC;AAC9C,iDAAoC,GAClD,8CAA8C,CAAC;AAEjD,4BAA4B;AACZ,uCAA0B,GAAG,kCAAkC,CAAC;AAChE,sCAAyB,GAAG,+BAA+B,CAAC;AAE5E,iBAAiB;AACD,6CAAgC,GAC9C,uDAAuD,CAAC;AAE1D,4BAA4B;AACZ,wCAA2B,GAAG,2CAA2C,CAAC;AAG5F;;;;GAIG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAQtC;;;;;;;OAOG;IACH,YAAY,OAAgB,EAAE,IAAgB;QAC5C,IAAI,CAAC,IAAI,EAAE;YACT,KAAK,CAAC,OAAO,CAAC,CAAC;YACf,OAAO;SACR;QAED,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * Error code to trace the error types.\n * @beta\n */\nexport enum ErrorCode {\n /**\n * Invalid parameter error.\n */\n InvalidParameter = \"InvalidParameter\",\n\n /**\n * Invalid configuration error.\n */\n InvalidConfiguration = \"InvalidConfiguration\",\n\n /**\n * Invalid certificate error.\n */\n InvalidCertificate = \"InvalidCertificate\",\n\n /**\n * Internal error.\n */\n InternalError = \"InternalError\",\n\n /**\n * Channel is not supported error.\n */\n ChannelNotSupported = \"ChannelNotSupported\",\n\n /**\n * Runtime is not supported error.\n */\n RuntimeNotSupported = \"RuntimeNotSupported\",\n\n /**\n * User failed to finish the AAD consent flow failed.\n */\n ConsentFailed = \"ConsentFailed\",\n\n /**\n * The user or administrator has not consented to use the application error.\n */\n UiRequiredError = \"UiRequiredError\",\n\n /**\n * Token is not within its valid time range error.\n */\n TokenExpiredError = \"TokenExpiredError\",\n\n /**\n * Call service (AAD or simple authentication server) failed.\n */\n ServiceError = \"ServiceError\",\n\n /**\n * Operation failed.\n */\n FailedOperation = \"FailedOperation\",\n}\n\n/**\n * @internal\n */\nexport class ErrorMessage {\n // InvalidConfiguration Error\n static readonly InvalidConfiguration = \"{0} in configuration is invalid: {1}.\";\n static readonly ConfigurationNotExists = \"Configuration does not exist. {0}\";\n static readonly ResourceConfigurationNotExists = \"{0} resource configuration does not exist.\";\n static readonly MissingResourceConfiguration =\n \"Missing resource configuration with type: {0}, name: {1}.\";\n static readonly AuthenticationConfigurationNotExists =\n \"Authentication configuration does not exist.\";\n\n // RuntimeNotSupported Error\n static readonly BrowserRuntimeNotSupported = \"{0} is not supported in browser.\";\n static readonly NodejsRuntimeNotSupported = \"{0} is not supported in Node.\";\n\n // Internal Error\n static readonly FailToAcquireTokenOnBehalfOfUser =\n \"Failed to acquire access token on behalf of user: {0}\";\n\n // ChannelNotSupported Error\n static readonly OnlyMSTeamsChannelSupported = \"{0} is only supported in MS Teams Channel\";\n}\n\n/**\n * Error class with code and message thrown by the SDK.\n *\n * @beta\n */\nexport class ErrorWithCode extends Error {\n /**\n * Error code\n *\n * @readonly\n */\n code: string | undefined;\n\n /**\n * Constructor of ErrorWithCode.\n *\n * @param {string} message - error message.\n * @param {ErrorCode} code - error code.\n *\n * @beta\n */\n constructor(message?: string, code?: ErrorCode) {\n if (!code) {\n super(message);\n return;\n }\n\n super(message);\n Object.setPrototypeOf(this, ErrorWithCode.prototype);\n this.name = `${new.target.name}.${code}`;\n this.code = code;\n }\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT license.
3
3
  import { __awaiter } from "tslib";
4
- import { ClientSecretCredential, AuthenticationError, } from "@azure/identity";
5
4
  import { internalLogger } from "../util/logger";
6
- import { validateScopesType, formatString } from "../util/utils";
5
+ import { validateScopesType, formatString, getScopesArray } from "../util/utils";
7
6
  import { getAuthenticationConfiguration } from "../core/configurationProvider";
8
7
  import { ErrorCode, ErrorMessage, ErrorWithCode } from "../core/errors";
8
+ import { createConfidentialClientApplication } from "../util/utils.node";
9
9
  /**
10
10
  * Represent Microsoft 365 tenant identity, and it is usually used when user is not involved like time-triggered automation job.
11
11
  *
@@ -35,10 +35,7 @@ export class M365TenantCredential {
35
35
  constructor() {
36
36
  internalLogger.info("Create M365 tenant credential");
37
37
  const config = this.loadAndValidateConfig();
38
- const tokenCredentialOptions = {
39
- authorityHost: config.authorityHost,
40
- };
41
- this.clientSecretCredential = new ClientSecretCredential(config.tenantId, config.clientId, config.clientSecret, tokenCredentialOptions);
38
+ this.msalClient = createConfidentialClientApplication(config);
42
39
  }
43
40
  /**
44
41
  * Get access token for credential.
@@ -73,20 +70,21 @@ export class M365TenantCredential {
73
70
  const scopesStr = typeof scopes === "string" ? scopes : scopes.join(" ");
74
71
  internalLogger.info("Get access token with scopes: " + scopesStr);
75
72
  try {
76
- accessToken = yield this.clientSecretCredential.getToken(scopes);
73
+ const scopesArray = getScopesArray(scopes);
74
+ const authenticationResult = yield this.msalClient.acquireTokenByClientCredential({
75
+ scopes: scopesArray,
76
+ });
77
+ if (authenticationResult) {
78
+ accessToken = {
79
+ token: authenticationResult.accessToken,
80
+ expiresOnTimestamp: authenticationResult.expiresOn.getTime(),
81
+ };
82
+ }
77
83
  }
78
84
  catch (err) {
79
- if (err instanceof AuthenticationError) {
80
- const authError = err;
81
- const errorMsg = `Get M365 tenant credential with authentication error: status code ${authError.statusCode}, error messages: ${authError.message}`;
82
- internalLogger.error(errorMsg);
83
- throw new ErrorWithCode(errorMsg, ErrorCode.ServiceError);
84
- }
85
- else {
86
- const errorMsg = "Get M365 tenant credential failed with error: " + err.message;
87
- internalLogger.error(errorMsg);
88
- throw new ErrorWithCode(errorMsg, ErrorCode.InternalError);
89
- }
85
+ const errorMsg = "Get M365 tenant credential failed with error: " + err.message;
86
+ internalLogger.error(errorMsg);
87
+ throw new ErrorWithCode(errorMsg, ErrorCode.ServiceError);
90
88
  }
91
89
  if (!accessToken) {
92
90
  const errorMsg = "Get M365 tenant credential access token failed with empty access token";
@@ -107,15 +105,15 @@ export class M365TenantCredential {
107
105
  internalLogger.error(ErrorMessage.AuthenticationConfigurationNotExists);
108
106
  throw new ErrorWithCode(ErrorMessage.AuthenticationConfigurationNotExists, ErrorCode.InvalidConfiguration);
109
107
  }
110
- if (config.clientId && config.clientSecret && config.tenantId) {
108
+ if (config.clientId && (config.clientSecret || config.certificateContent) && config.tenantId) {
111
109
  return config;
112
110
  }
113
111
  const missingValues = [];
114
112
  if (!config.clientId) {
115
113
  missingValues.push("clientId");
116
114
  }
117
- if (!config.clientSecret) {
118
- missingValues.push("clientSecret");
115
+ if (!config.clientSecret && !config.certificateContent) {
116
+ missingValues.push("clientSecret or certificateContent");
119
117
  }
120
118
  if (!config.tenantId) {
121
119
  missingValues.push("tenantId");
@@ -1 +1 @@
1
- {"version":3,"file":"m365TenantCredential.js","sourceRoot":"","sources":["../../../src/credential/m365TenantCredential.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport {\n AccessToken,\n TokenCredential,\n GetTokenOptions,\n ClientSecretCredential,\n TokenCredentialOptions,\n AuthenticationError,\n} from \"@azure/identity\";\nimport { AuthenticationConfiguration } from \"../models/configuration\";\nimport { internalLogger } from \"../util/logger\";\nimport { validateScopesType, formatString } from \"../util/utils\";\nimport { getAuthenticationConfiguration } from \"../core/configurationProvider\";\nimport { ErrorCode, ErrorMessage, ErrorWithCode } from \"../core/errors\";\n\n/**\n * Represent Microsoft 365 tenant identity, and it is usually used when user is not involved like time-triggered automation job.\n *\n * @example\n * ```typescript\n * loadConfiguration(); // load configuration from environment variables\n * const credential = new M365TenantCredential();\n * ```\n *\n * @remarks\n * Only works in in server side.\n *\n * @beta\n */\nexport class M365TenantCredential implements TokenCredential {\n private readonly clientSecretCredential: ClientSecretCredential;\n\n /**\n * Constructor of M365TenantCredential.\n *\n * @remarks\n * Only works in in server side.\n *\n * @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret or tenant id is not found in config.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.\n *\n * @beta\n */\n constructor() {\n internalLogger.info(\"Create M365 tenant credential\");\n\n const config = this.loadAndValidateConfig();\n\n const tokenCredentialOptions: TokenCredentialOptions = {\n authorityHost: config.authorityHost,\n };\n\n this.clientSecretCredential = new ClientSecretCredential(\n config.tenantId!,\n config.clientId!,\n config.clientSecret!,\n tokenCredentialOptions\n );\n }\n\n /**\n * Get access token for credential.\n *\n * @example\n * ```typescript\n * await credential.getToken([\"User.Read.All\"]) // Get Graph access token for single scope using string array\n * await credential.getToken(\"User.Read.All\") // Get Graph access token for single scope using string\n * await credential.getToken([\"User.Read.All\", \"Calendars.Read\"]) // Get Graph access token for multiple scopes using string array\n * await credential.getToken(\"User.Read.All Calendars.Read\") // Get Graph access token for multiple scopes using space-separated string\n * await credential.getToken(\"https://graph.microsoft.com/User.Read.All\") // Get Graph access token with full resource URI\n * await credential.getToken([\"https://outlook.office.com/Mail.Read\"]) // Get Outlook access token\n * ```\n *\n * @param {string | string[]} scopes - The list of scopes for which the token will have access.\n * @param {GetTokenOptions} options - The options used to configure any requests this TokenCredential implementation might make.\n *\n * @throws {@link ErrorCode|ServiceError} when get access token with authentication error.\n * @throws {@link ErrorCode|InternalError} when get access token with unknown error.\n * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.\n *\n * @returns Access token with expected scopes.\n * Throw error if get access token failed.\n *\n * @beta\n */\n async getToken(\n scopes: string | string[],\n options?: GetTokenOptions\n ): Promise<AccessToken | null> {\n let accessToken;\n validateScopesType(scopes);\n const scopesStr = typeof scopes === \"string\" ? scopes : scopes.join(\" \");\n internalLogger.info(\"Get access token with scopes: \" + scopesStr);\n\n try {\n accessToken = await this.clientSecretCredential.getToken(scopes);\n } catch (err) {\n if (err instanceof AuthenticationError) {\n const authError = err as AuthenticationError;\n const errorMsg = `Get M365 tenant credential with authentication error: status code ${authError.statusCode}, error messages: ${authError.message}`;\n internalLogger.error(errorMsg);\n\n throw new ErrorWithCode(errorMsg, ErrorCode.ServiceError);\n } else {\n const errorMsg = \"Get M365 tenant credential failed with error: \" + err.message;\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InternalError);\n }\n }\n\n if (!accessToken) {\n const errorMsg = \"Get M365 tenant credential access token failed with empty access token\";\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InternalError);\n }\n\n return accessToken;\n }\n\n /**\n * Load and validate authentication configuration\n * @returns Authentication configuration\n */\n private loadAndValidateConfig(): AuthenticationConfiguration {\n internalLogger.verbose(\"Validate authentication configuration\");\n\n const config = getAuthenticationConfiguration();\n\n if (!config) {\n internalLogger.error(ErrorMessage.AuthenticationConfigurationNotExists);\n throw new ErrorWithCode(\n ErrorMessage.AuthenticationConfigurationNotExists,\n ErrorCode.InvalidConfiguration\n );\n }\n\n if (config.clientId && config.clientSecret && config.tenantId) {\n return config;\n }\n\n const missingValues = [];\n\n if (!config.clientId) {\n missingValues.push(\"clientId\");\n }\n\n if (!config.clientSecret) {\n missingValues.push(\"clientSecret\");\n }\n\n if (!config.tenantId) {\n missingValues.push(\"tenantId\");\n }\n\n const errorMsg = formatString(\n ErrorMessage.InvalidConfiguration,\n missingValues.join(\", \"),\n \"undefined\"\n );\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);\n }\n}\n"]}
1
+ {"version":3,"file":"m365TenantCredential.js","sourceRoot":"","sources":["../../../src/credential/m365TenantCredential.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { AccessToken, TokenCredential, GetTokenOptions } from \"@azure/identity\";\nimport { AuthenticationConfiguration } from \"../models/configuration\";\nimport { internalLogger } from \"../util/logger\";\nimport { validateScopesType, formatString, getScopesArray } from \"../util/utils\";\nimport { getAuthenticationConfiguration } from \"../core/configurationProvider\";\nimport { ErrorCode, ErrorMessage, ErrorWithCode } from \"../core/errors\";\nimport { ConfidentialClientApplication } from \"@azure/msal-node\";\nimport { createConfidentialClientApplication } from \"../util/utils.node\";\n\n/**\n * Represent Microsoft 365 tenant identity, and it is usually used when user is not involved like time-triggered automation job.\n *\n * @example\n * ```typescript\n * loadConfiguration(); // load configuration from environment variables\n * const credential = new M365TenantCredential();\n * ```\n *\n * @remarks\n * Only works in in server side.\n *\n * @beta\n */\nexport class M365TenantCredential implements TokenCredential {\n private readonly msalClient: ConfidentialClientApplication;\n\n /**\n * Constructor of M365TenantCredential.\n *\n * @remarks\n * Only works in in server side.\n *\n * @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret or tenant id is not found in config.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.\n *\n * @beta\n */\n constructor() {\n internalLogger.info(\"Create M365 tenant credential\");\n\n const config = this.loadAndValidateConfig();\n\n this.msalClient = createConfidentialClientApplication(config);\n }\n\n /**\n * Get access token for credential.\n *\n * @example\n * ```typescript\n * await credential.getToken([\"User.Read.All\"]) // Get Graph access token for single scope using string array\n * await credential.getToken(\"User.Read.All\") // Get Graph access token for single scope using string\n * await credential.getToken([\"User.Read.All\", \"Calendars.Read\"]) // Get Graph access token for multiple scopes using string array\n * await credential.getToken(\"User.Read.All Calendars.Read\") // Get Graph access token for multiple scopes using space-separated string\n * await credential.getToken(\"https://graph.microsoft.com/User.Read.All\") // Get Graph access token with full resource URI\n * await credential.getToken([\"https://outlook.office.com/Mail.Read\"]) // Get Outlook access token\n * ```\n *\n * @param {string | string[]} scopes - The list of scopes for which the token will have access.\n * @param {GetTokenOptions} options - The options used to configure any requests this TokenCredential implementation might make.\n *\n * @throws {@link ErrorCode|ServiceError} when get access token with authentication error.\n * @throws {@link ErrorCode|InternalError} when get access token with unknown error.\n * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.\n *\n * @returns Access token with expected scopes.\n * Throw error if get access token failed.\n *\n * @beta\n */\n async getToken(\n scopes: string | string[],\n options?: GetTokenOptions\n ): Promise<AccessToken | null> {\n let accessToken;\n validateScopesType(scopes);\n const scopesStr = typeof scopes === \"string\" ? scopes : scopes.join(\" \");\n internalLogger.info(\"Get access token with scopes: \" + scopesStr);\n\n try {\n const scopesArray = getScopesArray(scopes);\n const authenticationResult = await this.msalClient.acquireTokenByClientCredential({\n scopes: scopesArray,\n });\n if (authenticationResult) {\n accessToken = {\n token: authenticationResult.accessToken,\n expiresOnTimestamp: authenticationResult.expiresOn!.getTime(),\n };\n }\n } catch (err: any) {\n const errorMsg = \"Get M365 tenant credential failed with error: \" + err.message;\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.ServiceError);\n }\n\n if (!accessToken) {\n const errorMsg = \"Get M365 tenant credential access token failed with empty access token\";\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InternalError);\n }\n\n return accessToken;\n }\n\n /**\n * Load and validate authentication configuration\n * @returns Authentication configuration\n */\n private loadAndValidateConfig(): AuthenticationConfiguration {\n internalLogger.verbose(\"Validate authentication configuration\");\n\n const config = getAuthenticationConfiguration();\n\n if (!config) {\n internalLogger.error(ErrorMessage.AuthenticationConfigurationNotExists);\n throw new ErrorWithCode(\n ErrorMessage.AuthenticationConfigurationNotExists,\n ErrorCode.InvalidConfiguration\n );\n }\n\n if (config.clientId && (config.clientSecret || config.certificateContent) && config.tenantId) {\n return config;\n }\n\n const missingValues = [];\n\n if (!config.clientId) {\n missingValues.push(\"clientId\");\n }\n\n if (!config.clientSecret && !config.certificateContent) {\n missingValues.push(\"clientSecret or certificateContent\");\n }\n\n if (!config.tenantId) {\n missingValues.push(\"tenantId\");\n }\n\n const errorMsg = formatString(\n ErrorMessage.InvalidConfiguration,\n missingValues.join(\", \"),\n \"undefined\"\n );\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);\n }\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT license.
3
3
  import { __awaiter } from "tslib";
4
- import { ConfidentialClientApplication } from "@azure/msal-node";
5
4
  import { config } from "../core/configurationProvider";
6
5
  import { internalLogger } from "../util/logger";
7
- import { formatString, getUserInfoFromSsoToken, parseJwt, validateScopesType } from "../util/utils";
6
+ import { formatString, getScopesArray, getUserInfoFromSsoToken, parseJwt, validateScopesType, } from "../util/utils";
8
7
  import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors";
8
+ import { createConfidentialClientApplication } from "../util/utils.node";
9
9
  /**
10
10
  * Represent on-behalf-of flow to get user identity, and it is designed to be used in server side.
11
11
  *
@@ -29,7 +29,7 @@ export class OnBehalfOfUserCredential {
29
29
  *
30
30
  * @param {string} ssoToken - User token provided by Teams SSO feature.
31
31
  *
32
- * @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret, authority host or tenant id is not found in config.
32
+ * @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret, certificate content, authority host or tenant id is not found in config.
33
33
  * @throws {@link ErrorCode|InternalError} when SSO token is not valid.
34
34
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
35
35
  *
@@ -45,10 +45,10 @@ export class OnBehalfOfUserCredential {
45
45
  if (!((_b = config === null || config === void 0 ? void 0 : config.authentication) === null || _b === void 0 ? void 0 : _b.authorityHost)) {
46
46
  missingConfigurations.push("authorityHost");
47
47
  }
48
- if (!((_c = config === null || config === void 0 ? void 0 : config.authentication) === null || _c === void 0 ? void 0 : _c.clientSecret)) {
49
- missingConfigurations.push("clientSecret");
48
+ if (!((_c = config === null || config === void 0 ? void 0 : config.authentication) === null || _c === void 0 ? void 0 : _c.clientSecret) && !((_d = config === null || config === void 0 ? void 0 : config.authentication) === null || _d === void 0 ? void 0 : _d.certificateContent)) {
49
+ missingConfigurations.push("clientSecret or certificateContent");
50
50
  }
51
- if (!((_d = config === null || config === void 0 ? void 0 : config.authentication) === null || _d === void 0 ? void 0 : _d.tenantId)) {
51
+ if (!((_e = config === null || config === void 0 ? void 0 : config.authentication) === null || _e === void 0 ? void 0 : _e.tenantId)) {
52
52
  missingConfigurations.push("tenantId");
53
53
  }
54
54
  if (missingConfigurations.length != 0) {
@@ -56,15 +56,7 @@ export class OnBehalfOfUserCredential {
56
56
  internalLogger.error(errorMsg);
57
57
  throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);
58
58
  }
59
- const normalizedAuthorityHost = config.authentication.authorityHost.replace(/\/+$/g, "");
60
- const authority = normalizedAuthorityHost + "/" + ((_e = config.authentication) === null || _e === void 0 ? void 0 : _e.tenantId);
61
- this.msalClient = new ConfidentialClientApplication({
62
- auth: {
63
- clientId: config.authentication.clientId,
64
- authority: authority,
65
- clientSecret: config.authentication.clientSecret,
66
- },
67
- });
59
+ this.msalClient = createConfidentialClientApplication(config.authentication);
68
60
  const decodedSsoToken = parseJwt(ssoToken);
69
61
  this.ssoToken = {
70
62
  token: ssoToken,
@@ -109,8 +101,7 @@ export class OnBehalfOfUserCredential {
109
101
  getToken(scopes, options) {
110
102
  return __awaiter(this, void 0, void 0, function* () {
111
103
  validateScopesType(scopes);
112
- let scopesArray = typeof scopes === "string" ? scopes.split(" ") : scopes;
113
- scopesArray = scopesArray.filter((x) => x !== null && x !== "");
104
+ const scopesArray = getScopesArray(scopes);
114
105
  let result;
115
106
  if (!scopesArray.length) {
116
107
  internalLogger.info("Get SSO token.");
@@ -1 +1 @@
1
- {"version":3,"file":"onBehalfOfUserCredential.js","sourceRoot":"","sources":["../../../src/credential/onBehalfOfUserCredential.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/identity\";\nimport { AuthenticationResult, ConfidentialClientApplication } from \"@azure/msal-node\";\nimport { config } from \"../core/configurationProvider\";\nimport { UserInfo } from \"../models/userinfo\";\nimport { internalLogger } from \"../util/logger\";\nimport { formatString, getUserInfoFromSsoToken, parseJwt, validateScopesType } from \"../util/utils\";\nimport { ErrorWithCode, ErrorCode, ErrorMessage } from \"../core/errors\";\n\n/**\n * Represent on-behalf-of flow to get user identity, and it is designed to be used in server side.\n *\n * @example\n * ```typescript\n * loadConfiguration(); // load configuration from environment variables\n * const credential = new OnBehalfOfUserCredential(ssoToken);\n * ```\n *\n * @remarks\n * Can only be used in server side.\n *\n * @beta\n */\nexport class OnBehalfOfUserCredential implements TokenCredential {\n private msalClient: ConfidentialClientApplication;\n private ssoToken: AccessToken;\n\n /**\n * Constructor of OnBehalfOfUserCredential\n *\n * @remarks\n * Only works in in server side.\n *\n * @param {string} ssoToken - User token provided by Teams SSO feature.\n *\n * @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret, authority host or tenant id is not found in config.\n * @throws {@link ErrorCode|InternalError} when SSO token is not valid.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.\n *\n * @beta\n */\n constructor(ssoToken: string) {\n internalLogger.info(\"Get on behalf of user credential\");\n\n const missingConfigurations: string[] = [];\n if (!config?.authentication?.clientId) {\n missingConfigurations.push(\"clientId\");\n }\n\n if (!config?.authentication?.authorityHost) {\n missingConfigurations.push(\"authorityHost\");\n }\n\n if (!config?.authentication?.clientSecret) {\n missingConfigurations.push(\"clientSecret\");\n }\n\n if (!config?.authentication?.tenantId) {\n missingConfigurations.push(\"tenantId\");\n }\n\n if (missingConfigurations.length != 0) {\n const errorMsg = formatString(\n ErrorMessage.InvalidConfiguration,\n missingConfigurations.join(\", \"),\n \"undefined\"\n );\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);\n }\n\n const normalizedAuthorityHost = config.authentication!.authorityHost!.replace(/\\/+$/g, \"\");\n const authority: string =\n normalizedAuthorityHost + \"/\" + config.authentication?.tenantId;\n this.msalClient = new ConfidentialClientApplication({\n auth: {\n clientId: config.authentication!.clientId!,\n authority: authority,\n clientSecret: config.authentication!.clientSecret!,\n },\n });\n\n const decodedSsoToken = parseJwt(ssoToken);\n this.ssoToken = {\n token: ssoToken,\n expiresOnTimestamp: decodedSsoToken.exp,\n };\n }\n\n /**\n * Get access token from credential.\n *\n * @example\n * ```typescript\n * await credential.getToken([]) // Get SSO token using empty string array\n * await credential.getToken(\"\") // Get SSO token using empty string\n * await credential.getToken([\".default\"]) // Get Graph access token with default scope using string array\n * await credential.getToken(\".default\") // Get Graph access token with default scope using string\n * await credential.getToken([\"User.Read\"]) // Get Graph access token for single scope using string array\n * await credential.getToken(\"User.Read\") // Get Graph access token for single scope using string\n * await credential.getToken([\"User.Read\", \"Application.Read.All\"]) // Get Graph access token for multiple scopes using string array\n * await credential.getToken(\"User.Read Application.Read.All\") // Get Graph access token for multiple scopes using space-separated string\n * await credential.getToken(\"https://graph.microsoft.com/User.Read\") // Get Graph access token with full resource URI\n * await credential.getToken([\"https://outlook.office.com/Mail.Read\"]) // Get Outlook access token\n * ```\n *\n * @param {string | string[]} scopes - The list of scopes for which the token will have access.\n * @param {GetTokenOptions} options - The options used to configure any requests this TokenCredential implementation might make.\n *\n * @throws {@link ErrorCode|InternalError} when failed to acquire access token on behalf of user with unknown error.\n * @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.\n * @throws {@link ErrorCode|UiRequiredError} when need user consent to get access token.\n * @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.\n * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.\n *\n * @returns Access token with expected scopes.\n *\n * @remarks\n * If scopes is empty string or array, it returns SSO token.\n * If scopes is non-empty, it returns access token for target scope.\n *\n * @beta\n */\n async getToken(\n scopes: string | string[],\n options?: GetTokenOptions\n ): Promise<AccessToken | null> {\n validateScopesType(scopes);\n\n let scopesArray: string[] = typeof scopes === \"string\" ? scopes.split(\" \") : scopes;\n scopesArray = scopesArray.filter((x) => x !== null && x !== \"\");\n\n let result: AccessToken | null;\n if (!scopesArray.length) {\n internalLogger.info(\"Get SSO token.\");\n if (Math.floor(Date.now() / 1000) > this.ssoToken.expiresOnTimestamp) {\n const errorMsg = \"Sso token has already expired.\";\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.TokenExpiredError);\n }\n result = this.ssoToken;\n } else {\n internalLogger.info(\"Get access token with scopes: \" + scopesArray.join(\" \"));\n\n let authenticationResult: AuthenticationResult | null;\n try {\n authenticationResult = await this.msalClient.acquireTokenOnBehalfOf({\n oboAssertion: this.ssoToken.token,\n scopes: scopesArray,\n });\n } catch (error) {\n throw this.generateAuthServerError(error);\n }\n\n if (!authenticationResult) {\n const errorMsg = \"Access token is null\";\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(\n formatString(ErrorMessage.FailToAcquireTokenOnBehalfOfUser, errorMsg),\n ErrorCode.InternalError\n );\n }\n\n result = {\n token: authenticationResult.accessToken,\n expiresOnTimestamp: authenticationResult.expiresOn!.getTime(),\n };\n }\n\n return result;\n }\n\n /**\n * Get basic user info from SSO token.\n *\n * @example\n * ```typescript\n * const currentUser = getUserInfo();\n * ```\n *\n * @throws {@link ErrorCode|InternalError} when SSO token is not valid.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.\n *\n * @returns Basic user info with user displayName, objectId and preferredUserName.\n *\n * @beta\n */\n public getUserInfo(): UserInfo {\n internalLogger.info(\"Get basic user info from SSO token\");\n return getUserInfoFromSsoToken(this.ssoToken.token);\n }\n\n private generateAuthServerError(err: any): Error {\n const errorMessage = err.errorMessage;\n if (err.name === \"InteractionRequiredAuthError\") {\n const fullErrorMsg =\n \"Failed to get access token from AAD server, interaction required: \" + errorMessage;\n internalLogger.warn(fullErrorMsg);\n return new ErrorWithCode(fullErrorMsg, ErrorCode.UiRequiredError);\n } else if (errorMessage && errorMessage.indexOf(\"AADSTS500133\") >= 0) {\n const fullErrorMsg =\n \"Failed to get access token from AAD server, sso token expired: \" + errorMessage;\n internalLogger.error(fullErrorMsg);\n return new ErrorWithCode(fullErrorMsg, ErrorCode.TokenExpiredError);\n } else {\n const fullErrorMsg = formatString(\n ErrorMessage.FailToAcquireTokenOnBehalfOfUser,\n errorMessage\n );\n internalLogger.error(fullErrorMsg);\n return new ErrorWithCode(fullErrorMsg, ErrorCode.ServiceError);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"onBehalfOfUserCredential.js","sourceRoot":"","sources":["../../../src/credential/onBehalfOfUserCredential.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/identity\";\nimport { AuthenticationResult, ConfidentialClientApplication } from \"@azure/msal-node\";\nimport { config } from \"../core/configurationProvider\";\nimport { UserInfo } from \"../models/userinfo\";\nimport { internalLogger } from \"../util/logger\";\nimport {\n formatString,\n getScopesArray,\n getUserInfoFromSsoToken,\n parseJwt,\n validateScopesType,\n} from \"../util/utils\";\nimport { ErrorWithCode, ErrorCode, ErrorMessage } from \"../core/errors\";\nimport { createConfidentialClientApplication } from \"../util/utils.node\";\n\n/**\n * Represent on-behalf-of flow to get user identity, and it is designed to be used in server side.\n *\n * @example\n * ```typescript\n * loadConfiguration(); // load configuration from environment variables\n * const credential = new OnBehalfOfUserCredential(ssoToken);\n * ```\n *\n * @remarks\n * Can only be used in server side.\n *\n * @beta\n */\nexport class OnBehalfOfUserCredential implements TokenCredential {\n private msalClient: ConfidentialClientApplication;\n private ssoToken: AccessToken;\n\n /**\n * Constructor of OnBehalfOfUserCredential\n *\n * @remarks\n * Only works in in server side.\n *\n * @param {string} ssoToken - User token provided by Teams SSO feature.\n *\n * @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret, certificate content, authority host or tenant id is not found in config.\n * @throws {@link ErrorCode|InternalError} when SSO token is not valid.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.\n *\n * @beta\n */\n constructor(ssoToken: string) {\n internalLogger.info(\"Get on behalf of user credential\");\n\n const missingConfigurations: string[] = [];\n if (!config?.authentication?.clientId) {\n missingConfigurations.push(\"clientId\");\n }\n\n if (!config?.authentication?.authorityHost) {\n missingConfigurations.push(\"authorityHost\");\n }\n\n if (!config?.authentication?.clientSecret && !config?.authentication?.certificateContent) {\n missingConfigurations.push(\"clientSecret or certificateContent\");\n }\n\n if (!config?.authentication?.tenantId) {\n missingConfigurations.push(\"tenantId\");\n }\n\n if (missingConfigurations.length != 0) {\n const errorMsg = formatString(\n ErrorMessage.InvalidConfiguration,\n missingConfigurations.join(\", \"),\n \"undefined\"\n );\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);\n }\n\n this.msalClient = createConfidentialClientApplication(config.authentication!);\n\n const decodedSsoToken = parseJwt(ssoToken);\n this.ssoToken = {\n token: ssoToken,\n expiresOnTimestamp: decodedSsoToken.exp,\n };\n }\n\n /**\n * Get access token from credential.\n *\n * @example\n * ```typescript\n * await credential.getToken([]) // Get SSO token using empty string array\n * await credential.getToken(\"\") // Get SSO token using empty string\n * await credential.getToken([\".default\"]) // Get Graph access token with default scope using string array\n * await credential.getToken(\".default\") // Get Graph access token with default scope using string\n * await credential.getToken([\"User.Read\"]) // Get Graph access token for single scope using string array\n * await credential.getToken(\"User.Read\") // Get Graph access token for single scope using string\n * await credential.getToken([\"User.Read\", \"Application.Read.All\"]) // Get Graph access token for multiple scopes using string array\n * await credential.getToken(\"User.Read Application.Read.All\") // Get Graph access token for multiple scopes using space-separated string\n * await credential.getToken(\"https://graph.microsoft.com/User.Read\") // Get Graph access token with full resource URI\n * await credential.getToken([\"https://outlook.office.com/Mail.Read\"]) // Get Outlook access token\n * ```\n *\n * @param {string | string[]} scopes - The list of scopes for which the token will have access.\n * @param {GetTokenOptions} options - The options used to configure any requests this TokenCredential implementation might make.\n *\n * @throws {@link ErrorCode|InternalError} when failed to acquire access token on behalf of user with unknown error.\n * @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.\n * @throws {@link ErrorCode|UiRequiredError} when need user consent to get access token.\n * @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.\n * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.\n *\n * @returns Access token with expected scopes.\n *\n * @remarks\n * If scopes is empty string or array, it returns SSO token.\n * If scopes is non-empty, it returns access token for target scope.\n *\n * @beta\n */\n async getToken(\n scopes: string | string[],\n options?: GetTokenOptions\n ): Promise<AccessToken | null> {\n validateScopesType(scopes);\n\n const scopesArray = getScopesArray(scopes);\n\n let result: AccessToken | null;\n if (!scopesArray.length) {\n internalLogger.info(\"Get SSO token.\");\n if (Math.floor(Date.now() / 1000) > this.ssoToken.expiresOnTimestamp) {\n const errorMsg = \"Sso token has already expired.\";\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.TokenExpiredError);\n }\n result = this.ssoToken;\n } else {\n internalLogger.info(\"Get access token with scopes: \" + scopesArray.join(\" \"));\n\n let authenticationResult: AuthenticationResult | null;\n try {\n authenticationResult = await this.msalClient.acquireTokenOnBehalfOf({\n oboAssertion: this.ssoToken.token,\n scopes: scopesArray,\n });\n } catch (error) {\n throw this.generateAuthServerError(error);\n }\n\n if (!authenticationResult) {\n const errorMsg = \"Access token is null\";\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(\n formatString(ErrorMessage.FailToAcquireTokenOnBehalfOfUser, errorMsg),\n ErrorCode.InternalError\n );\n }\n\n result = {\n token: authenticationResult.accessToken,\n expiresOnTimestamp: authenticationResult.expiresOn!.getTime(),\n };\n }\n\n return result;\n }\n\n /**\n * Get basic user info from SSO token.\n *\n * @example\n * ```typescript\n * const currentUser = getUserInfo();\n * ```\n *\n * @throws {@link ErrorCode|InternalError} when SSO token is not valid.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.\n *\n * @returns Basic user info with user displayName, objectId and preferredUserName.\n *\n * @beta\n */\n public getUserInfo(): UserInfo {\n internalLogger.info(\"Get basic user info from SSO token\");\n return getUserInfoFromSsoToken(this.ssoToken.token);\n }\n\n private generateAuthServerError(err: any): Error {\n const errorMessage = err.errorMessage;\n if (err.name === \"InteractionRequiredAuthError\") {\n const fullErrorMsg =\n \"Failed to get access token from AAD server, interaction required: \" + errorMessage;\n internalLogger.warn(fullErrorMsg);\n return new ErrorWithCode(fullErrorMsg, ErrorCode.UiRequiredError);\n } else if (errorMessage && errorMessage.indexOf(\"AADSTS500133\") >= 0) {\n const fullErrorMsg =\n \"Failed to get access token from AAD server, sso token expired: \" + errorMessage;\n internalLogger.error(fullErrorMsg);\n return new ErrorWithCode(fullErrorMsg, ErrorCode.TokenExpiredError);\n } else {\n const fullErrorMsg = formatString(\n ErrorMessage.FailToAcquireTokenOnBehalfOfUser,\n errorMessage\n );\n internalLogger.error(fullErrorMsg);\n return new ErrorWithCode(fullErrorMsg, ErrorCode.ServiceError);\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"teamsUserCredential.browser.js","sourceRoot":"","sources":["../../../src/credential/teamsUserCredential.browser.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { AccessToken, TokenCredential, GetTokenOptions } from \"@azure/identity\";\nimport { UserInfo } from \"../models/userinfo\";\nimport { ErrorCode, ErrorMessage, ErrorWithCode } from \"../core/errors\";\nimport { Cache } from \"../core/cache.browser\";\nimport * as microsoftTeams from \"@microsoft/teams-js\";\nimport { getAuthenticationConfiguration } from \"../core/configurationProvider\";\nimport { AuthenticationConfiguration } from \"../models/configuration\";\nimport { AuthCodeResult } from \"../models/authCodeResult\";\nimport axios, { AxiosInstance } from \"axios\";\nimport { GrantType } from \"../models/grantType\";\nimport { AccessTokenResult } from \"../models/accessTokenResult\";\nimport { validateScopesType, getUserInfoFromSsoToken, parseJwt } from \"../util/utils\";\nimport { formatString } from \"../util/utils\";\nimport { internalLogger } from \"../util/logger\";\n\nconst accessTokenCacheKeyPrefix = \"accessToken\";\nconst separator = \"-\";\nconst tokenRefreshTimeSpanInMillisecond = 5 * 60 * 1000;\nconst initializeTeamsSdkTimeoutInMillisecond = 5000;\nconst loginPageWidth = 600;\nconst loginPageHeight = 535;\nconst maxRetryCount = 3;\nconst retryTimeSpanInMillisecond = 3000;\n\n/**\n * Represent Teams current user's identity, and it is used within Teams tab application.\n *\n * @remarks\n * Can only be used within Teams.\n *\n * @beta\n */\nexport class TeamsUserCredential implements TokenCredential {\n private readonly config: AuthenticationConfiguration;\n private ssoToken: AccessToken | null;\n\n /**\n * Constructor of TeamsUserCredential.\n * Developer need to call loadConfiguration(config) before using this class.\n * \n * @example\n * ```typescript\n * const config = {\n * authentication: {\n * runtimeConnectorEndpoint: \"https://xxx.xxx.com\",\n * initiateLoginEndpoint: \"https://localhost:3000/auth-start.html\",\n * clientId: \"xxx\"\n * }\n * }\n loadConfiguration(config); // No default config from environment variables, developers must provide the config object.\n const credential = new TeamsUserCredential([\"https://graph.microsoft.com/User.Read\"]);\n * ```\n *\n * @throws {@link ErrorCode|InvalidConfiguration} when client id, initiate login endpoint or simple auth endpoint is not found in config.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.\n * \n * @beta\n */\n constructor() {\n internalLogger.info(\"Create teams user credential\");\n this.config = this.loadAndValidateConfig();\n this.ssoToken = null;\n }\n\n /**\n * Popup login page to get user's access token with specific scopes.\n *\n * @remarks\n * Only works in Teams client APP. User will be redirected to the authorization page to login and consent.\n *\n * @example\n * ```typescript\n * await credential.login([\"https://graph.microsoft.com/User.Read\"]); // single scope using string array\n * await credential.login(\"https://graph.microsoft.com/User.Read\"); // single scopes using string\n * await credential.login([\"https://graph.microsoft.com/User.Read\", \"Calendars.Read\"]); // multiple scopes using string array\n * await credential.login(\"https://graph.microsoft.com/User.Read Calendars.Read\"); // multiple scopes using string\n * ```\n * @param scopes - The list of scopes for which the token will have access, before that, we will request user to consent.\n *\n * @throws {@link ErrorCode|InternalError} when failed to login with unknown error.\n * @throws {@link ErrorCode|ServiceError} when simple auth server failed to exchange access token.\n * @throws {@link ErrorCode|ConsentFailed} when user canceled or failed to consent.\n * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.\n *\n * @beta\n */\n public async login(scopes: string | string[]): Promise<void> {\n validateScopesType(scopes);\n const scopesStr = typeof scopes === \"string\" ? scopes : scopes.join(\" \");\n\n internalLogger.info(`Popup login page to get user's access token with scopes: ${scopesStr}`);\n\n return new Promise<void>((resolve, reject) => {\n microsoftTeams.initialize(() => {\n microsoftTeams.authentication.authenticate({\n url: `${this.config.initiateLoginEndpoint}?clientId=${\n this.config.clientId\n }&scope=${encodeURI(scopesStr)}`,\n width: loginPageWidth,\n height: loginPageHeight,\n successCallback: async (result?: string) => {\n if (!result) {\n const errorMsg = \"Get empty authentication result from Teams\";\n\n internalLogger.error(errorMsg);\n reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));\n return;\n }\n\n const authCodeResult: AuthCodeResult = JSON.parse(result);\n try {\n await this.exchangeAccessTokenFromSimpleAuthServer(scopesStr, authCodeResult);\n resolve();\n } catch (err) {\n reject(this.generateAuthServerError(err));\n }\n },\n failureCallback: (reason?: string) => {\n const errorMsg = `Consent failed for the scope ${scopesStr} with error: ${reason}`;\n internalLogger.error(errorMsg);\n reject(new ErrorWithCode(errorMsg, ErrorCode.ConsentFailed));\n },\n });\n });\n });\n }\n\n /**\n * Get access token from credential.\n *\n * @example\n * ```typescript\n * await credential.getToken([]) // Get SSO token using empty string array\n * await credential.getToken(\"\") // Get SSO token using empty string\n * await credential.getToken([\".default\"]) // Get Graph access token with default scope using string array\n * await credential.getToken(\".default\") // Get Graph access token with default scope using string\n * await credential.getToken([\"User.Read\"]) // Get Graph access token for single scope using string array\n * await credential.getToken(\"User.Read\") // Get Graph access token for single scope using string\n * await credential.getToken([\"User.Read\", \"Application.Read.All\"]) // Get Graph access token for multiple scopes using string array\n * await credential.getToken(\"User.Read Application.Read.All\") // Get Graph access token for multiple scopes using space-separated string\n * await credential.getToken(\"https://graph.microsoft.com/User.Read\") // Get Graph access token with full resource URI\n * await credential.getToken([\"https://outlook.office.com/Mail.Read\"]) // Get Outlook access token\n * ```\n *\n * @param {string | string[]} scopes - The list of scopes for which the token will have access.\n * @param {GetTokenOptions} options - The options used to configure any requests this TokenCredential implementation might make.\n *\n * @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.\n * @throws {@link ErrorCode|UiRequiredError} when need user consent to get access token.\n * @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.\n * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.\n *\n * @returns User access token of defined scopes.\n * If scopes is empty string or array, it returns SSO token.\n * If scopes is non-empty, it returns access token for target scope.\n * Throw error if get access token failed.\n *\n * @beta\n */\n async getToken(\n scopes: string | string[],\n options?: GetTokenOptions\n ): Promise<AccessToken | null> {\n validateScopesType(scopes);\n const ssoToken = await this.getSSOToken();\n\n const scopeStr = typeof scopes === \"string\" ? scopes : scopes.join(\" \");\n if (scopeStr === \"\") {\n internalLogger.info(\"Get SSO token\");\n\n return ssoToken;\n } else {\n internalLogger.info(\"Get access token with scopes: \" + scopeStr);\n const cachedKey = await this.getAccessTokenCacheKey(scopeStr);\n const cachedToken = this.getTokenCache(cachedKey);\n\n if (cachedToken) {\n if (!this.isAccessTokenNearExpired(cachedToken)) {\n internalLogger.verbose(\"Get access token from cache\");\n return cachedToken;\n } else {\n internalLogger.verbose(\"Cached access token is expired\");\n }\n } else {\n internalLogger.verbose(\"No cached access token\");\n }\n\n const accessToken = await this.getAndCacheAccessTokenFromSimpleAuthServer(scopeStr);\n return accessToken;\n }\n }\n\n /**\n * Get basic user info from SSO token\n *\n * @example\n * ```typescript\n * const currentUser = await credential.getUserInfo();\n * ```\n *\n * @throws {@link ErrorCode|InternalError} when SSO token from Teams client is not valid.\n * @throws {@link ErrorCode|InvalidParameter} when SSO token from Teams client is empty.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.\n *\n * @returns Basic user info with user displayName, objectId and preferredUserName.\n *\n * @beta\n */\n public async getUserInfo(): Promise<UserInfo> {\n internalLogger.info(\"Get basic user info from SSO token\");\n const ssoToken = await this.getSSOToken();\n return getUserInfoFromSsoToken(ssoToken.token);\n }\n\n private async exchangeAccessTokenFromSimpleAuthServer(\n scopesStr: string,\n authCodeResult: AuthCodeResult\n ): Promise<void> {\n const axiosInstance: AxiosInstance = await this.getAxiosInstance();\n\n let retryCount = 0;\n while (true) {\n try {\n const response = await axiosInstance.post(\"/auth/token\", {\n scope: scopesStr,\n code: authCodeResult.code,\n code_verifier: authCodeResult.codeVerifier,\n redirect_uri: authCodeResult.redirectUri,\n grant_type: GrantType.authCode,\n });\n\n const tokenResult: AccessTokenResult = response.data;\n const key = await this.getAccessTokenCacheKey(scopesStr);\n this.setTokenCache(key, {\n token: tokenResult.access_token,\n expiresOnTimestamp: tokenResult.expires_on,\n });\n return;\n } catch (err) {\n if (err.response?.data?.type && err.response.data.type === \"AadUiRequiredException\") {\n internalLogger.warn(\"Exchange access token failed, retry...\");\n if (retryCount < maxRetryCount) {\n await this.sleep(retryTimeSpanInMillisecond);\n retryCount++;\n continue;\n }\n }\n throw err;\n }\n }\n }\n\n /**\n * Get access token cache from authentication server\n * @returns Access token\n */\n private async getAndCacheAccessTokenFromSimpleAuthServer(\n scopesStr: string\n ): Promise<AccessToken> {\n try {\n internalLogger.verbose(\n \"Get access token from authentication server with scopes: \" + scopesStr\n );\n const axiosInstance: AxiosInstance = await this.getAxiosInstance();\n const response = await axiosInstance.post(\"/auth/token\", {\n scope: scopesStr,\n grant_type: GrantType.ssoToken,\n });\n\n const accessTokenResult: AccessTokenResult = response.data;\n const accessToken: AccessToken = {\n token: accessTokenResult.access_token,\n expiresOnTimestamp: accessTokenResult.expires_on,\n };\n const cacheKey = await this.getAccessTokenCacheKey(scopesStr);\n this.setTokenCache(cacheKey, accessToken);\n return accessToken;\n } catch (err) {\n throw this.generateAuthServerError(err);\n }\n }\n\n /**\n * Get SSO token using teams SDK\n * It will try to get SSO token from memory first, if SSO token doesn't exist or about to expired, then it will using teams SDK to get SSO token\n * @returns SSO token\n */\n private getSSOToken(): Promise<AccessToken> {\n return new Promise<AccessToken>((resolve, reject) => {\n if (this.ssoToken) {\n if (this.ssoToken.expiresOnTimestamp - Date.now() > tokenRefreshTimeSpanInMillisecond) {\n internalLogger.verbose(\"Get SSO token from memory cache\");\n resolve(this.ssoToken);\n return;\n }\n }\n\n let initialized = false;\n microsoftTeams.initialize(() => {\n initialized = true;\n microsoftTeams.authentication.getAuthToken({\n successCallback: (token: string) => {\n if (!token) {\n const errorMsg = \"Get empty SSO token from Teams\";\n internalLogger.error(errorMsg);\n reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));\n return;\n }\n\n const tokenObject = parseJwt(token);\n if (tokenObject.ver !== \"1.0\" && tokenObject.ver !== \"2.0\") {\n const errorMsg = \"SSO token is not valid with an unknown version: \" + tokenObject.ver;\n internalLogger.error(errorMsg);\n reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));\n return;\n }\n\n const ssoToken: AccessToken = {\n token,\n expiresOnTimestamp: tokenObject.exp * 1000,\n };\n\n this.ssoToken = ssoToken;\n resolve(ssoToken);\n },\n failureCallback: (errMessage: string) => {\n const errorMsg = \"Get SSO token failed with error: \" + errMessage;\n internalLogger.error(errorMsg);\n reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));\n },\n resources: [],\n });\n });\n\n // If the code not running in Teams, the initialize callback function would never trigger\n setTimeout(() => {\n if (!initialized) {\n const errorMsg =\n \"Initialize teams sdk timeout, maybe the code is not running inside Teams\";\n internalLogger.error(errorMsg);\n reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));\n }\n }, initializeTeamsSdkTimeoutInMillisecond);\n });\n }\n\n /**\n * Load and validate authentication configuration\n * @returns Authentication configuration\n */\n private loadAndValidateConfig(): AuthenticationConfiguration {\n internalLogger.verbose(\"Validate authentication configuration\");\n const config = getAuthenticationConfiguration();\n\n if (!config) {\n internalLogger.error(ErrorMessage.AuthenticationConfigurationNotExists);\n\n throw new ErrorWithCode(\n ErrorMessage.AuthenticationConfigurationNotExists,\n ErrorCode.InvalidConfiguration\n );\n }\n\n if (config.initiateLoginEndpoint && config.simpleAuthEndpoint && config.clientId) {\n return config;\n }\n\n const missingValues = [];\n if (!config.initiateLoginEndpoint) {\n missingValues.push(\"initiateLoginEndpoint\");\n }\n\n if (!config.simpleAuthEndpoint) {\n missingValues.push(\"simpleAuthEndpoint\");\n }\n\n if (!config.clientId) {\n missingValues.push(\"clientId\");\n }\n\n const errorMsg = formatString(\n ErrorMessage.InvalidConfiguration,\n missingValues.join(\", \"),\n \"undefined\"\n );\n\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);\n }\n\n /**\n * Get axios instance with sso token bearer header\n * @returns AxiosInstance\n */\n private async getAxiosInstance(): Promise<AxiosInstance> {\n const ssoToken = await this.getSSOToken();\n const axiosInstance: AxiosInstance = axios.create({\n baseURL: this.config.simpleAuthEndpoint,\n });\n\n axiosInstance.interceptors.request.use((config) => {\n config.headers.Authorization = \"Bearer \" + ssoToken.token;\n return config;\n });\n\n return axiosInstance;\n }\n\n /**\n * Set access token to cache\n * @param key\n * @param token\n */\n private setTokenCache(key: string, token: AccessToken): void {\n Cache.set(key, JSON.stringify(token));\n }\n\n /**\n * Get access token from cache.\n * If there is no cache or cannot be parsed, then it will return null\n * @param key\n * @returns Access token or null\n */\n private getTokenCache(key: string): AccessToken | null {\n const value = Cache.get(key);\n if (value === null) {\n return null;\n }\n\n const accessToken: AccessToken | null = this.validateAndParseJson(value);\n return accessToken;\n }\n\n /**\n * Parses passed value as JSON access token, if value is not a valid json string JSON.parse() will throw an error.\n * @param jsonValue\n */\n private validateAndParseJson(jsonValue: string): AccessToken | null {\n try {\n const parsedJson = JSON.parse(jsonValue);\n /**\n * There are edge cases in which JSON.parse will successfully parse a non-valid JSON object\n * (e.g. JSON.parse will parse an escaped string into an unescaped string), so adding a type check\n * of the parsed value is necessary in order to be certain that the string represents a valid JSON object.\n *\n */\n return parsedJson && typeof parsedJson === \"object\" ? parsedJson : null;\n } catch (error) {\n return null;\n }\n }\n\n /**\n * Generate cache key\n * @param scopesStr\n * @returns Access token cache key, a key example: accessToken-userId-clientId-tenantId-scopes\n */\n private async getAccessTokenCacheKey(scopesStr: string): Promise<string> {\n const ssoToken = await this.getSSOToken();\n const ssoTokenObj = parseJwt(ssoToken.token);\n\n const clientId = this.config.clientId;\n const userObjectId = ssoTokenObj.oid;\n const tenantId = ssoTokenObj.tid;\n\n const key = [accessTokenCacheKeyPrefix, userObjectId, clientId, tenantId, scopesStr]\n .join(separator)\n .replace(/\" \"/g, \"_\");\n return key;\n }\n\n /**\n * Check whether the token is about to expire (within 5 minutes)\n * @returns Boolean value indicate whether the token is about to expire\n */\n private isAccessTokenNearExpired(token: AccessToken): boolean {\n const expireDate = new Date(token.expiresOnTimestamp);\n if (expireDate.getTime() - Date.now() > tokenRefreshTimeSpanInMillisecond) {\n return false;\n }\n return true;\n }\n\n private generateAuthServerError(err: any): Error {\n let errorMessage = err.message;\n if (err.response?.data?.type) {\n errorMessage = err.response.data.detail;\n if (err.response.data.type === \"AadUiRequiredException\") {\n const fullErrorMsg =\n \"Failed to get access token from authentication server, please login first: \" +\n errorMessage;\n internalLogger.warn(fullErrorMsg);\n return new ErrorWithCode(fullErrorMsg, ErrorCode.UiRequiredError);\n } else {\n const fullErrorMsg =\n \"Failed to get access token from authentication server: \" + errorMessage;\n internalLogger.error(fullErrorMsg);\n return new ErrorWithCode(fullErrorMsg, ErrorCode.ServiceError);\n }\n }\n\n const fullErrorMsg = \"Failed to get access token with error: \" + errorMessage;\n return new ErrorWithCode(fullErrorMsg, ErrorCode.InternalError);\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"]}
1
+ {"version":3,"file":"teamsUserCredential.browser.js","sourceRoot":"","sources":["../../../src/credential/teamsUserCredential.browser.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { AccessToken, TokenCredential, GetTokenOptions } from \"@azure/identity\";\nimport { UserInfo } from \"../models/userinfo\";\nimport { ErrorCode, ErrorMessage, ErrorWithCode } from \"../core/errors\";\nimport { Cache } from \"../core/cache.browser\";\nimport * as microsoftTeams from \"@microsoft/teams-js\";\nimport { getAuthenticationConfiguration } from \"../core/configurationProvider\";\nimport { AuthenticationConfiguration } from \"../models/configuration\";\nimport { AuthCodeResult } from \"../models/authCodeResult\";\nimport axios, { AxiosInstance } from \"axios\";\nimport { GrantType } from \"../models/grantType\";\nimport { AccessTokenResult } from \"../models/accessTokenResult\";\nimport { validateScopesType, getUserInfoFromSsoToken, parseJwt } from \"../util/utils\";\nimport { formatString } from \"../util/utils\";\nimport { internalLogger } from \"../util/logger\";\n\nconst accessTokenCacheKeyPrefix = \"accessToken\";\nconst separator = \"-\";\nconst tokenRefreshTimeSpanInMillisecond = 5 * 60 * 1000;\nconst initializeTeamsSdkTimeoutInMillisecond = 5000;\nconst loginPageWidth = 600;\nconst loginPageHeight = 535;\nconst maxRetryCount = 3;\nconst retryTimeSpanInMillisecond = 3000;\n\n/**\n * Represent Teams current user's identity, and it is used within Teams tab application.\n *\n * @remarks\n * Can only be used within Teams.\n *\n * @beta\n */\nexport class TeamsUserCredential implements TokenCredential {\n private readonly config: AuthenticationConfiguration;\n private ssoToken: AccessToken | null;\n\n /**\n * Constructor of TeamsUserCredential.\n * Developer need to call loadConfiguration(config) before using this class.\n * \n * @example\n * ```typescript\n * const config = {\n * authentication: {\n * runtimeConnectorEndpoint: \"https://xxx.xxx.com\",\n * initiateLoginEndpoint: \"https://localhost:3000/auth-start.html\",\n * clientId: \"xxx\"\n * }\n * }\n loadConfiguration(config); // No default config from environment variables, developers must provide the config object.\n const credential = new TeamsUserCredential([\"https://graph.microsoft.com/User.Read\"]);\n * ```\n *\n * @throws {@link ErrorCode|InvalidConfiguration} when client id, initiate login endpoint or simple auth endpoint is not found in config.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.\n * \n * @beta\n */\n constructor() {\n internalLogger.info(\"Create teams user credential\");\n this.config = this.loadAndValidateConfig();\n this.ssoToken = null;\n }\n\n /**\n * Popup login page to get user's access token with specific scopes.\n *\n * @remarks\n * Only works in Teams client APP. User will be redirected to the authorization page to login and consent.\n *\n * @example\n * ```typescript\n * await credential.login([\"https://graph.microsoft.com/User.Read\"]); // single scope using string array\n * await credential.login(\"https://graph.microsoft.com/User.Read\"); // single scopes using string\n * await credential.login([\"https://graph.microsoft.com/User.Read\", \"Calendars.Read\"]); // multiple scopes using string array\n * await credential.login(\"https://graph.microsoft.com/User.Read Calendars.Read\"); // multiple scopes using string\n * ```\n * @param scopes - The list of scopes for which the token will have access, before that, we will request user to consent.\n *\n * @throws {@link ErrorCode|InternalError} when failed to login with unknown error.\n * @throws {@link ErrorCode|ServiceError} when simple auth server failed to exchange access token.\n * @throws {@link ErrorCode|ConsentFailed} when user canceled or failed to consent.\n * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.\n *\n * @beta\n */\n public async login(scopes: string | string[]): Promise<void> {\n validateScopesType(scopes);\n const scopesStr = typeof scopes === \"string\" ? scopes : scopes.join(\" \");\n\n internalLogger.info(`Popup login page to get user's access token with scopes: ${scopesStr}`);\n\n return new Promise<void>((resolve, reject) => {\n microsoftTeams.initialize(() => {\n microsoftTeams.authentication.authenticate({\n url: `${this.config.initiateLoginEndpoint}?clientId=${\n this.config.clientId\n }&scope=${encodeURI(scopesStr)}`,\n width: loginPageWidth,\n height: loginPageHeight,\n successCallback: async (result?: string) => {\n if (!result) {\n const errorMsg = \"Get empty authentication result from Teams\";\n\n internalLogger.error(errorMsg);\n reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));\n return;\n }\n\n const authCodeResult: AuthCodeResult = JSON.parse(result);\n try {\n await this.exchangeAccessTokenFromSimpleAuthServer(scopesStr, authCodeResult);\n resolve();\n } catch (err) {\n reject(this.generateAuthServerError(err));\n }\n },\n failureCallback: (reason?: string) => {\n const errorMsg = `Consent failed for the scope ${scopesStr} with error: ${reason}`;\n internalLogger.error(errorMsg);\n reject(new ErrorWithCode(errorMsg, ErrorCode.ConsentFailed));\n },\n });\n });\n });\n }\n\n /**\n * Get access token from credential.\n *\n * @example\n * ```typescript\n * await credential.getToken([]) // Get SSO token using empty string array\n * await credential.getToken(\"\") // Get SSO token using empty string\n * await credential.getToken([\".default\"]) // Get Graph access token with default scope using string array\n * await credential.getToken(\".default\") // Get Graph access token with default scope using string\n * await credential.getToken([\"User.Read\"]) // Get Graph access token for single scope using string array\n * await credential.getToken(\"User.Read\") // Get Graph access token for single scope using string\n * await credential.getToken([\"User.Read\", \"Application.Read.All\"]) // Get Graph access token for multiple scopes using string array\n * await credential.getToken(\"User.Read Application.Read.All\") // Get Graph access token for multiple scopes using space-separated string\n * await credential.getToken(\"https://graph.microsoft.com/User.Read\") // Get Graph access token with full resource URI\n * await credential.getToken([\"https://outlook.office.com/Mail.Read\"]) // Get Outlook access token\n * ```\n *\n * @param {string | string[]} scopes - The list of scopes for which the token will have access.\n * @param {GetTokenOptions} options - The options used to configure any requests this TokenCredential implementation might make.\n *\n * @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.\n * @throws {@link ErrorCode|UiRequiredError} when need user consent to get access token.\n * @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.\n * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.\n *\n * @returns User access token of defined scopes.\n * If scopes is empty string or array, it returns SSO token.\n * If scopes is non-empty, it returns access token for target scope.\n * Throw error if get access token failed.\n *\n * @beta\n */\n async getToken(\n scopes: string | string[],\n options?: GetTokenOptions\n ): Promise<AccessToken | null> {\n validateScopesType(scopes);\n const ssoToken = await this.getSSOToken();\n\n const scopeStr = typeof scopes === \"string\" ? scopes : scopes.join(\" \");\n if (scopeStr === \"\") {\n internalLogger.info(\"Get SSO token\");\n\n return ssoToken;\n } else {\n internalLogger.info(\"Get access token with scopes: \" + scopeStr);\n const cachedKey = await this.getAccessTokenCacheKey(scopeStr);\n const cachedToken = this.getTokenCache(cachedKey);\n\n if (cachedToken) {\n if (!this.isAccessTokenNearExpired(cachedToken)) {\n internalLogger.verbose(\"Get access token from cache\");\n return cachedToken;\n } else {\n internalLogger.verbose(\"Cached access token is expired\");\n }\n } else {\n internalLogger.verbose(\"No cached access token\");\n }\n\n const accessToken = await this.getAndCacheAccessTokenFromSimpleAuthServer(scopeStr);\n return accessToken;\n }\n }\n\n /**\n * Get basic user info from SSO token\n *\n * @example\n * ```typescript\n * const currentUser = await credential.getUserInfo();\n * ```\n *\n * @throws {@link ErrorCode|InternalError} when SSO token from Teams client is not valid.\n * @throws {@link ErrorCode|InvalidParameter} when SSO token from Teams client is empty.\n * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.\n *\n * @returns Basic user info with user displayName, objectId and preferredUserName.\n *\n * @beta\n */\n public async getUserInfo(): Promise<UserInfo> {\n internalLogger.info(\"Get basic user info from SSO token\");\n const ssoToken = await this.getSSOToken();\n return getUserInfoFromSsoToken(ssoToken.token);\n }\n\n private async exchangeAccessTokenFromSimpleAuthServer(\n scopesStr: string,\n authCodeResult: AuthCodeResult\n ): Promise<void> {\n const axiosInstance: AxiosInstance = await this.getAxiosInstance();\n\n let retryCount = 0;\n while (true) {\n try {\n const response = await axiosInstance.post(\"/auth/token\", {\n scope: scopesStr,\n code: authCodeResult.code,\n code_verifier: authCodeResult.codeVerifier,\n redirect_uri: authCodeResult.redirectUri,\n grant_type: GrantType.authCode,\n });\n\n const tokenResult: AccessTokenResult = response.data;\n const key = await this.getAccessTokenCacheKey(scopesStr);\n this.setTokenCache(key, {\n token: tokenResult.access_token,\n expiresOnTimestamp: tokenResult.expires_on,\n });\n return;\n } catch (err: any) {\n if (err.response?.data?.type && err.response.data.type === \"AadUiRequiredException\") {\n internalLogger.warn(\"Exchange access token failed, retry...\");\n if (retryCount < maxRetryCount) {\n await this.sleep(retryTimeSpanInMillisecond);\n retryCount++;\n continue;\n }\n }\n throw err;\n }\n }\n }\n\n /**\n * Get access token cache from authentication server\n * @returns Access token\n */\n private async getAndCacheAccessTokenFromSimpleAuthServer(\n scopesStr: string\n ): Promise<AccessToken> {\n try {\n internalLogger.verbose(\n \"Get access token from authentication server with scopes: \" + scopesStr\n );\n const axiosInstance: AxiosInstance = await this.getAxiosInstance();\n const response = await axiosInstance.post(\"/auth/token\", {\n scope: scopesStr,\n grant_type: GrantType.ssoToken,\n });\n\n const accessTokenResult: AccessTokenResult = response.data;\n const accessToken: AccessToken = {\n token: accessTokenResult.access_token,\n expiresOnTimestamp: accessTokenResult.expires_on,\n };\n const cacheKey = await this.getAccessTokenCacheKey(scopesStr);\n this.setTokenCache(cacheKey, accessToken);\n return accessToken;\n } catch (err) {\n throw this.generateAuthServerError(err);\n }\n }\n\n /**\n * Get SSO token using teams SDK\n * It will try to get SSO token from memory first, if SSO token doesn't exist or about to expired, then it will using teams SDK to get SSO token\n * @returns SSO token\n */\n private getSSOToken(): Promise<AccessToken> {\n return new Promise<AccessToken>((resolve, reject) => {\n if (this.ssoToken) {\n if (this.ssoToken.expiresOnTimestamp - Date.now() > tokenRefreshTimeSpanInMillisecond) {\n internalLogger.verbose(\"Get SSO token from memory cache\");\n resolve(this.ssoToken);\n return;\n }\n }\n\n let initialized = false;\n microsoftTeams.initialize(() => {\n initialized = true;\n microsoftTeams.authentication.getAuthToken({\n successCallback: (token: string) => {\n if (!token) {\n const errorMsg = \"Get empty SSO token from Teams\";\n internalLogger.error(errorMsg);\n reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));\n return;\n }\n\n const tokenObject = parseJwt(token);\n if (tokenObject.ver !== \"1.0\" && tokenObject.ver !== \"2.0\") {\n const errorMsg = \"SSO token is not valid with an unknown version: \" + tokenObject.ver;\n internalLogger.error(errorMsg);\n reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));\n return;\n }\n\n const ssoToken: AccessToken = {\n token,\n expiresOnTimestamp: tokenObject.exp * 1000,\n };\n\n this.ssoToken = ssoToken;\n resolve(ssoToken);\n },\n failureCallback: (errMessage: string) => {\n const errorMsg = \"Get SSO token failed with error: \" + errMessage;\n internalLogger.error(errorMsg);\n reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));\n },\n resources: [],\n });\n });\n\n // If the code not running in Teams, the initialize callback function would never trigger\n setTimeout(() => {\n if (!initialized) {\n const errorMsg =\n \"Initialize teams sdk timeout, maybe the code is not running inside Teams\";\n internalLogger.error(errorMsg);\n reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));\n }\n }, initializeTeamsSdkTimeoutInMillisecond);\n });\n }\n\n /**\n * Load and validate authentication configuration\n * @returns Authentication configuration\n */\n private loadAndValidateConfig(): AuthenticationConfiguration {\n internalLogger.verbose(\"Validate authentication configuration\");\n const config = getAuthenticationConfiguration();\n\n if (!config) {\n internalLogger.error(ErrorMessage.AuthenticationConfigurationNotExists);\n\n throw new ErrorWithCode(\n ErrorMessage.AuthenticationConfigurationNotExists,\n ErrorCode.InvalidConfiguration\n );\n }\n\n if (config.initiateLoginEndpoint && config.simpleAuthEndpoint && config.clientId) {\n return config;\n }\n\n const missingValues = [];\n if (!config.initiateLoginEndpoint) {\n missingValues.push(\"initiateLoginEndpoint\");\n }\n\n if (!config.simpleAuthEndpoint) {\n missingValues.push(\"simpleAuthEndpoint\");\n }\n\n if (!config.clientId) {\n missingValues.push(\"clientId\");\n }\n\n const errorMsg = formatString(\n ErrorMessage.InvalidConfiguration,\n missingValues.join(\", \"),\n \"undefined\"\n );\n\n internalLogger.error(errorMsg);\n throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);\n }\n\n /**\n * Get axios instance with sso token bearer header\n * @returns AxiosInstance\n */\n private async getAxiosInstance(): Promise<AxiosInstance> {\n const ssoToken = await this.getSSOToken();\n const axiosInstance: AxiosInstance = axios.create({\n baseURL: this.config.simpleAuthEndpoint,\n });\n\n axiosInstance.interceptors.request.use((config) => {\n config.headers.Authorization = \"Bearer \" + ssoToken.token;\n return config;\n });\n\n return axiosInstance;\n }\n\n /**\n * Set access token to cache\n * @param key\n * @param token\n */\n private setTokenCache(key: string, token: AccessToken): void {\n Cache.set(key, JSON.stringify(token));\n }\n\n /**\n * Get access token from cache.\n * If there is no cache or cannot be parsed, then it will return null\n * @param key\n * @returns Access token or null\n */\n private getTokenCache(key: string): AccessToken | null {\n const value = Cache.get(key);\n if (value === null) {\n return null;\n }\n\n const accessToken: AccessToken | null = this.validateAndParseJson(value);\n return accessToken;\n }\n\n /**\n * Parses passed value as JSON access token, if value is not a valid json string JSON.parse() will throw an error.\n * @param jsonValue\n */\n private validateAndParseJson(jsonValue: string): AccessToken | null {\n try {\n const parsedJson = JSON.parse(jsonValue);\n /**\n * There are edge cases in which JSON.parse will successfully parse a non-valid JSON object\n * (e.g. JSON.parse will parse an escaped string into an unescaped string), so adding a type check\n * of the parsed value is necessary in order to be certain that the string represents a valid JSON object.\n *\n */\n return parsedJson && typeof parsedJson === \"object\" ? parsedJson : null;\n } catch (error) {\n return null;\n }\n }\n\n /**\n * Generate cache key\n * @param scopesStr\n * @returns Access token cache key, a key example: accessToken-userId-clientId-tenantId-scopes\n */\n private async getAccessTokenCacheKey(scopesStr: string): Promise<string> {\n const ssoToken = await this.getSSOToken();\n const ssoTokenObj = parseJwt(ssoToken.token);\n\n const clientId = this.config.clientId;\n const userObjectId = ssoTokenObj.oid;\n const tenantId = ssoTokenObj.tid;\n\n const key = [accessTokenCacheKeyPrefix, userObjectId, clientId, tenantId, scopesStr]\n .join(separator)\n .replace(/\" \"/g, \"_\");\n return key;\n }\n\n /**\n * Check whether the token is about to expire (within 5 minutes)\n * @returns Boolean value indicate whether the token is about to expire\n */\n private isAccessTokenNearExpired(token: AccessToken): boolean {\n const expireDate = new Date(token.expiresOnTimestamp);\n if (expireDate.getTime() - Date.now() > tokenRefreshTimeSpanInMillisecond) {\n return false;\n }\n return true;\n }\n\n private generateAuthServerError(err: any): Error {\n let errorMessage = err.message;\n if (err.response?.data?.type) {\n errorMessage = err.response.data.detail;\n if (err.response.data.type === \"AadUiRequiredException\") {\n const fullErrorMsg =\n \"Failed to get access token from authentication server, please login first: \" +\n errorMessage;\n internalLogger.warn(fullErrorMsg);\n return new ErrorWithCode(fullErrorMsg, ErrorCode.UiRequiredError);\n } else {\n const fullErrorMsg =\n \"Failed to get access token from authentication server: \" + errorMessage;\n internalLogger.error(fullErrorMsg);\n return new ErrorWithCode(fullErrorMsg, ErrorCode.ServiceError);\n }\n }\n\n const fullErrorMsg = \"Failed to get access token with error: \" + errorMessage;\n return new ErrorWithCode(fullErrorMsg, ErrorCode.InternalError);\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"]}