@fluidframework/tool-utils 2.51.0 → 2.53.0-350190

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @fluidframework/tool-utils
2
2
 
3
+ ## 2.52.0
4
+
5
+ Dependency updates only.
6
+
3
7
  ## 2.51.0
4
8
 
5
9
  Dependency updates only.
@@ -1 +1 @@
1
- {"version":3,"file":"odspTokenManager.d.ts","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,mBAAmB,EACnB,WAAW,EAEX,MAAM,4CAA4C,CAAC;AAYpD,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAUhE;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAO,mBAQ3C,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,eAAe,GACxB;IACA,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAChB,GACD;IACA,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9D,CAAC;AAEL;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC9B;AAiBD;;GAEG;AACH,qBAAa,gBAAgB;IAK3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAJ7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;gBAExB,UAAU,CAAC,iEAAqD;IAGrE,iBAAiB,CAC7B,GAAG,EAAE,yBAAyB,EAC9B,KAAK,EAAE,WAAW,GAChB,OAAO,CAAC,IAAI,CAAC;YAMF,4BAA4B;IAU7B,aAAa,CACzB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,mBAAmB,EACjC,WAAW,EAAE,eAAe,EAC5B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;IAKV,aAAa,CACzB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,mBAAmB,EACjC,WAAW,EAAE,eAAe,EAC5B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;YAKT,iBAAiB;IAiB/B,OAAO,CAAC,MAAM,CAAC,WAAW;YAYZ,SAAS;YA0CT,aAAa;YAkEb,yBAAyB;YAezB,4BAA4B;YAuC5B,yBAAyB;IASvC,OAAO,CAAC,wBAAwB;CAWhC;AAaD;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,yBAAyB,EAAE,WAAW,CA6B/E,CAAC"}
1
+ {"version":3,"file":"odspTokenManager.d.ts","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,mBAAmB,EACnB,WAAW,EAEX,MAAM,4CAA4C,CAAC;AAWpD,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAUhE;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAO,mBAQ3C,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,eAAe,GACxB;IACA,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAChB,GACD;IACA,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9D,CAAC;AAEL;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC9B;AAsBD;;GAEG;AACH,qBAAa,gBAAgB;IAK3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAJ7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;gBAExB,UAAU,CAAC,iEAAqD;IAGrE,iBAAiB,CAC7B,GAAG,EAAE,yBAAyB,EAC9B,KAAK,EAAE,WAAW,GAChB,OAAO,CAAC,IAAI,CAAC;YAMF,4BAA4B;IAU7B,aAAa,CACzB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,mBAAmB,EACjC,WAAW,EAAE,eAAe,EAC5B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;IAKV,aAAa,CACzB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,mBAAmB,EACjC,WAAW,EAAE,eAAe,EAC5B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;YAKT,iBAAiB;IAiB/B,OAAO,CAAC,MAAM,CAAC,WAAW;YAYZ,SAAS;YA0CT,aAAa;YAyEb,yBAAyB;YAezB,4BAA4B;YAuC5B,yBAAyB;IASvC,OAAO,CAAC,wBAAwB;CAWhC;AAaD;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,yBAAyB,EAAE,WAAW,CA6B/E,CAAC"}
@@ -8,7 +8,6 @@ exports.odspTokensCache = exports.OdspTokenManager = exports.getMicrosoftConfigu
8
8
  const internal_1 = require("@fluidframework/core-utils/internal");
9
9
  const internal_2 = require("@fluidframework/odsp-doclib-utils/internal");
10
10
  const async_mutex_1 = require("async-mutex");
11
- const jwt_decode_1 = require("jwt-decode");
12
11
  const debug_js_1 = require("./debug.js");
13
12
  const fluidToolRc_js_1 = require("./fluidToolRc.js");
14
13
  const httpHelpers_js_1 = require("./httpHelpers.js");
@@ -30,14 +29,18 @@ const getMicrosoftConfiguration = () => ({
30
29
  },
31
30
  });
32
31
  exports.getMicrosoftConfiguration = getMicrosoftConfiguration;
33
- const isValidToken = (token) => {
32
+ const isValidAndNotExpiredToken = (tokens) => {
34
33
  // Return false for undefined or empty tokens.
35
- if (!token || token.length === 0) {
34
+ if (!tokens.accessToken || tokens.accessToken.length === 0) {
36
35
  return false;
37
36
  }
38
- const decodedToken = (0, jwt_decode_1.jwtDecode)(token);
37
+ if (tokens.receivedAt === undefined || tokens.expiresIn === undefined) {
38
+ // If we don't have receivedAt or expiresIn, we treat the token as expired.
39
+ return false;
40
+ }
41
+ const expiresAt = tokens.receivedAt + tokens.expiresIn;
39
42
  // Give it a 60s buffer
40
- return decodedToken.exp - 60 >= Date.now() / 1000;
43
+ return expiresAt - 60 >= Date.now() / 1000;
41
44
  };
42
45
  const cacheKeyToString = (key) => {
43
46
  return `${key.userOrServer}${key.isPush ? "[Push]" : ""}`;
@@ -105,7 +108,7 @@ class OdspTokenManager {
105
108
  const cacheKey = OdspTokenManager.getCacheKey(isPush, tokenConfig, server);
106
109
  const tokensFromCache = await this.getTokenFromCache(cacheKey);
107
110
  if (tokensFromCache) {
108
- if (isValidToken(tokensFromCache.accessToken)) {
111
+ if (isValidAndNotExpiredToken(tokensFromCache)) {
109
112
  (0, debug_js_1.debug)(`${cacheKeyToString(cacheKey)}: Token reused from cache `);
110
113
  await this.onTokenRetrievalFromCache(tokenConfig, tokensFromCache);
111
114
  return tokensFromCache;
@@ -127,7 +130,7 @@ class OdspTokenManager {
127
130
  // check the cache again under the lock (if it is there)
128
131
  const tokensFromCache = await this.getTokenFromCache(cacheKey);
129
132
  if (tokensFromCache) {
130
- if (forceRefresh || !isValidToken(tokensFromCache.accessToken)) {
133
+ if (forceRefresh || !isValidAndNotExpiredToken(tokensFromCache)) {
131
134
  try {
132
135
  // This updates the tokens in tokensFromCache
133
136
  tokens = await (0, internal_2.refreshTokens)(server, scope, clientConfig, tokensFromCache);
@@ -160,6 +163,10 @@ class OdspTokenManager {
160
163
  (0, internal_1.unreachableCase)(tokenConfig);
161
164
  }
162
165
  }
166
+ if (!isValidAndNotExpiredToken(tokens)) {
167
+ throw new Error(`Acquired invalid tokens for ${cacheKeyToString(cacheKey)}. ` +
168
+ `Acquired token JSON: ${JSON.stringify(tokens)}`);
169
+ }
163
170
  await this.updateTokensCacheWithoutLock(cacheKey, tokens);
164
171
  return tokens;
165
172
  }
@@ -1 +1 @@
1
- {"version":3,"file":"odspTokenManager.js","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { unreachableCase } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIPublicClientConfig,\n\tIOdspTokens,\n\tTokenRequestCredentials,\n} from \"@fluidframework/odsp-doclib-utils/internal\";\nimport {\n\tfetchTokens,\n\tgetLoginPageUrl,\n\tgetOdspScope,\n\tpushScope,\n\trefreshTokens,\n} from \"@fluidframework/odsp-doclib-utils/internal\";\nimport { Mutex } from \"async-mutex\";\nimport { jwtDecode } from \"jwt-decode\";\n\nimport { debug } from \"./debug.js\";\nimport type { IAsyncCache, IResources } from \"./fluidToolRc.js\";\nimport { loadRC, lockRC, saveRC } from \"./fluidToolRc.js\";\nimport { endResponse, serverListenAndHandle } from \"./httpHelpers.js\";\n\nconst odspAuthRedirectPort = 7000;\nconst odspAuthRedirectOrigin = `http://localhost:${odspAuthRedirectPort}`;\nconst odspAuthRedirectUri = new URL(\"/auth/callback\", odspAuthRedirectOrigin).href;\n\n// TODO: Add documentation\n// eslint-disable-next-line jsdoc/require-description\n/**\n * @internal\n */\nexport const getMicrosoftConfiguration = (): IPublicClientConfig => ({\n\tget clientId(): string {\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\tif (!process.env.login__microsoft__clientId) {\n\t\t\tthrow new Error(\"Client ID environment variable not set: login__microsoft__clientId.\");\n\t\t}\n\t\treturn process.env.login__microsoft__clientId;\n\t},\n});\n\n/**\n * @internal\n */\nexport type OdspTokenConfig =\n\t| {\n\t\t\ttype: \"password\";\n\t\t\tusername: string;\n\t\t\tpassword: string;\n\t }\n\t| {\n\t\t\ttype: \"browserLogin\";\n\t\t\tnavigator: (url: string) => void;\n\t\t\tredirectUriCallback?: (tokens: IOdspTokens) => Promise<string>;\n\t };\n\n/**\n * @internal\n */\nexport interface IOdspTokenManagerCacheKey {\n\treadonly isPush: boolean;\n\treadonly userOrServer: string;\n}\n\nconst isValidToken = (token: string): boolean => {\n\t// Return false for undefined or empty tokens.\n\tif (!token || token.length === 0) {\n\t\treturn false;\n\t}\n\n\tconst decodedToken = jwtDecode<{ exp: number }>(token);\n\t// Give it a 60s buffer\n\treturn decodedToken.exp - 60 >= Date.now() / 1000;\n};\n\nconst cacheKeyToString = (key: IOdspTokenManagerCacheKey): string => {\n\treturn `${key.userOrServer}${key.isPush ? \"[Push]\" : \"\"}`;\n};\n\n/**\n * @internal\n */\nexport class OdspTokenManager {\n\tprivate readonly storageCache = new Map<string, IOdspTokens>();\n\tprivate readonly pushCache = new Map<string, IOdspTokens>();\n\tprivate readonly cacheMutex = new Mutex();\n\tpublic constructor(\n\t\tprivate readonly tokenCache?: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens>,\n\t) {}\n\n\tpublic async updateTokensCache(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tawait this.cacheMutex.runExclusive(async () => {\n\t\t\tawait this.updateTokensCacheWithoutLock(key, value);\n\t\t});\n\t}\n\n\tprivate async updateTokensCacheWithoutLock(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tdebug(`${cacheKeyToString(key)}: Saving tokens`);\n\t\tconst memoryCache = key.isPush ? this.pushCache : this.storageCache;\n\t\tmemoryCache.set(key.userOrServer, value);\n\t\tawait this.tokenCache?.save(key, value);\n\t}\n\n\tpublic async getOdspTokens(\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting odsp tokens\");\n\t\treturn this.getTokens(false, server, clientConfig, tokenConfig, forceRefresh, forceReauth);\n\t}\n\n\tpublic async getPushTokens(\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting push tokens\");\n\t\treturn this.getTokens(true, server, clientConfig, tokenConfig, forceRefresh, forceReauth);\n\t}\n\n\tprivate async getTokenFromCache(\n\t\tcacheKey: IOdspTokenManagerCacheKey,\n\t): Promise<IOdspTokens | undefined> {\n\t\tconst memoryCache = cacheKey.isPush ? this.pushCache : this.storageCache;\n\t\tconst memoryToken = memoryCache.get(cacheKey.userOrServer);\n\t\tif (memoryToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in memory `);\n\t\t\treturn memoryToken;\n\t\t}\n\t\tconst fileToken = await this.tokenCache?.get(cacheKey);\n\t\tif (fileToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in file`);\n\t\t\tmemoryCache.set(cacheKey.userOrServer, fileToken);\n\t\t\treturn fileToken;\n\t\t}\n\t}\n\n\tprivate static getCacheKey(\n\t\tisPush: boolean,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tserver: string,\n\t): IOdspTokenManagerCacheKey {\n\t\t// If we are using password, we should cache the token per user instead of per server\n\t\treturn {\n\t\t\tisPush,\n\t\t\tuserOrServer: tokenConfig.type === \"password\" ? tokenConfig.username : server,\n\t\t};\n\t}\n\n\tprivate async getTokens(\n\t\tisPush: boolean,\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst invokeGetTokensCore = async (): Promise<IOdspTokens> => {\n\t\t\t// Don't solely rely on tokenCache lock, ensure serialized execution of\n\t\t\t// cache update to avoid multiple fetch.\n\t\t\treturn this.cacheMutex.runExclusive(async () => {\n\t\t\t\treturn this.getTokensCore(\n\t\t\t\t\tisPush,\n\t\t\t\t\tserver,\n\t\t\t\t\tclientConfig,\n\t\t\t\t\ttokenConfig,\n\t\t\t\t\tforceRefresh,\n\t\t\t\t\tforceReauth,\n\t\t\t\t);\n\t\t\t});\n\t\t};\n\t\tif (!forceReauth && !forceRefresh) {\n\t\t\t// check and return if it exists without lock\n\t\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, tokenConfig, server);\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (isValidToken(tokensFromCache.accessToken)) {\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from cache `);\n\t\t\t\t\tawait this.onTokenRetrievalFromCache(tokenConfig, tokensFromCache);\n\t\t\t\t\treturn tokensFromCache;\n\t\t\t\t}\n\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token expired from cache `);\n\t\t\t}\n\t\t}\n\t\tif (this.tokenCache) {\n\t\t\t// check with lock, used to prevent concurrent auth attempts\n\t\t\treturn this.tokenCache.lock(invokeGetTokensCore);\n\t\t}\n\t\treturn invokeGetTokensCore();\n\t}\n\n\tprivate async getTokensCore(\n\t\tisPush: boolean,\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst scope = isPush ? pushScope : getOdspScope(server);\n\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, tokenConfig, server);\n\t\tlet tokens: IOdspTokens | undefined;\n\t\tif (!forceReauth) {\n\t\t\t// check the cache again under the lock (if it is there)\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (forceRefresh || !isValidToken(tokensFromCache.accessToken)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// This updates the tokens in tokensFromCache\n\t\t\t\t\t\ttokens = await refreshTokens(server, scope, clientConfig, tokensFromCache);\n\t\t\t\t\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Error in refreshing token. ${error}`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttokens = tokensFromCache;\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from locked cache `);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (tokens) {\n\t\t\tawait this.onTokenRetrievalFromCache(tokenConfig, tokens);\n\t\t\treturn tokens;\n\t\t}\n\n\t\tswitch (tokenConfig.type) {\n\t\t\tcase \"password\": {\n\t\t\t\ttokens = await this.acquireTokensWithPassword(\n\t\t\t\t\tserver,\n\t\t\t\t\tscope,\n\t\t\t\t\tclientConfig,\n\t\t\t\t\ttokenConfig.username,\n\t\t\t\t\ttokenConfig.password,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"browserLogin\": {\n\t\t\t\ttokens = await this.acquireTokensViaBrowserLogin(\n\t\t\t\t\tgetLoginPageUrl(server, clientConfig, scope, odspAuthRedirectUri),\n\t\t\t\t\tserver,\n\t\t\t\t\tclientConfig,\n\t\t\t\t\tscope,\n\t\t\t\t\ttokenConfig.navigator,\n\t\t\t\t\ttokenConfig.redirectUriCallback,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tunreachableCase(tokenConfig);\n\t\t\t}\n\t\t}\n\n\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\treturn tokens;\n\t}\n\n\tprivate async acquireTokensWithPassword(\n\t\tserver: string,\n\t\tscope: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\tusername: string,\n\t\tpassword: string,\n\t): Promise<IOdspTokens> {\n\t\tconst credentials: TokenRequestCredentials = {\n\t\t\tgrant_type: \"password\",\n\t\t\tusername,\n\t\t\tpassword,\n\t\t};\n\t\treturn fetchTokens(server, scope, clientConfig, credentials);\n\t}\n\n\tprivate async acquireTokensViaBrowserLogin(\n\t\tloginPageUrl: string,\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\tscope: string,\n\t\tnavigator: (url: string) => void,\n\t\tredirectUriCallback?: (tokens: IOdspTokens) => Promise<string>,\n\t): Promise<IOdspTokens> {\n\t\t// Start up a local auth redirect handler service to receive the tokens after login\n\t\tconst tokenGetter = await serverListenAndHandle(odspAuthRedirectPort, async (req, res) => {\n\t\t\t// extract code from request URL and fetch the tokens\n\t\t\tconst credentials: TokenRequestCredentials = {\n\t\t\t\tgrant_type: \"authorization_code\",\n\t\t\t\tcode: this.extractAuthorizationCode(req.url),\n\t\t\t\tredirect_uri: odspAuthRedirectUri,\n\t\t\t};\n\t\t\tconst tokens = await fetchTokens(server, scope, clientConfig, credentials);\n\n\t\t\t// redirect now that the browser is done with auth\n\t\t\tif (redirectUriCallback) {\n\t\t\t\tres.writeHead(301, { Location: await redirectUriCallback(tokens) });\n\t\t\t\tawait endResponse(res);\n\t\t\t} else {\n\t\t\t\tres.write(\"Please close the window\");\n\t\t\t\tawait endResponse(res);\n\t\t\t}\n\n\t\t\treturn tokens;\n\t\t});\n\n\t\t// Now that our local redirect handler is up, navigate the browser to the login page\n\t\tnavigator(loginPageUrl);\n\n\t\t// Receive and extract the tokens\n\t\tconst odspTokens = await tokenGetter();\n\n\t\treturn odspTokens;\n\t}\n\n\tprivate async onTokenRetrievalFromCache(\n\t\tconfig: OdspTokenConfig,\n\t\ttokens: IOdspTokens,\n\t): Promise<void> {\n\t\tif (config.type === \"browserLogin\" && config.redirectUriCallback) {\n\t\t\tconfig.navigator(await config.redirectUriCallback(tokens));\n\t\t}\n\t}\n\n\tprivate extractAuthorizationCode(relativeUrl: string | undefined): string {\n\t\tif (relativeUrl === undefined) {\n\t\t\tthrow new Error(\"Failed to get authorization\");\n\t\t}\n\t\tconst parsedUrl = new URL(relativeUrl, odspAuthRedirectOrigin);\n\t\tconst code = parsedUrl.searchParams.get(\"code\");\n\t\tif (code === null || code === undefined) {\n\t\t\tthrow new Error(\"Failed to get authorization\");\n\t\t}\n\t\treturn code;\n\t}\n}\n\nasync function loadAndPatchRC(): Promise<IResources> {\n\tconst rc = await loadRC();\n\tif (rc.tokens && rc.tokens.version === undefined) {\n\t\t// Clean up older versions\n\t\tdelete rc.tokens;\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\tdelete (rc as any).pushTokens;\n\t}\n\treturn rc;\n}\n\n/**\n * @internal\n */\nexport const odspTokensCache: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens> = {\n\tasync get(key: IOdspTokenManagerCacheKey): Promise<IOdspTokens | undefined> {\n\t\tconst rc = await loadAndPatchRC();\n\t\treturn rc.tokens?.data[key.userOrServer]?.[key.isPush ? \"push\" : \"storage\"];\n\t},\n\tasync save(key: IOdspTokenManagerCacheKey, tokens: IOdspTokens): Promise<void> {\n\t\tconst rc = await loadAndPatchRC();\n\t\tif (!rc.tokens) {\n\t\t\trc.tokens = {\n\t\t\t\tversion: 1,\n\t\t\t\tdata: {},\n\t\t\t};\n\t\t}\n\t\tlet prevTokens = rc.tokens.data[key.userOrServer];\n\t\tif (!prevTokens) {\n\t\t\tprevTokens = {};\n\t\t\trc.tokens.data[key.userOrServer] = prevTokens;\n\t\t}\n\t\tprevTokens[key.isPush ? \"push\" : \"storage\"] = tokens;\n\t\treturn saveRC(rc);\n\t},\n\tasync lock<T>(callback: () => Promise<T>): Promise<T> {\n\t\tconst release = await lockRC();\n\t\ttry {\n\t\t\treturn await callback();\n\t\t} finally {\n\t\t\tawait release();\n\t\t}\n\t},\n};\n"]}
1
+ {"version":3,"file":"odspTokenManager.js","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { unreachableCase } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIPublicClientConfig,\n\tIOdspTokens,\n\tTokenRequestCredentials,\n} from \"@fluidframework/odsp-doclib-utils/internal\";\nimport {\n\tfetchTokens,\n\tgetLoginPageUrl,\n\tgetOdspScope,\n\tpushScope,\n\trefreshTokens,\n} from \"@fluidframework/odsp-doclib-utils/internal\";\nimport { Mutex } from \"async-mutex\";\n\nimport { debug } from \"./debug.js\";\nimport type { IAsyncCache, IResources } from \"./fluidToolRc.js\";\nimport { loadRC, lockRC, saveRC } from \"./fluidToolRc.js\";\nimport { endResponse, serverListenAndHandle } from \"./httpHelpers.js\";\n\nconst odspAuthRedirectPort = 7000;\nconst odspAuthRedirectOrigin = `http://localhost:${odspAuthRedirectPort}`;\nconst odspAuthRedirectUri = new URL(\"/auth/callback\", odspAuthRedirectOrigin).href;\n\n// TODO: Add documentation\n// eslint-disable-next-line jsdoc/require-description\n/**\n * @internal\n */\nexport const getMicrosoftConfiguration = (): IPublicClientConfig => ({\n\tget clientId(): string {\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\tif (!process.env.login__microsoft__clientId) {\n\t\t\tthrow new Error(\"Client ID environment variable not set: login__microsoft__clientId.\");\n\t\t}\n\t\treturn process.env.login__microsoft__clientId;\n\t},\n});\n\n/**\n * @internal\n */\nexport type OdspTokenConfig =\n\t| {\n\t\t\ttype: \"password\";\n\t\t\tusername: string;\n\t\t\tpassword: string;\n\t }\n\t| {\n\t\t\ttype: \"browserLogin\";\n\t\t\tnavigator: (url: string) => void;\n\t\t\tredirectUriCallback?: (tokens: IOdspTokens) => Promise<string>;\n\t };\n\n/**\n * @internal\n */\nexport interface IOdspTokenManagerCacheKey {\n\treadonly isPush: boolean;\n\treadonly userOrServer: string;\n}\n\nconst isValidAndNotExpiredToken = (tokens: IOdspTokens): boolean => {\n\t// Return false for undefined or empty tokens.\n\tif (!tokens.accessToken || tokens.accessToken.length === 0) {\n\t\treturn false;\n\t}\n\n\tif (tokens.receivedAt === undefined || tokens.expiresIn === undefined) {\n\t\t// If we don't have receivedAt or expiresIn, we treat the token as expired.\n\t\treturn false;\n\t}\n\n\tconst expiresAt = tokens.receivedAt + tokens.expiresIn;\n\t// Give it a 60s buffer\n\treturn expiresAt - 60 >= Date.now() / 1000;\n};\n\nconst cacheKeyToString = (key: IOdspTokenManagerCacheKey): string => {\n\treturn `${key.userOrServer}${key.isPush ? \"[Push]\" : \"\"}`;\n};\n\n/**\n * @internal\n */\nexport class OdspTokenManager {\n\tprivate readonly storageCache = new Map<string, IOdspTokens>();\n\tprivate readonly pushCache = new Map<string, IOdspTokens>();\n\tprivate readonly cacheMutex = new Mutex();\n\tpublic constructor(\n\t\tprivate readonly tokenCache?: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens>,\n\t) {}\n\n\tpublic async updateTokensCache(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tawait this.cacheMutex.runExclusive(async () => {\n\t\t\tawait this.updateTokensCacheWithoutLock(key, value);\n\t\t});\n\t}\n\n\tprivate async updateTokensCacheWithoutLock(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tdebug(`${cacheKeyToString(key)}: Saving tokens`);\n\t\tconst memoryCache = key.isPush ? this.pushCache : this.storageCache;\n\t\tmemoryCache.set(key.userOrServer, value);\n\t\tawait this.tokenCache?.save(key, value);\n\t}\n\n\tpublic async getOdspTokens(\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting odsp tokens\");\n\t\treturn this.getTokens(false, server, clientConfig, tokenConfig, forceRefresh, forceReauth);\n\t}\n\n\tpublic async getPushTokens(\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting push tokens\");\n\t\treturn this.getTokens(true, server, clientConfig, tokenConfig, forceRefresh, forceReauth);\n\t}\n\n\tprivate async getTokenFromCache(\n\t\tcacheKey: IOdspTokenManagerCacheKey,\n\t): Promise<IOdspTokens | undefined> {\n\t\tconst memoryCache = cacheKey.isPush ? this.pushCache : this.storageCache;\n\t\tconst memoryToken = memoryCache.get(cacheKey.userOrServer);\n\t\tif (memoryToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in memory `);\n\t\t\treturn memoryToken;\n\t\t}\n\t\tconst fileToken = await this.tokenCache?.get(cacheKey);\n\t\tif (fileToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in file`);\n\t\t\tmemoryCache.set(cacheKey.userOrServer, fileToken);\n\t\t\treturn fileToken;\n\t\t}\n\t}\n\n\tprivate static getCacheKey(\n\t\tisPush: boolean,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tserver: string,\n\t): IOdspTokenManagerCacheKey {\n\t\t// If we are using password, we should cache the token per user instead of per server\n\t\treturn {\n\t\t\tisPush,\n\t\t\tuserOrServer: tokenConfig.type === \"password\" ? tokenConfig.username : server,\n\t\t};\n\t}\n\n\tprivate async getTokens(\n\t\tisPush: boolean,\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst invokeGetTokensCore = async (): Promise<IOdspTokens> => {\n\t\t\t// Don't solely rely on tokenCache lock, ensure serialized execution of\n\t\t\t// cache update to avoid multiple fetch.\n\t\t\treturn this.cacheMutex.runExclusive(async () => {\n\t\t\t\treturn this.getTokensCore(\n\t\t\t\t\tisPush,\n\t\t\t\t\tserver,\n\t\t\t\t\tclientConfig,\n\t\t\t\t\ttokenConfig,\n\t\t\t\t\tforceRefresh,\n\t\t\t\t\tforceReauth,\n\t\t\t\t);\n\t\t\t});\n\t\t};\n\t\tif (!forceReauth && !forceRefresh) {\n\t\t\t// check and return if it exists without lock\n\t\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, tokenConfig, server);\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (isValidAndNotExpiredToken(tokensFromCache)) {\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from cache `);\n\t\t\t\t\tawait this.onTokenRetrievalFromCache(tokenConfig, tokensFromCache);\n\t\t\t\t\treturn tokensFromCache;\n\t\t\t\t}\n\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token expired from cache `);\n\t\t\t}\n\t\t}\n\t\tif (this.tokenCache) {\n\t\t\t// check with lock, used to prevent concurrent auth attempts\n\t\t\treturn this.tokenCache.lock(invokeGetTokensCore);\n\t\t}\n\t\treturn invokeGetTokensCore();\n\t}\n\n\tprivate async getTokensCore(\n\t\tisPush: boolean,\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst scope = isPush ? pushScope : getOdspScope(server);\n\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, tokenConfig, server);\n\t\tlet tokens: IOdspTokens | undefined;\n\t\tif (!forceReauth) {\n\t\t\t// check the cache again under the lock (if it is there)\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (forceRefresh || !isValidAndNotExpiredToken(tokensFromCache)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// This updates the tokens in tokensFromCache\n\t\t\t\t\t\ttokens = await refreshTokens(server, scope, clientConfig, tokensFromCache);\n\t\t\t\t\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Error in refreshing token. ${error}`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttokens = tokensFromCache;\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from locked cache `);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (tokens) {\n\t\t\tawait this.onTokenRetrievalFromCache(tokenConfig, tokens);\n\t\t\treturn tokens;\n\t\t}\n\n\t\tswitch (tokenConfig.type) {\n\t\t\tcase \"password\": {\n\t\t\t\ttokens = await this.acquireTokensWithPassword(\n\t\t\t\t\tserver,\n\t\t\t\t\tscope,\n\t\t\t\t\tclientConfig,\n\t\t\t\t\ttokenConfig.username,\n\t\t\t\t\ttokenConfig.password,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"browserLogin\": {\n\t\t\t\ttokens = await this.acquireTokensViaBrowserLogin(\n\t\t\t\t\tgetLoginPageUrl(server, clientConfig, scope, odspAuthRedirectUri),\n\t\t\t\t\tserver,\n\t\t\t\t\tclientConfig,\n\t\t\t\t\tscope,\n\t\t\t\t\ttokenConfig.navigator,\n\t\t\t\t\ttokenConfig.redirectUriCallback,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tunreachableCase(tokenConfig);\n\t\t\t}\n\t\t}\n\n\t\tif (!isValidAndNotExpiredToken(tokens)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Acquired invalid tokens for ${cacheKeyToString(cacheKey)}. ` +\n\t\t\t\t\t`Acquired token JSON: ${JSON.stringify(tokens)}`,\n\t\t\t);\n\t\t}\n\n\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\treturn tokens;\n\t}\n\n\tprivate async acquireTokensWithPassword(\n\t\tserver: string,\n\t\tscope: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\tusername: string,\n\t\tpassword: string,\n\t): Promise<IOdspTokens> {\n\t\tconst credentials: TokenRequestCredentials = {\n\t\t\tgrant_type: \"password\",\n\t\t\tusername,\n\t\t\tpassword,\n\t\t};\n\t\treturn fetchTokens(server, scope, clientConfig, credentials);\n\t}\n\n\tprivate async acquireTokensViaBrowserLogin(\n\t\tloginPageUrl: string,\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\tscope: string,\n\t\tnavigator: (url: string) => void,\n\t\tredirectUriCallback?: (tokens: IOdspTokens) => Promise<string>,\n\t): Promise<IOdspTokens> {\n\t\t// Start up a local auth redirect handler service to receive the tokens after login\n\t\tconst tokenGetter = await serverListenAndHandle(odspAuthRedirectPort, async (req, res) => {\n\t\t\t// extract code from request URL and fetch the tokens\n\t\t\tconst credentials: TokenRequestCredentials = {\n\t\t\t\tgrant_type: \"authorization_code\",\n\t\t\t\tcode: this.extractAuthorizationCode(req.url),\n\t\t\t\tredirect_uri: odspAuthRedirectUri,\n\t\t\t};\n\t\t\tconst tokens = await fetchTokens(server, scope, clientConfig, credentials);\n\n\t\t\t// redirect now that the browser is done with auth\n\t\t\tif (redirectUriCallback) {\n\t\t\t\tres.writeHead(301, { Location: await redirectUriCallback(tokens) });\n\t\t\t\tawait endResponse(res);\n\t\t\t} else {\n\t\t\t\tres.write(\"Please close the window\");\n\t\t\t\tawait endResponse(res);\n\t\t\t}\n\n\t\t\treturn tokens;\n\t\t});\n\n\t\t// Now that our local redirect handler is up, navigate the browser to the login page\n\t\tnavigator(loginPageUrl);\n\n\t\t// Receive and extract the tokens\n\t\tconst odspTokens = await tokenGetter();\n\n\t\treturn odspTokens;\n\t}\n\n\tprivate async onTokenRetrievalFromCache(\n\t\tconfig: OdspTokenConfig,\n\t\ttokens: IOdspTokens,\n\t): Promise<void> {\n\t\tif (config.type === \"browserLogin\" && config.redirectUriCallback) {\n\t\t\tconfig.navigator(await config.redirectUriCallback(tokens));\n\t\t}\n\t}\n\n\tprivate extractAuthorizationCode(relativeUrl: string | undefined): string {\n\t\tif (relativeUrl === undefined) {\n\t\t\tthrow new Error(\"Failed to get authorization\");\n\t\t}\n\t\tconst parsedUrl = new URL(relativeUrl, odspAuthRedirectOrigin);\n\t\tconst code = parsedUrl.searchParams.get(\"code\");\n\t\tif (code === null || code === undefined) {\n\t\t\tthrow new Error(\"Failed to get authorization\");\n\t\t}\n\t\treturn code;\n\t}\n}\n\nasync function loadAndPatchRC(): Promise<IResources> {\n\tconst rc = await loadRC();\n\tif (rc.tokens && rc.tokens.version === undefined) {\n\t\t// Clean up older versions\n\t\tdelete rc.tokens;\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\tdelete (rc as any).pushTokens;\n\t}\n\treturn rc;\n}\n\n/**\n * @internal\n */\nexport const odspTokensCache: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens> = {\n\tasync get(key: IOdspTokenManagerCacheKey): Promise<IOdspTokens | undefined> {\n\t\tconst rc = await loadAndPatchRC();\n\t\treturn rc.tokens?.data[key.userOrServer]?.[key.isPush ? \"push\" : \"storage\"];\n\t},\n\tasync save(key: IOdspTokenManagerCacheKey, tokens: IOdspTokens): Promise<void> {\n\t\tconst rc = await loadAndPatchRC();\n\t\tif (!rc.tokens) {\n\t\t\trc.tokens = {\n\t\t\t\tversion: 1,\n\t\t\t\tdata: {},\n\t\t\t};\n\t\t}\n\t\tlet prevTokens = rc.tokens.data[key.userOrServer];\n\t\tif (!prevTokens) {\n\t\t\tprevTokens = {};\n\t\t\trc.tokens.data[key.userOrServer] = prevTokens;\n\t\t}\n\t\tprevTokens[key.isPush ? \"push\" : \"storage\"] = tokens;\n\t\treturn saveRC(rc);\n\t},\n\tasync lock<T>(callback: () => Promise<T>): Promise<T> {\n\t\tconst release = await lockRC();\n\t\ttry {\n\t\t\treturn await callback();\n\t\t} finally {\n\t\t\tawait release();\n\t\t}\n\t},\n};\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/tool-utils";
8
- export declare const pkgVersion = "2.51.0";
8
+ export declare const pkgVersion = "2.53.0-350190";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,+BAA+B,CAAC;AACpD,eAAO,MAAM,UAAU,WAAW,CAAC"}
1
+ {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,+BAA+B,CAAC;AACpD,eAAO,MAAM,UAAU,kBAAkB,CAAC"}
@@ -8,5 +8,5 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.pkgVersion = exports.pkgName = void 0;
10
10
  exports.pkgName = "@fluidframework/tool-utils";
11
- exports.pkgVersion = "2.51.0";
11
+ exports.pkgVersion = "2.53.0-350190";
12
12
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,4BAA4B,CAAC;AACvC,QAAA,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/tool-utils\";\nexport const pkgVersion = \"2.51.0\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,4BAA4B,CAAC;AACvC,QAAA,UAAU,GAAG,eAAe,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/tool-utils\";\nexport const pkgVersion = \"2.53.0-350190\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"odspTokenManager.d.ts","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,mBAAmB,EACnB,WAAW,EAEX,MAAM,4CAA4C,CAAC;AAYpD,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAUhE;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAO,mBAQ3C,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,eAAe,GACxB;IACA,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAChB,GACD;IACA,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9D,CAAC;AAEL;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC9B;AAiBD;;GAEG;AACH,qBAAa,gBAAgB;IAK3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAJ7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;gBAExB,UAAU,CAAC,iEAAqD;IAGrE,iBAAiB,CAC7B,GAAG,EAAE,yBAAyB,EAC9B,KAAK,EAAE,WAAW,GAChB,OAAO,CAAC,IAAI,CAAC;YAMF,4BAA4B;IAU7B,aAAa,CACzB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,mBAAmB,EACjC,WAAW,EAAE,eAAe,EAC5B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;IAKV,aAAa,CACzB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,mBAAmB,EACjC,WAAW,EAAE,eAAe,EAC5B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;YAKT,iBAAiB;IAiB/B,OAAO,CAAC,MAAM,CAAC,WAAW;YAYZ,SAAS;YA0CT,aAAa;YAkEb,yBAAyB;YAezB,4BAA4B;YAuC5B,yBAAyB;IASvC,OAAO,CAAC,wBAAwB;CAWhC;AAaD;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,yBAAyB,EAAE,WAAW,CA6B/E,CAAC"}
1
+ {"version":3,"file":"odspTokenManager.d.ts","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,mBAAmB,EACnB,WAAW,EAEX,MAAM,4CAA4C,CAAC;AAWpD,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAUhE;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAO,mBAQ3C,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,eAAe,GACxB;IACA,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAChB,GACD;IACA,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9D,CAAC;AAEL;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC9B;AAsBD;;GAEG;AACH,qBAAa,gBAAgB;IAK3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAJ7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;gBAExB,UAAU,CAAC,iEAAqD;IAGrE,iBAAiB,CAC7B,GAAG,EAAE,yBAAyB,EAC9B,KAAK,EAAE,WAAW,GAChB,OAAO,CAAC,IAAI,CAAC;YAMF,4BAA4B;IAU7B,aAAa,CACzB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,mBAAmB,EACjC,WAAW,EAAE,eAAe,EAC5B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;IAKV,aAAa,CACzB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,mBAAmB,EACjC,WAAW,EAAE,eAAe,EAC5B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;YAKT,iBAAiB;IAiB/B,OAAO,CAAC,MAAM,CAAC,WAAW;YAYZ,SAAS;YA0CT,aAAa;YAyEb,yBAAyB;YAezB,4BAA4B;YAuC5B,yBAAyB;IASvC,OAAO,CAAC,wBAAwB;CAWhC;AAaD;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,yBAAyB,EAAE,WAAW,CA6B/E,CAAC"}
@@ -5,7 +5,6 @@
5
5
  import { unreachableCase } from "@fluidframework/core-utils/internal";
6
6
  import { fetchTokens, getLoginPageUrl, getOdspScope, pushScope, refreshTokens, } from "@fluidframework/odsp-doclib-utils/internal";
7
7
  import { Mutex } from "async-mutex";
8
- import { jwtDecode } from "jwt-decode";
9
8
  import { debug } from "./debug.js";
10
9
  import { loadRC, lockRC, saveRC } from "./fluidToolRc.js";
11
10
  import { endResponse, serverListenAndHandle } from "./httpHelpers.js";
@@ -26,14 +25,18 @@ export const getMicrosoftConfiguration = () => ({
26
25
  return process.env.login__microsoft__clientId;
27
26
  },
28
27
  });
29
- const isValidToken = (token) => {
28
+ const isValidAndNotExpiredToken = (tokens) => {
30
29
  // Return false for undefined or empty tokens.
31
- if (!token || token.length === 0) {
30
+ if (!tokens.accessToken || tokens.accessToken.length === 0) {
32
31
  return false;
33
32
  }
34
- const decodedToken = jwtDecode(token);
33
+ if (tokens.receivedAt === undefined || tokens.expiresIn === undefined) {
34
+ // If we don't have receivedAt or expiresIn, we treat the token as expired.
35
+ return false;
36
+ }
37
+ const expiresAt = tokens.receivedAt + tokens.expiresIn;
35
38
  // Give it a 60s buffer
36
- return decodedToken.exp - 60 >= Date.now() / 1000;
39
+ return expiresAt - 60 >= Date.now() / 1000;
37
40
  };
38
41
  const cacheKeyToString = (key) => {
39
42
  return `${key.userOrServer}${key.isPush ? "[Push]" : ""}`;
@@ -101,7 +104,7 @@ export class OdspTokenManager {
101
104
  const cacheKey = OdspTokenManager.getCacheKey(isPush, tokenConfig, server);
102
105
  const tokensFromCache = await this.getTokenFromCache(cacheKey);
103
106
  if (tokensFromCache) {
104
- if (isValidToken(tokensFromCache.accessToken)) {
107
+ if (isValidAndNotExpiredToken(tokensFromCache)) {
105
108
  debug(`${cacheKeyToString(cacheKey)}: Token reused from cache `);
106
109
  await this.onTokenRetrievalFromCache(tokenConfig, tokensFromCache);
107
110
  return tokensFromCache;
@@ -123,7 +126,7 @@ export class OdspTokenManager {
123
126
  // check the cache again under the lock (if it is there)
124
127
  const tokensFromCache = await this.getTokenFromCache(cacheKey);
125
128
  if (tokensFromCache) {
126
- if (forceRefresh || !isValidToken(tokensFromCache.accessToken)) {
129
+ if (forceRefresh || !isValidAndNotExpiredToken(tokensFromCache)) {
127
130
  try {
128
131
  // This updates the tokens in tokensFromCache
129
132
  tokens = await refreshTokens(server, scope, clientConfig, tokensFromCache);
@@ -156,6 +159,10 @@ export class OdspTokenManager {
156
159
  unreachableCase(tokenConfig);
157
160
  }
158
161
  }
162
+ if (!isValidAndNotExpiredToken(tokens)) {
163
+ throw new Error(`Acquired invalid tokens for ${cacheKeyToString(cacheKey)}. ` +
164
+ `Acquired token JSON: ${JSON.stringify(tokens)}`);
165
+ }
159
166
  await this.updateTokensCacheWithoutLock(cacheKey, tokens);
160
167
  return tokens;
161
168
  }
@@ -1 +1 @@
1
- {"version":3,"file":"odspTokenManager.js","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { unreachableCase } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIPublicClientConfig,\n\tIOdspTokens,\n\tTokenRequestCredentials,\n} from \"@fluidframework/odsp-doclib-utils/internal\";\nimport {\n\tfetchTokens,\n\tgetLoginPageUrl,\n\tgetOdspScope,\n\tpushScope,\n\trefreshTokens,\n} from \"@fluidframework/odsp-doclib-utils/internal\";\nimport { Mutex } from \"async-mutex\";\nimport { jwtDecode } from \"jwt-decode\";\n\nimport { debug } from \"./debug.js\";\nimport type { IAsyncCache, IResources } from \"./fluidToolRc.js\";\nimport { loadRC, lockRC, saveRC } from \"./fluidToolRc.js\";\nimport { endResponse, serverListenAndHandle } from \"./httpHelpers.js\";\n\nconst odspAuthRedirectPort = 7000;\nconst odspAuthRedirectOrigin = `http://localhost:${odspAuthRedirectPort}`;\nconst odspAuthRedirectUri = new URL(\"/auth/callback\", odspAuthRedirectOrigin).href;\n\n// TODO: Add documentation\n// eslint-disable-next-line jsdoc/require-description\n/**\n * @internal\n */\nexport const getMicrosoftConfiguration = (): IPublicClientConfig => ({\n\tget clientId(): string {\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\tif (!process.env.login__microsoft__clientId) {\n\t\t\tthrow new Error(\"Client ID environment variable not set: login__microsoft__clientId.\");\n\t\t}\n\t\treturn process.env.login__microsoft__clientId;\n\t},\n});\n\n/**\n * @internal\n */\nexport type OdspTokenConfig =\n\t| {\n\t\t\ttype: \"password\";\n\t\t\tusername: string;\n\t\t\tpassword: string;\n\t }\n\t| {\n\t\t\ttype: \"browserLogin\";\n\t\t\tnavigator: (url: string) => void;\n\t\t\tredirectUriCallback?: (tokens: IOdspTokens) => Promise<string>;\n\t };\n\n/**\n * @internal\n */\nexport interface IOdspTokenManagerCacheKey {\n\treadonly isPush: boolean;\n\treadonly userOrServer: string;\n}\n\nconst isValidToken = (token: string): boolean => {\n\t// Return false for undefined or empty tokens.\n\tif (!token || token.length === 0) {\n\t\treturn false;\n\t}\n\n\tconst decodedToken = jwtDecode<{ exp: number }>(token);\n\t// Give it a 60s buffer\n\treturn decodedToken.exp - 60 >= Date.now() / 1000;\n};\n\nconst cacheKeyToString = (key: IOdspTokenManagerCacheKey): string => {\n\treturn `${key.userOrServer}${key.isPush ? \"[Push]\" : \"\"}`;\n};\n\n/**\n * @internal\n */\nexport class OdspTokenManager {\n\tprivate readonly storageCache = new Map<string, IOdspTokens>();\n\tprivate readonly pushCache = new Map<string, IOdspTokens>();\n\tprivate readonly cacheMutex = new Mutex();\n\tpublic constructor(\n\t\tprivate readonly tokenCache?: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens>,\n\t) {}\n\n\tpublic async updateTokensCache(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tawait this.cacheMutex.runExclusive(async () => {\n\t\t\tawait this.updateTokensCacheWithoutLock(key, value);\n\t\t});\n\t}\n\n\tprivate async updateTokensCacheWithoutLock(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tdebug(`${cacheKeyToString(key)}: Saving tokens`);\n\t\tconst memoryCache = key.isPush ? this.pushCache : this.storageCache;\n\t\tmemoryCache.set(key.userOrServer, value);\n\t\tawait this.tokenCache?.save(key, value);\n\t}\n\n\tpublic async getOdspTokens(\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting odsp tokens\");\n\t\treturn this.getTokens(false, server, clientConfig, tokenConfig, forceRefresh, forceReauth);\n\t}\n\n\tpublic async getPushTokens(\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting push tokens\");\n\t\treturn this.getTokens(true, server, clientConfig, tokenConfig, forceRefresh, forceReauth);\n\t}\n\n\tprivate async getTokenFromCache(\n\t\tcacheKey: IOdspTokenManagerCacheKey,\n\t): Promise<IOdspTokens | undefined> {\n\t\tconst memoryCache = cacheKey.isPush ? this.pushCache : this.storageCache;\n\t\tconst memoryToken = memoryCache.get(cacheKey.userOrServer);\n\t\tif (memoryToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in memory `);\n\t\t\treturn memoryToken;\n\t\t}\n\t\tconst fileToken = await this.tokenCache?.get(cacheKey);\n\t\tif (fileToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in file`);\n\t\t\tmemoryCache.set(cacheKey.userOrServer, fileToken);\n\t\t\treturn fileToken;\n\t\t}\n\t}\n\n\tprivate static getCacheKey(\n\t\tisPush: boolean,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tserver: string,\n\t): IOdspTokenManagerCacheKey {\n\t\t// If we are using password, we should cache the token per user instead of per server\n\t\treturn {\n\t\t\tisPush,\n\t\t\tuserOrServer: tokenConfig.type === \"password\" ? tokenConfig.username : server,\n\t\t};\n\t}\n\n\tprivate async getTokens(\n\t\tisPush: boolean,\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst invokeGetTokensCore = async (): Promise<IOdspTokens> => {\n\t\t\t// Don't solely rely on tokenCache lock, ensure serialized execution of\n\t\t\t// cache update to avoid multiple fetch.\n\t\t\treturn this.cacheMutex.runExclusive(async () => {\n\t\t\t\treturn this.getTokensCore(\n\t\t\t\t\tisPush,\n\t\t\t\t\tserver,\n\t\t\t\t\tclientConfig,\n\t\t\t\t\ttokenConfig,\n\t\t\t\t\tforceRefresh,\n\t\t\t\t\tforceReauth,\n\t\t\t\t);\n\t\t\t});\n\t\t};\n\t\tif (!forceReauth && !forceRefresh) {\n\t\t\t// check and return if it exists without lock\n\t\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, tokenConfig, server);\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (isValidToken(tokensFromCache.accessToken)) {\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from cache `);\n\t\t\t\t\tawait this.onTokenRetrievalFromCache(tokenConfig, tokensFromCache);\n\t\t\t\t\treturn tokensFromCache;\n\t\t\t\t}\n\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token expired from cache `);\n\t\t\t}\n\t\t}\n\t\tif (this.tokenCache) {\n\t\t\t// check with lock, used to prevent concurrent auth attempts\n\t\t\treturn this.tokenCache.lock(invokeGetTokensCore);\n\t\t}\n\t\treturn invokeGetTokensCore();\n\t}\n\n\tprivate async getTokensCore(\n\t\tisPush: boolean,\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst scope = isPush ? pushScope : getOdspScope(server);\n\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, tokenConfig, server);\n\t\tlet tokens: IOdspTokens | undefined;\n\t\tif (!forceReauth) {\n\t\t\t// check the cache again under the lock (if it is there)\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (forceRefresh || !isValidToken(tokensFromCache.accessToken)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// This updates the tokens in tokensFromCache\n\t\t\t\t\t\ttokens = await refreshTokens(server, scope, clientConfig, tokensFromCache);\n\t\t\t\t\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Error in refreshing token. ${error}`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttokens = tokensFromCache;\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from locked cache `);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (tokens) {\n\t\t\tawait this.onTokenRetrievalFromCache(tokenConfig, tokens);\n\t\t\treturn tokens;\n\t\t}\n\n\t\tswitch (tokenConfig.type) {\n\t\t\tcase \"password\": {\n\t\t\t\ttokens = await this.acquireTokensWithPassword(\n\t\t\t\t\tserver,\n\t\t\t\t\tscope,\n\t\t\t\t\tclientConfig,\n\t\t\t\t\ttokenConfig.username,\n\t\t\t\t\ttokenConfig.password,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"browserLogin\": {\n\t\t\t\ttokens = await this.acquireTokensViaBrowserLogin(\n\t\t\t\t\tgetLoginPageUrl(server, clientConfig, scope, odspAuthRedirectUri),\n\t\t\t\t\tserver,\n\t\t\t\t\tclientConfig,\n\t\t\t\t\tscope,\n\t\t\t\t\ttokenConfig.navigator,\n\t\t\t\t\ttokenConfig.redirectUriCallback,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tunreachableCase(tokenConfig);\n\t\t\t}\n\t\t}\n\n\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\treturn tokens;\n\t}\n\n\tprivate async acquireTokensWithPassword(\n\t\tserver: string,\n\t\tscope: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\tusername: string,\n\t\tpassword: string,\n\t): Promise<IOdspTokens> {\n\t\tconst credentials: TokenRequestCredentials = {\n\t\t\tgrant_type: \"password\",\n\t\t\tusername,\n\t\t\tpassword,\n\t\t};\n\t\treturn fetchTokens(server, scope, clientConfig, credentials);\n\t}\n\n\tprivate async acquireTokensViaBrowserLogin(\n\t\tloginPageUrl: string,\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\tscope: string,\n\t\tnavigator: (url: string) => void,\n\t\tredirectUriCallback?: (tokens: IOdspTokens) => Promise<string>,\n\t): Promise<IOdspTokens> {\n\t\t// Start up a local auth redirect handler service to receive the tokens after login\n\t\tconst tokenGetter = await serverListenAndHandle(odspAuthRedirectPort, async (req, res) => {\n\t\t\t// extract code from request URL and fetch the tokens\n\t\t\tconst credentials: TokenRequestCredentials = {\n\t\t\t\tgrant_type: \"authorization_code\",\n\t\t\t\tcode: this.extractAuthorizationCode(req.url),\n\t\t\t\tredirect_uri: odspAuthRedirectUri,\n\t\t\t};\n\t\t\tconst tokens = await fetchTokens(server, scope, clientConfig, credentials);\n\n\t\t\t// redirect now that the browser is done with auth\n\t\t\tif (redirectUriCallback) {\n\t\t\t\tres.writeHead(301, { Location: await redirectUriCallback(tokens) });\n\t\t\t\tawait endResponse(res);\n\t\t\t} else {\n\t\t\t\tres.write(\"Please close the window\");\n\t\t\t\tawait endResponse(res);\n\t\t\t}\n\n\t\t\treturn tokens;\n\t\t});\n\n\t\t// Now that our local redirect handler is up, navigate the browser to the login page\n\t\tnavigator(loginPageUrl);\n\n\t\t// Receive and extract the tokens\n\t\tconst odspTokens = await tokenGetter();\n\n\t\treturn odspTokens;\n\t}\n\n\tprivate async onTokenRetrievalFromCache(\n\t\tconfig: OdspTokenConfig,\n\t\ttokens: IOdspTokens,\n\t): Promise<void> {\n\t\tif (config.type === \"browserLogin\" && config.redirectUriCallback) {\n\t\t\tconfig.navigator(await config.redirectUriCallback(tokens));\n\t\t}\n\t}\n\n\tprivate extractAuthorizationCode(relativeUrl: string | undefined): string {\n\t\tif (relativeUrl === undefined) {\n\t\t\tthrow new Error(\"Failed to get authorization\");\n\t\t}\n\t\tconst parsedUrl = new URL(relativeUrl, odspAuthRedirectOrigin);\n\t\tconst code = parsedUrl.searchParams.get(\"code\");\n\t\tif (code === null || code === undefined) {\n\t\t\tthrow new Error(\"Failed to get authorization\");\n\t\t}\n\t\treturn code;\n\t}\n}\n\nasync function loadAndPatchRC(): Promise<IResources> {\n\tconst rc = await loadRC();\n\tif (rc.tokens && rc.tokens.version === undefined) {\n\t\t// Clean up older versions\n\t\tdelete rc.tokens;\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\tdelete (rc as any).pushTokens;\n\t}\n\treturn rc;\n}\n\n/**\n * @internal\n */\nexport const odspTokensCache: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens> = {\n\tasync get(key: IOdspTokenManagerCacheKey): Promise<IOdspTokens | undefined> {\n\t\tconst rc = await loadAndPatchRC();\n\t\treturn rc.tokens?.data[key.userOrServer]?.[key.isPush ? \"push\" : \"storage\"];\n\t},\n\tasync save(key: IOdspTokenManagerCacheKey, tokens: IOdspTokens): Promise<void> {\n\t\tconst rc = await loadAndPatchRC();\n\t\tif (!rc.tokens) {\n\t\t\trc.tokens = {\n\t\t\t\tversion: 1,\n\t\t\t\tdata: {},\n\t\t\t};\n\t\t}\n\t\tlet prevTokens = rc.tokens.data[key.userOrServer];\n\t\tif (!prevTokens) {\n\t\t\tprevTokens = {};\n\t\t\trc.tokens.data[key.userOrServer] = prevTokens;\n\t\t}\n\t\tprevTokens[key.isPush ? \"push\" : \"storage\"] = tokens;\n\t\treturn saveRC(rc);\n\t},\n\tasync lock<T>(callback: () => Promise<T>): Promise<T> {\n\t\tconst release = await lockRC();\n\t\ttry {\n\t\t\treturn await callback();\n\t\t} finally {\n\t\t\tawait release();\n\t\t}\n\t},\n};\n"]}
1
+ {"version":3,"file":"odspTokenManager.js","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAMtE,OAAO,EACN,WAAW,EACX,eAAe,EACf,YAAY,EACZ,SAAS,EACT,aAAa,GACb,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEtE,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAClC,MAAM,sBAAsB,GAAG,oBAAoB,oBAAoB,EAAE,CAAC;AAC1E,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,gBAAgB,EAAE,sBAAsB,CAAC,CAAC,IAAI,CAAC;AAEnF,0BAA0B;AAC1B,qDAAqD;AACrD;;GAEG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAwB,EAAE,CAAC,CAAC;IACpE,IAAI,QAAQ;QACX,yEAAyE;QACzE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;QACxF,CAAC;QACD,OAAO,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;IAC/C,CAAC;CACD,CAAC,CAAC;AAyBH,MAAM,yBAAyB,GAAG,CAAC,MAAmB,EAAW,EAAE;IAClE,8CAA8C;IAC9C,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5D,OAAO,KAAK,CAAC;IACd,CAAC;IAED,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACvE,2EAA2E;QAC3E,OAAO,KAAK,CAAC;IACd,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,SAAS,CAAC;IACvD,uBAAuB;IACvB,OAAO,SAAS,GAAG,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAC5C,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,GAA8B,EAAU,EAAE;IACnE,OAAO,GAAG,GAAG,CAAC,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAC3D,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,OAAO,gBAAgB;IAI5B,YACkB,UAAgE;QAAhE,eAAU,GAAV,UAAU,CAAsD;QAJjE,iBAAY,GAAG,IAAI,GAAG,EAAuB,CAAC;QAC9C,cAAS,GAAG,IAAI,GAAG,EAAuB,CAAC;QAC3C,eAAU,GAAG,IAAI,KAAK,EAAE,CAAC;IAGvC,CAAC;IAEG,KAAK,CAAC,iBAAiB,CAC7B,GAA8B,EAC9B,KAAkB;QAElB,MAAM,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE;YAC7C,MAAM,IAAI,CAAC,4BAA4B,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,4BAA4B,CACzC,GAA8B,EAC9B,KAAkB;QAElB,KAAK,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QACjD,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;QACpE,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;QACzC,MAAM,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACzC,CAAC;IAEM,KAAK,CAAC,aAAa,CACzB,MAAc,EACd,YAAiC,EACjC,WAA4B,EAC5B,YAAY,GAAG,KAAK,EACpB,WAAW,GAAG,KAAK;QAEnB,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;IAC5F,CAAC;IAEM,KAAK,CAAC,aAAa,CACzB,MAAc,EACd,YAAiC,EACjC,WAA4B,EAC5B,YAAY,GAAG,KAAK,EACpB,WAAW,GAAG,KAAK;QAEnB,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;IAC3F,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAC9B,QAAmC;QAEnC,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;QACzE,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC3D,IAAI,WAAW,EAAE,CAAC;YACjB,KAAK,CAAC,GAAG,gBAAgB,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAAC;YAC/D,OAAO,WAAW,CAAC;QACpB,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QACvD,IAAI,SAAS,EAAE,CAAC;YACf,KAAK,CAAC,GAAG,gBAAgB,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC;YAC5D,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;YAClD,OAAO,SAAS,CAAC;QAClB,CAAC;IACF,CAAC;IAEO,MAAM,CAAC,WAAW,CACzB,MAAe,EACf,WAA4B,EAC5B,MAAc;QAEd,qFAAqF;QACrF,OAAO;YACN,MAAM;YACN,YAAY,EAAE,WAAW,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM;SAC7E,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,SAAS,CACtB,MAAe,EACf,MAAc,EACd,YAAiC,EACjC,WAA4B,EAC5B,YAAqB,EACrB,WAAoB;QAEpB,MAAM,mBAAmB,GAAG,KAAK,IAA0B,EAAE;YAC5D,uEAAuE;YACvE,wCAAwC;YACxC,OAAO,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE;gBAC9C,OAAO,IAAI,CAAC,aAAa,CACxB,MAAM,EACN,MAAM,EACN,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,WAAW,CACX,CAAC;YACH,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC;QACF,IAAI,CAAC,WAAW,IAAI,CAAC,YAAY,EAAE,CAAC;YACnC,6CAA6C;YAC7C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;YAC3E,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YAC/D,IAAI,eAAe,EAAE,CAAC;gBACrB,IAAI,yBAAyB,CAAC,eAAe,CAAC,EAAE,CAAC;oBAChD,KAAK,CAAC,GAAG,gBAAgB,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;oBACjE,MAAM,IAAI,CAAC,yBAAyB,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;oBACnE,OAAO,eAAe,CAAC;gBACxB,CAAC;gBACD,KAAK,CAAC,GAAG,gBAAgB,CAAC,QAAQ,CAAC,6BAA6B,CAAC,CAAC;YACnE,CAAC;QACF,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,4DAA4D;YAC5D,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAClD,CAAC;QACD,OAAO,mBAAmB,EAAE,CAAC;IAC9B,CAAC;IAEO,KAAK,CAAC,aAAa,CAC1B,MAAe,EACf,MAAc,EACd,YAAiC,EACjC,WAA4B,EAC5B,YAAqB,EACrB,WAAoB;QAEpB,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACxD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;QAC3E,IAAI,MAA+B,CAAC;QACpC,IAAI,CAAC,WAAW,EAAE,CAAC;YAClB,wDAAwD;YACxD,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YAC/D,IAAI,eAAe,EAAE,CAAC;gBACrB,IAAI,YAAY,IAAI,CAAC,yBAAyB,CAAC,eAAe,CAAC,EAAE,CAAC;oBACjE,IAAI,CAAC;wBACJ,6CAA6C;wBAC7C,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC;wBAC3E,MAAM,IAAI,CAAC,4BAA4B,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;oBAC3D,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBAChB,KAAK,CAAC,GAAG,gBAAgB,CAAC,QAAQ,CAAC,gCAAgC,KAAK,EAAE,CAAC,CAAC;oBAC7E,CAAC;gBACF,CAAC;qBAAM,CAAC;oBACP,MAAM,GAAG,eAAe,CAAC;oBACzB,KAAK,CAAC,GAAG,gBAAgB,CAAC,QAAQ,CAAC,mCAAmC,CAAC,CAAC;gBACzE,CAAC;YACF,CAAC;QACF,CAAC;QAED,IAAI,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,CAAC,yBAAyB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;YAC1D,OAAO,MAAM,CAAC;QACf,CAAC;QAED,QAAQ,WAAW,CAAC,IAAI,EAAE,CAAC;YAC1B,KAAK,UAAU,CAAC,CAAC,CAAC;gBACjB,MAAM,GAAG,MAAM,IAAI,CAAC,yBAAyB,CAC5C,MAAM,EACN,KAAK,EACL,YAAY,EACZ,WAAW,CAAC,QAAQ,EACpB,WAAW,CAAC,QAAQ,CACpB,CAAC;gBACF,MAAM;YACP,CAAC;YACD,KAAK,cAAc,CAAC,CAAC,CAAC;gBACrB,MAAM,GAAG,MAAM,IAAI,CAAC,4BAA4B,CAC/C,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,mBAAmB,CAAC,EACjE,MAAM,EACN,YAAY,EACZ,KAAK,EACL,WAAW,CAAC,SAAS,EACrB,WAAW,CAAC,mBAAmB,CAC/B,CAAC;gBACF,MAAM;YACP,CAAC;YACD,OAAO,CAAC,CAAC,CAAC;gBACT,eAAe,CAAC,WAAW,CAAC,CAAC;YAC9B,CAAC;QACF,CAAC;QAED,IAAI,CAAC,yBAAyB,CAAC,MAAM,CAAC,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CACd,+BAA+B,gBAAgB,CAAC,QAAQ,CAAC,IAAI;gBAC5D,wBAAwB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CACjD,CAAC;QACH,CAAC;QAED,MAAM,IAAI,CAAC,4BAA4B,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC1D,OAAO,MAAM,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,yBAAyB,CACtC,MAAc,EACd,KAAa,EACb,YAAiC,EACjC,QAAgB,EAChB,QAAgB;QAEhB,MAAM,WAAW,GAA4B;YAC5C,UAAU,EAAE,UAAU;YACtB,QAAQ;YACR,QAAQ;SACR,CAAC;QACF,OAAO,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;IAC9D,CAAC;IAEO,KAAK,CAAC,4BAA4B,CACzC,YAAoB,EACpB,MAAc,EACd,YAAiC,EACjC,KAAa,EACb,SAAgC,EAChC,mBAA8D;QAE9D,mFAAmF;QACnF,MAAM,WAAW,GAAG,MAAM,qBAAqB,CAAC,oBAAoB,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;YACxF,qDAAqD;YACrD,MAAM,WAAW,GAA4B;gBAC5C,UAAU,EAAE,oBAAoB;gBAChC,IAAI,EAAE,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,GAAG,CAAC;gBAC5C,YAAY,EAAE,mBAAmB;aACjC,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;YAE3E,kDAAkD;YAClD,IAAI,mBAAmB,EAAE,CAAC;gBACzB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACpE,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACP,GAAG,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;gBACrC,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;YACxB,CAAC;YAED,OAAO,MAAM,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,oFAAoF;QACpF,SAAS,CAAC,YAAY,CAAC,CAAC;QAExB,iCAAiC;QACjC,MAAM,UAAU,GAAG,MAAM,WAAW,EAAE,CAAC;QAEvC,OAAO,UAAU,CAAC;IACnB,CAAC;IAEO,KAAK,CAAC,yBAAyB,CACtC,MAAuB,EACvB,MAAmB;QAEnB,IAAI,MAAM,CAAC,IAAI,KAAK,cAAc,IAAI,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAClE,MAAM,CAAC,SAAS,CAAC,MAAM,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC;QAC5D,CAAC;IACF,CAAC;IAEO,wBAAwB,CAAC,WAA+B;QAC/D,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAChD,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE,sBAAsB,CAAC,CAAC;QAC/D,MAAM,IAAI,GAAG,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;CACD;AAED,KAAK,UAAU,cAAc;IAC5B,MAAM,EAAE,GAAG,MAAM,MAAM,EAAE,CAAC;IAC1B,IAAI,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAClD,0BAA0B;QAC1B,OAAO,EAAE,CAAC,MAAM,CAAC;QACjB,0GAA0G;QAC1G,OAAQ,EAAU,CAAC,UAAU,CAAC;IAC/B,CAAC;IACD,OAAO,EAAE,CAAC;AACX,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAwD;IACnF,KAAK,CAAC,GAAG,CAAC,GAA8B;QACvC,MAAM,EAAE,GAAG,MAAM,cAAc,EAAE,CAAC;QAClC,OAAO,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC7E,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,GAA8B,EAAE,MAAmB;QAC7D,MAAM,EAAE,GAAG,MAAM,cAAc,EAAE,CAAC;QAClC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC;YAChB,EAAE,CAAC,MAAM,GAAG;gBACX,OAAO,EAAE,CAAC;gBACV,IAAI,EAAE,EAAE;aACR,CAAC;QACH,CAAC;QACD,IAAI,UAAU,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAClD,IAAI,CAAC,UAAU,EAAE,CAAC;YACjB,UAAU,GAAG,EAAE,CAAC;YAChB,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,UAAU,CAAC;QAC/C,CAAC;QACD,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC;QACrD,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC;IACD,KAAK,CAAC,IAAI,CAAI,QAA0B;QACvC,MAAM,OAAO,GAAG,MAAM,MAAM,EAAE,CAAC;QAC/B,IAAI,CAAC;YACJ,OAAO,MAAM,QAAQ,EAAE,CAAC;QACzB,CAAC;gBAAS,CAAC;YACV,MAAM,OAAO,EAAE,CAAC;QACjB,CAAC;IACF,CAAC;CACD,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { unreachableCase } from \"@fluidframework/core-utils/internal\";\nimport type {\n\tIPublicClientConfig,\n\tIOdspTokens,\n\tTokenRequestCredentials,\n} from \"@fluidframework/odsp-doclib-utils/internal\";\nimport {\n\tfetchTokens,\n\tgetLoginPageUrl,\n\tgetOdspScope,\n\tpushScope,\n\trefreshTokens,\n} from \"@fluidframework/odsp-doclib-utils/internal\";\nimport { Mutex } from \"async-mutex\";\n\nimport { debug } from \"./debug.js\";\nimport type { IAsyncCache, IResources } from \"./fluidToolRc.js\";\nimport { loadRC, lockRC, saveRC } from \"./fluidToolRc.js\";\nimport { endResponse, serverListenAndHandle } from \"./httpHelpers.js\";\n\nconst odspAuthRedirectPort = 7000;\nconst odspAuthRedirectOrigin = `http://localhost:${odspAuthRedirectPort}`;\nconst odspAuthRedirectUri = new URL(\"/auth/callback\", odspAuthRedirectOrigin).href;\n\n// TODO: Add documentation\n// eslint-disable-next-line jsdoc/require-description\n/**\n * @internal\n */\nexport const getMicrosoftConfiguration = (): IPublicClientConfig => ({\n\tget clientId(): string {\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\tif (!process.env.login__microsoft__clientId) {\n\t\t\tthrow new Error(\"Client ID environment variable not set: login__microsoft__clientId.\");\n\t\t}\n\t\treturn process.env.login__microsoft__clientId;\n\t},\n});\n\n/**\n * @internal\n */\nexport type OdspTokenConfig =\n\t| {\n\t\t\ttype: \"password\";\n\t\t\tusername: string;\n\t\t\tpassword: string;\n\t }\n\t| {\n\t\t\ttype: \"browserLogin\";\n\t\t\tnavigator: (url: string) => void;\n\t\t\tredirectUriCallback?: (tokens: IOdspTokens) => Promise<string>;\n\t };\n\n/**\n * @internal\n */\nexport interface IOdspTokenManagerCacheKey {\n\treadonly isPush: boolean;\n\treadonly userOrServer: string;\n}\n\nconst isValidAndNotExpiredToken = (tokens: IOdspTokens): boolean => {\n\t// Return false for undefined or empty tokens.\n\tif (!tokens.accessToken || tokens.accessToken.length === 0) {\n\t\treturn false;\n\t}\n\n\tif (tokens.receivedAt === undefined || tokens.expiresIn === undefined) {\n\t\t// If we don't have receivedAt or expiresIn, we treat the token as expired.\n\t\treturn false;\n\t}\n\n\tconst expiresAt = tokens.receivedAt + tokens.expiresIn;\n\t// Give it a 60s buffer\n\treturn expiresAt - 60 >= Date.now() / 1000;\n};\n\nconst cacheKeyToString = (key: IOdspTokenManagerCacheKey): string => {\n\treturn `${key.userOrServer}${key.isPush ? \"[Push]\" : \"\"}`;\n};\n\n/**\n * @internal\n */\nexport class OdspTokenManager {\n\tprivate readonly storageCache = new Map<string, IOdspTokens>();\n\tprivate readonly pushCache = new Map<string, IOdspTokens>();\n\tprivate readonly cacheMutex = new Mutex();\n\tpublic constructor(\n\t\tprivate readonly tokenCache?: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens>,\n\t) {}\n\n\tpublic async updateTokensCache(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tawait this.cacheMutex.runExclusive(async () => {\n\t\t\tawait this.updateTokensCacheWithoutLock(key, value);\n\t\t});\n\t}\n\n\tprivate async updateTokensCacheWithoutLock(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tdebug(`${cacheKeyToString(key)}: Saving tokens`);\n\t\tconst memoryCache = key.isPush ? this.pushCache : this.storageCache;\n\t\tmemoryCache.set(key.userOrServer, value);\n\t\tawait this.tokenCache?.save(key, value);\n\t}\n\n\tpublic async getOdspTokens(\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting odsp tokens\");\n\t\treturn this.getTokens(false, server, clientConfig, tokenConfig, forceRefresh, forceReauth);\n\t}\n\n\tpublic async getPushTokens(\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting push tokens\");\n\t\treturn this.getTokens(true, server, clientConfig, tokenConfig, forceRefresh, forceReauth);\n\t}\n\n\tprivate async getTokenFromCache(\n\t\tcacheKey: IOdspTokenManagerCacheKey,\n\t): Promise<IOdspTokens | undefined> {\n\t\tconst memoryCache = cacheKey.isPush ? this.pushCache : this.storageCache;\n\t\tconst memoryToken = memoryCache.get(cacheKey.userOrServer);\n\t\tif (memoryToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in memory `);\n\t\t\treturn memoryToken;\n\t\t}\n\t\tconst fileToken = await this.tokenCache?.get(cacheKey);\n\t\tif (fileToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in file`);\n\t\t\tmemoryCache.set(cacheKey.userOrServer, fileToken);\n\t\t\treturn fileToken;\n\t\t}\n\t}\n\n\tprivate static getCacheKey(\n\t\tisPush: boolean,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tserver: string,\n\t): IOdspTokenManagerCacheKey {\n\t\t// If we are using password, we should cache the token per user instead of per server\n\t\treturn {\n\t\t\tisPush,\n\t\t\tuserOrServer: tokenConfig.type === \"password\" ? tokenConfig.username : server,\n\t\t};\n\t}\n\n\tprivate async getTokens(\n\t\tisPush: boolean,\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst invokeGetTokensCore = async (): Promise<IOdspTokens> => {\n\t\t\t// Don't solely rely on tokenCache lock, ensure serialized execution of\n\t\t\t// cache update to avoid multiple fetch.\n\t\t\treturn this.cacheMutex.runExclusive(async () => {\n\t\t\t\treturn this.getTokensCore(\n\t\t\t\t\tisPush,\n\t\t\t\t\tserver,\n\t\t\t\t\tclientConfig,\n\t\t\t\t\ttokenConfig,\n\t\t\t\t\tforceRefresh,\n\t\t\t\t\tforceReauth,\n\t\t\t\t);\n\t\t\t});\n\t\t};\n\t\tif (!forceReauth && !forceRefresh) {\n\t\t\t// check and return if it exists without lock\n\t\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, tokenConfig, server);\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (isValidAndNotExpiredToken(tokensFromCache)) {\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from cache `);\n\t\t\t\t\tawait this.onTokenRetrievalFromCache(tokenConfig, tokensFromCache);\n\t\t\t\t\treturn tokensFromCache;\n\t\t\t\t}\n\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token expired from cache `);\n\t\t\t}\n\t\t}\n\t\tif (this.tokenCache) {\n\t\t\t// check with lock, used to prevent concurrent auth attempts\n\t\t\treturn this.tokenCache.lock(invokeGetTokensCore);\n\t\t}\n\t\treturn invokeGetTokensCore();\n\t}\n\n\tprivate async getTokensCore(\n\t\tisPush: boolean,\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\ttokenConfig: OdspTokenConfig,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst scope = isPush ? pushScope : getOdspScope(server);\n\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, tokenConfig, server);\n\t\tlet tokens: IOdspTokens | undefined;\n\t\tif (!forceReauth) {\n\t\t\t// check the cache again under the lock (if it is there)\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (forceRefresh || !isValidAndNotExpiredToken(tokensFromCache)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// This updates the tokens in tokensFromCache\n\t\t\t\t\t\ttokens = await refreshTokens(server, scope, clientConfig, tokensFromCache);\n\t\t\t\t\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Error in refreshing token. ${error}`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttokens = tokensFromCache;\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from locked cache `);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (tokens) {\n\t\t\tawait this.onTokenRetrievalFromCache(tokenConfig, tokens);\n\t\t\treturn tokens;\n\t\t}\n\n\t\tswitch (tokenConfig.type) {\n\t\t\tcase \"password\": {\n\t\t\t\ttokens = await this.acquireTokensWithPassword(\n\t\t\t\t\tserver,\n\t\t\t\t\tscope,\n\t\t\t\t\tclientConfig,\n\t\t\t\t\ttokenConfig.username,\n\t\t\t\t\ttokenConfig.password,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"browserLogin\": {\n\t\t\t\ttokens = await this.acquireTokensViaBrowserLogin(\n\t\t\t\t\tgetLoginPageUrl(server, clientConfig, scope, odspAuthRedirectUri),\n\t\t\t\t\tserver,\n\t\t\t\t\tclientConfig,\n\t\t\t\t\tscope,\n\t\t\t\t\ttokenConfig.navigator,\n\t\t\t\t\ttokenConfig.redirectUriCallback,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tunreachableCase(tokenConfig);\n\t\t\t}\n\t\t}\n\n\t\tif (!isValidAndNotExpiredToken(tokens)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Acquired invalid tokens for ${cacheKeyToString(cacheKey)}. ` +\n\t\t\t\t\t`Acquired token JSON: ${JSON.stringify(tokens)}`,\n\t\t\t);\n\t\t}\n\n\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\treturn tokens;\n\t}\n\n\tprivate async acquireTokensWithPassword(\n\t\tserver: string,\n\t\tscope: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\tusername: string,\n\t\tpassword: string,\n\t): Promise<IOdspTokens> {\n\t\tconst credentials: TokenRequestCredentials = {\n\t\t\tgrant_type: \"password\",\n\t\t\tusername,\n\t\t\tpassword,\n\t\t};\n\t\treturn fetchTokens(server, scope, clientConfig, credentials);\n\t}\n\n\tprivate async acquireTokensViaBrowserLogin(\n\t\tloginPageUrl: string,\n\t\tserver: string,\n\t\tclientConfig: IPublicClientConfig,\n\t\tscope: string,\n\t\tnavigator: (url: string) => void,\n\t\tredirectUriCallback?: (tokens: IOdspTokens) => Promise<string>,\n\t): Promise<IOdspTokens> {\n\t\t// Start up a local auth redirect handler service to receive the tokens after login\n\t\tconst tokenGetter = await serverListenAndHandle(odspAuthRedirectPort, async (req, res) => {\n\t\t\t// extract code from request URL and fetch the tokens\n\t\t\tconst credentials: TokenRequestCredentials = {\n\t\t\t\tgrant_type: \"authorization_code\",\n\t\t\t\tcode: this.extractAuthorizationCode(req.url),\n\t\t\t\tredirect_uri: odspAuthRedirectUri,\n\t\t\t};\n\t\t\tconst tokens = await fetchTokens(server, scope, clientConfig, credentials);\n\n\t\t\t// redirect now that the browser is done with auth\n\t\t\tif (redirectUriCallback) {\n\t\t\t\tres.writeHead(301, { Location: await redirectUriCallback(tokens) });\n\t\t\t\tawait endResponse(res);\n\t\t\t} else {\n\t\t\t\tres.write(\"Please close the window\");\n\t\t\t\tawait endResponse(res);\n\t\t\t}\n\n\t\t\treturn tokens;\n\t\t});\n\n\t\t// Now that our local redirect handler is up, navigate the browser to the login page\n\t\tnavigator(loginPageUrl);\n\n\t\t// Receive and extract the tokens\n\t\tconst odspTokens = await tokenGetter();\n\n\t\treturn odspTokens;\n\t}\n\n\tprivate async onTokenRetrievalFromCache(\n\t\tconfig: OdspTokenConfig,\n\t\ttokens: IOdspTokens,\n\t): Promise<void> {\n\t\tif (config.type === \"browserLogin\" && config.redirectUriCallback) {\n\t\t\tconfig.navigator(await config.redirectUriCallback(tokens));\n\t\t}\n\t}\n\n\tprivate extractAuthorizationCode(relativeUrl: string | undefined): string {\n\t\tif (relativeUrl === undefined) {\n\t\t\tthrow new Error(\"Failed to get authorization\");\n\t\t}\n\t\tconst parsedUrl = new URL(relativeUrl, odspAuthRedirectOrigin);\n\t\tconst code = parsedUrl.searchParams.get(\"code\");\n\t\tif (code === null || code === undefined) {\n\t\t\tthrow new Error(\"Failed to get authorization\");\n\t\t}\n\t\treturn code;\n\t}\n}\n\nasync function loadAndPatchRC(): Promise<IResources> {\n\tconst rc = await loadRC();\n\tif (rc.tokens && rc.tokens.version === undefined) {\n\t\t// Clean up older versions\n\t\tdelete rc.tokens;\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\tdelete (rc as any).pushTokens;\n\t}\n\treturn rc;\n}\n\n/**\n * @internal\n */\nexport const odspTokensCache: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens> = {\n\tasync get(key: IOdspTokenManagerCacheKey): Promise<IOdspTokens | undefined> {\n\t\tconst rc = await loadAndPatchRC();\n\t\treturn rc.tokens?.data[key.userOrServer]?.[key.isPush ? \"push\" : \"storage\"];\n\t},\n\tasync save(key: IOdspTokenManagerCacheKey, tokens: IOdspTokens): Promise<void> {\n\t\tconst rc = await loadAndPatchRC();\n\t\tif (!rc.tokens) {\n\t\t\trc.tokens = {\n\t\t\t\tversion: 1,\n\t\t\t\tdata: {},\n\t\t\t};\n\t\t}\n\t\tlet prevTokens = rc.tokens.data[key.userOrServer];\n\t\tif (!prevTokens) {\n\t\t\tprevTokens = {};\n\t\t\trc.tokens.data[key.userOrServer] = prevTokens;\n\t\t}\n\t\tprevTokens[key.isPush ? \"push\" : \"storage\"] = tokens;\n\t\treturn saveRC(rc);\n\t},\n\tasync lock<T>(callback: () => Promise<T>): Promise<T> {\n\t\tconst release = await lockRC();\n\t\ttry {\n\t\t\treturn await callback();\n\t\t} finally {\n\t\t\tawait release();\n\t\t}\n\t},\n};\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/tool-utils";
8
- export declare const pkgVersion = "2.51.0";
8
+ export declare const pkgVersion = "2.53.0-350190";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,+BAA+B,CAAC;AACpD,eAAO,MAAM,UAAU,WAAW,CAAC"}
1
+ {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,+BAA+B,CAAC;AACpD,eAAO,MAAM,UAAU,kBAAkB,CAAC"}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/tool-utils";
8
- export const pkgVersion = "2.51.0";
8
+ export const pkgVersion = "2.53.0-350190";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,4BAA4B,CAAC;AACpD,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/tool-utils\";\nexport const pkgVersion = \"2.51.0\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,4BAA4B,CAAC;AACpD,MAAM,CAAC,MAAM,UAAU,GAAG,eAAe,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/tool-utils\";\nexport const pkgVersion = \"2.53.0-350190\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/tool-utils",
3
- "version": "2.51.0",
3
+ "version": "2.53.0-350190",
4
4
  "description": "Common utilities for Fluid tools",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -59,24 +59,23 @@
59
59
  "temp-directory": "nyc/.nyc_output"
60
60
  },
61
61
  "dependencies": {
62
- "@fluidframework/core-utils": "~2.51.0",
63
- "@fluidframework/driver-definitions": "~2.51.0",
64
- "@fluidframework/driver-utils": "~2.51.0",
65
- "@fluidframework/odsp-doclib-utils": "~2.51.0",
62
+ "@fluidframework/core-utils": "2.53.0-350190",
63
+ "@fluidframework/driver-definitions": "2.53.0-350190",
64
+ "@fluidframework/driver-utils": "2.53.0-350190",
65
+ "@fluidframework/odsp-doclib-utils": "2.53.0-350190",
66
66
  "async-mutex": "^0.3.1",
67
67
  "debug": "^4.3.4",
68
- "jwt-decode": "^4.0.0",
69
68
  "proper-lockfile": "^4.1.2"
70
69
  },
71
70
  "devDependencies": {
72
71
  "@arethetypeswrong/cli": "^0.17.1",
73
72
  "@biomejs/biome": "~1.9.3",
74
- "@fluid-internal/mocha-test-setup": "~2.51.0",
75
- "@fluid-tools/build-cli": "^0.56.0",
73
+ "@fluid-internal/mocha-test-setup": "2.53.0-350190",
74
+ "@fluid-tools/build-cli": "^0.57.0",
76
75
  "@fluidframework/build-common": "^2.0.3",
77
- "@fluidframework/build-tools": "^0.56.0",
76
+ "@fluidframework/build-tools": "^0.57.0",
78
77
  "@fluidframework/eslint-config-fluid": "^5.7.4",
79
- "@fluidframework/tool-utils-previous": "npm:@fluidframework/tool-utils@2.50.0",
78
+ "@fluidframework/tool-utils-previous": "npm:@fluidframework/tool-utils@2.52.0",
80
79
  "@microsoft/api-extractor": "7.52.8",
81
80
  "@types/debug": "^4.1.5",
82
81
  "@types/mocha": "^10.0.10",
@@ -17,7 +17,6 @@ import {
17
17
  refreshTokens,
18
18
  } from "@fluidframework/odsp-doclib-utils/internal";
19
19
  import { Mutex } from "async-mutex";
20
- import { jwtDecode } from "jwt-decode";
21
20
 
22
21
  import { debug } from "./debug.js";
23
22
  import type { IAsyncCache, IResources } from "./fluidToolRc.js";
@@ -66,15 +65,20 @@ export interface IOdspTokenManagerCacheKey {
66
65
  readonly userOrServer: string;
67
66
  }
68
67
 
69
- const isValidToken = (token: string): boolean => {
68
+ const isValidAndNotExpiredToken = (tokens: IOdspTokens): boolean => {
70
69
  // Return false for undefined or empty tokens.
71
- if (!token || token.length === 0) {
70
+ if (!tokens.accessToken || tokens.accessToken.length === 0) {
72
71
  return false;
73
72
  }
74
73
 
75
- const decodedToken = jwtDecode<{ exp: number }>(token);
74
+ if (tokens.receivedAt === undefined || tokens.expiresIn === undefined) {
75
+ // If we don't have receivedAt or expiresIn, we treat the token as expired.
76
+ return false;
77
+ }
78
+
79
+ const expiresAt = tokens.receivedAt + tokens.expiresIn;
76
80
  // Give it a 60s buffer
77
- return decodedToken.exp - 60 >= Date.now() / 1000;
81
+ return expiresAt - 60 >= Date.now() / 1000;
78
82
  };
79
83
 
80
84
  const cacheKeyToString = (key: IOdspTokenManagerCacheKey): string => {
@@ -189,7 +193,7 @@ export class OdspTokenManager {
189
193
  const cacheKey = OdspTokenManager.getCacheKey(isPush, tokenConfig, server);
190
194
  const tokensFromCache = await this.getTokenFromCache(cacheKey);
191
195
  if (tokensFromCache) {
192
- if (isValidToken(tokensFromCache.accessToken)) {
196
+ if (isValidAndNotExpiredToken(tokensFromCache)) {
193
197
  debug(`${cacheKeyToString(cacheKey)}: Token reused from cache `);
194
198
  await this.onTokenRetrievalFromCache(tokenConfig, tokensFromCache);
195
199
  return tokensFromCache;
@@ -219,7 +223,7 @@ export class OdspTokenManager {
219
223
  // check the cache again under the lock (if it is there)
220
224
  const tokensFromCache = await this.getTokenFromCache(cacheKey);
221
225
  if (tokensFromCache) {
222
- if (forceRefresh || !isValidToken(tokensFromCache.accessToken)) {
226
+ if (forceRefresh || !isValidAndNotExpiredToken(tokensFromCache)) {
223
227
  try {
224
228
  // This updates the tokens in tokensFromCache
225
229
  tokens = await refreshTokens(server, scope, clientConfig, tokensFromCache);
@@ -266,6 +270,13 @@ export class OdspTokenManager {
266
270
  }
267
271
  }
268
272
 
273
+ if (!isValidAndNotExpiredToken(tokens)) {
274
+ throw new Error(
275
+ `Acquired invalid tokens for ${cacheKeyToString(cacheKey)}. ` +
276
+ `Acquired token JSON: ${JSON.stringify(tokens)}`,
277
+ );
278
+ }
279
+
269
280
  await this.updateTokensCacheWithoutLock(cacheKey, tokens);
270
281
  return tokens;
271
282
  }
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/tool-utils";
9
- export const pkgVersion = "2.51.0";
9
+ export const pkgVersion = "2.53.0-350190";