@azure/msal-browser 3.28.1 → 3.30.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.
Files changed (127) hide show
  1. package/dist/app/IPublicClientApplication.mjs +1 -1
  2. package/dist/app/PublicClientApplication.mjs +1 -1
  3. package/dist/app/PublicClientNext.mjs +1 -1
  4. package/dist/broker/nativeBroker/NativeMessageHandler.mjs +1 -1
  5. package/dist/broker/nativeBroker/NativeStatusCodes.mjs +1 -1
  6. package/dist/cache/AccountManager.d.ts +7 -7
  7. package/dist/cache/AccountManager.d.ts.map +1 -1
  8. package/dist/cache/AccountManager.mjs +17 -15
  9. package/dist/cache/AccountManager.mjs.map +1 -1
  10. package/dist/cache/AsyncMemoryStorage.mjs +1 -1
  11. package/dist/cache/BrowserCacheManager.d.ts +35 -27
  12. package/dist/cache/BrowserCacheManager.d.ts.map +1 -1
  13. package/dist/cache/BrowserCacheManager.mjs +187 -91
  14. package/dist/cache/BrowserCacheManager.mjs.map +1 -1
  15. package/dist/cache/BrowserStorage.mjs +1 -1
  16. package/dist/cache/CookieStorage.mjs +1 -1
  17. package/dist/cache/DatabaseStorage.mjs +1 -1
  18. package/dist/cache/LocalStorage.mjs +1 -1
  19. package/dist/cache/MemoryStorage.mjs +1 -1
  20. package/dist/cache/SessionStorage.mjs +1 -1
  21. package/dist/cache/TokenCache.d.ts.map +1 -1
  22. package/dist/cache/TokenCache.mjs +16 -15
  23. package/dist/cache/TokenCache.mjs.map +1 -1
  24. package/dist/config/Configuration.mjs +1 -1
  25. package/dist/controllers/ControllerFactory.mjs +1 -1
  26. package/dist/controllers/NestedAppAuthController.d.ts.map +1 -1
  27. package/dist/controllers/NestedAppAuthController.mjs +28 -18
  28. package/dist/controllers/NestedAppAuthController.mjs.map +1 -1
  29. package/dist/controllers/StandardController.d.ts.map +1 -1
  30. package/dist/controllers/StandardController.mjs +16 -9
  31. package/dist/controllers/StandardController.mjs.map +1 -1
  32. package/dist/controllers/UnknownOperatingContextController.mjs +1 -1
  33. package/dist/crypto/BrowserCrypto.mjs +1 -1
  34. package/dist/crypto/CryptoOps.mjs +1 -1
  35. package/dist/crypto/PkceGenerator.mjs +1 -1
  36. package/dist/crypto/SignedHttpRequest.mjs +1 -1
  37. package/dist/encode/Base64Decode.mjs +1 -1
  38. package/dist/encode/Base64Encode.mjs +1 -1
  39. package/dist/error/BrowserAuthError.mjs +1 -1
  40. package/dist/error/BrowserAuthErrorCodes.mjs +1 -1
  41. package/dist/error/BrowserConfigurationAuthError.mjs +1 -1
  42. package/dist/error/BrowserConfigurationAuthErrorCodes.mjs +1 -1
  43. package/dist/error/NativeAuthError.mjs +1 -1
  44. package/dist/error/NativeAuthErrorCodes.mjs +1 -1
  45. package/dist/error/NestedAppAuthError.mjs +1 -1
  46. package/dist/event/EventHandler.mjs +1 -1
  47. package/dist/event/EventMessage.mjs +1 -1
  48. package/dist/event/EventType.mjs +1 -1
  49. package/dist/index.mjs +1 -1
  50. package/dist/interaction_client/BaseInteractionClient.d.ts.map +1 -1
  51. package/dist/interaction_client/BaseInteractionClient.mjs +5 -5
  52. package/dist/interaction_client/BaseInteractionClient.mjs.map +1 -1
  53. package/dist/interaction_client/HybridSpaAuthorizationCodeClient.mjs +1 -1
  54. package/dist/interaction_client/NativeInteractionClient.d.ts.map +1 -1
  55. package/dist/interaction_client/NativeInteractionClient.mjs +9 -7
  56. package/dist/interaction_client/NativeInteractionClient.mjs.map +1 -1
  57. package/dist/interaction_client/PopupClient.d.ts.map +1 -1
  58. package/dist/interaction_client/PopupClient.mjs +2 -2
  59. package/dist/interaction_client/PopupClient.mjs.map +1 -1
  60. package/dist/interaction_client/RedirectClient.d.ts.map +1 -1
  61. package/dist/interaction_client/RedirectClient.mjs +2 -2
  62. package/dist/interaction_client/RedirectClient.mjs.map +1 -1
  63. package/dist/interaction_client/SilentAuthCodeClient.mjs +1 -1
  64. package/dist/interaction_client/SilentCacheClient.mjs +1 -1
  65. package/dist/interaction_client/SilentIframeClient.mjs +1 -1
  66. package/dist/interaction_client/SilentRefreshClient.mjs +1 -1
  67. package/dist/interaction_client/StandardInteractionClient.d.ts.map +1 -1
  68. package/dist/interaction_client/StandardInteractionClient.mjs +3 -2
  69. package/dist/interaction_client/StandardInteractionClient.mjs.map +1 -1
  70. package/dist/interaction_handler/InteractionHandler.mjs +1 -1
  71. package/dist/interaction_handler/RedirectHandler.mjs +1 -1
  72. package/dist/interaction_handler/SilentHandler.mjs +1 -1
  73. package/dist/naa/BridgeError.mjs +1 -1
  74. package/dist/naa/BridgeProxy.mjs +1 -1
  75. package/dist/naa/BridgeStatusCode.mjs +1 -1
  76. package/dist/naa/mapping/NestedAppAuthAdapter.mjs +1 -1
  77. package/dist/navigation/NavigationClient.mjs +1 -1
  78. package/dist/network/FetchClient.mjs +1 -1
  79. package/dist/operatingcontext/BaseOperatingContext.mjs +1 -1
  80. package/dist/operatingcontext/NestedAppOperatingContext.mjs +1 -1
  81. package/dist/operatingcontext/StandardOperatingContext.mjs +1 -1
  82. package/dist/operatingcontext/UnknownOperatingContext.mjs +1 -1
  83. package/dist/packageMetadata.d.ts +1 -1
  84. package/dist/packageMetadata.mjs +2 -2
  85. package/dist/request/RequestHelpers.mjs +1 -1
  86. package/dist/response/ResponseHandler.mjs +1 -1
  87. package/dist/telemetry/BrowserPerformanceClient.mjs +1 -1
  88. package/dist/telemetry/BrowserPerformanceMeasurement.mjs +1 -1
  89. package/dist/utils/BrowserConstants.d.ts +1 -0
  90. package/dist/utils/BrowserConstants.d.ts.map +1 -1
  91. package/dist/utils/BrowserConstants.mjs +2 -1
  92. package/dist/utils/BrowserConstants.mjs.map +1 -1
  93. package/dist/utils/BrowserProtocolUtils.mjs +1 -1
  94. package/dist/utils/BrowserUtils.mjs +1 -1
  95. package/lib/msal-browser.cjs +464 -343
  96. package/lib/msal-browser.cjs.map +1 -1
  97. package/lib/msal-browser.js +464 -343
  98. package/lib/msal-browser.js.map +1 -1
  99. package/lib/msal-browser.min.js +65 -66
  100. package/lib/types/cache/AccountManager.d.ts +7 -7
  101. package/lib/types/cache/AccountManager.d.ts.map +1 -1
  102. package/lib/types/cache/BrowserCacheManager.d.ts +35 -27
  103. package/lib/types/cache/BrowserCacheManager.d.ts.map +1 -1
  104. package/lib/types/cache/TokenCache.d.ts.map +1 -1
  105. package/lib/types/controllers/NestedAppAuthController.d.ts.map +1 -1
  106. package/lib/types/controllers/StandardController.d.ts.map +1 -1
  107. package/lib/types/interaction_client/BaseInteractionClient.d.ts.map +1 -1
  108. package/lib/types/interaction_client/NativeInteractionClient.d.ts.map +1 -1
  109. package/lib/types/interaction_client/PopupClient.d.ts.map +1 -1
  110. package/lib/types/interaction_client/RedirectClient.d.ts.map +1 -1
  111. package/lib/types/interaction_client/StandardInteractionClient.d.ts.map +1 -1
  112. package/lib/types/packageMetadata.d.ts +1 -1
  113. package/lib/types/utils/BrowserConstants.d.ts +1 -0
  114. package/lib/types/utils/BrowserConstants.d.ts.map +1 -1
  115. package/package.json +3 -3
  116. package/src/cache/AccountManager.ts +40 -20
  117. package/src/cache/BrowserCacheManager.ts +332 -109
  118. package/src/cache/TokenCache.ts +25 -11
  119. package/src/controllers/NestedAppAuthController.ts +51 -18
  120. package/src/controllers/StandardController.ts +26 -7
  121. package/src/interaction_client/BaseInteractionClient.ts +5 -4
  122. package/src/interaction_client/NativeInteractionClient.ts +22 -12
  123. package/src/interaction_client/PopupClient.ts +2 -1
  124. package/src/interaction_client/RedirectClient.ts +2 -1
  125. package/src/interaction_client/StandardInteractionClient.ts +2 -1
  126. package/src/packageMetadata.ts +1 -1
  127. package/src/utils/BrowserConstants.ts +1 -0
@@ -1,6 +1,6 @@
1
- /*! @azure/msal-browser v3.28.1 2025-01-14 */
1
+ /*! @azure/msal-browser v3.30.0 2025-08-05 */
2
2
  'use strict';
3
- import { CacheManager, CredentialType, CacheHelpers, AccountEntity, createClientAuthError, ClientAuthErrorCodes, Constants, PersistentCacheKeys, PerformanceEvents, StringUtils, ProtocolUtils, AuthToken, CacheError, DEFAULT_CRYPTO_IMPLEMENTATION, CcsCredentialType } from '@azure/msal-common/browser';
3
+ import { CacheManager, CredentialType, CacheHelpers, AccountEntity, createCacheError, CacheErrorCodes, createClientAuthError, ClientAuthErrorCodes, Constants, PersistentCacheKeys, PerformanceEvents, StringUtils, ProtocolUtils, AuthToken, CacheError, DEFAULT_CRYPTO_IMPLEMENTATION, CcsCredentialType } from '@azure/msal-common/browser';
4
4
  import { createBrowserAuthError } from '../error/BrowserAuthError.mjs';
5
5
  import { BrowserCacheLocation, StaticCacheKeys, InMemoryCacheKeys, TemporaryCacheKeys } from '../utils/BrowserConstants.mjs';
6
6
  import { LocalStorage } from './LocalStorage.mjs';
@@ -10,6 +10,7 @@ import { extractBrowserRequestState } from '../utils/BrowserProtocolUtils.mjs';
10
10
  import { base64Decode } from '../encode/Base64Decode.mjs';
11
11
  import { base64Encode } from '../encode/Base64Encode.mjs';
12
12
  import { CookieStorage } from './CookieStorage.mjs';
13
+ import { version } from '../packageMetadata.mjs';
13
14
  import { noTokenRequestCacheError, unableToParseTokenRequestCacheError, noCachedAuthorityError, interactionInProgress } from '../error/BrowserAuthErrorCodes.mjs';
14
15
 
15
16
  /*
@@ -64,6 +65,13 @@ class BrowserCacheManager extends CacheManager {
64
65
  * @param storeAuthStateInCookie
65
66
  */
66
67
  migrateCacheEntries() {
68
+ const previousVersion = this.browserStorage.getItem(StaticCacheKeys.VERSION);
69
+ if (previousVersion) {
70
+ this.logger.info(`MSAL.js was last initialized with version ${previousVersion}`);
71
+ }
72
+ if (previousVersion !== version) {
73
+ this.browserStorage.setItem(StaticCacheKeys.VERSION, version);
74
+ }
67
75
  const idTokenKey = `${Constants.CACHE_PREFIX}.${PersistentCacheKeys.ID_TOKEN}`;
68
76
  const clientInfoKey = `${Constants.CACHE_PREFIX}.${PersistentCacheKeys.CLIENT_INFO}`;
69
77
  const errorKey = `${Constants.CACHE_PREFIX}.${PersistentCacheKeys.ERROR}`;
@@ -98,6 +106,7 @@ class BrowserCacheManager extends CacheManager {
98
106
  */
99
107
  createKeyMaps() {
100
108
  this.logger.trace("BrowserCacheManager - createKeyMaps called.");
109
+ const correlationId = this.cryptoImpl.createNewGuid();
101
110
  const accountKeys = this.getItem(StaticCacheKeys.ACCOUNT_KEYS);
102
111
  const tokenKeys = this.getItem(`${StaticCacheKeys.TOKEN_KEYS}.${this.clientId}`);
103
112
  if (accountKeys && tokenKeys) {
@@ -119,8 +128,8 @@ class BrowserCacheManager extends CacheManager {
119
128
  this.logger.trace("BrowserCacheManager:createKeyMaps - idToken found, saving key to token key map");
120
129
  this.logger.tracePii(`BrowserCacheManager:createKeyMaps - idToken with key: ${key} found, saving key to token key map`);
121
130
  const idTokenEntity = credObj;
122
- const newKey = this.updateCredentialCacheKey(key, idTokenEntity);
123
- this.addTokenKey(newKey, CredentialType.ID_TOKEN);
131
+ const newKey = this.updateCredentialCacheKey(key, idTokenEntity, correlationId);
132
+ this.addTokenKey(newKey, CredentialType.ID_TOKEN, correlationId);
124
133
  return;
125
134
  }
126
135
  else {
@@ -134,8 +143,8 @@ class BrowserCacheManager extends CacheManager {
134
143
  this.logger.trace("BrowserCacheManager:createKeyMaps - accessToken found, saving key to token key map");
135
144
  this.logger.tracePii(`BrowserCacheManager:createKeyMaps - accessToken with key: ${key} found, saving key to token key map`);
136
145
  const accessTokenEntity = credObj;
137
- const newKey = this.updateCredentialCacheKey(key, accessTokenEntity);
138
- this.addTokenKey(newKey, CredentialType.ACCESS_TOKEN);
146
+ const newKey = this.updateCredentialCacheKey(key, accessTokenEntity, correlationId);
147
+ this.addTokenKey(newKey, CredentialType.ACCESS_TOKEN, correlationId);
139
148
  return;
140
149
  }
141
150
  else {
@@ -148,8 +157,8 @@ class BrowserCacheManager extends CacheManager {
148
157
  this.logger.trace("BrowserCacheManager:createKeyMaps - refreshToken found, saving key to token key map");
149
158
  this.logger.tracePii(`BrowserCacheManager:createKeyMaps - refreshToken with key: ${key} found, saving key to token key map`);
150
159
  const refreshTokenEntity = credObj;
151
- const newKey = this.updateCredentialCacheKey(key, refreshTokenEntity);
152
- this.addTokenKey(newKey, CredentialType.REFRESH_TOKEN);
160
+ const newKey = this.updateCredentialCacheKey(key, refreshTokenEntity, correlationId);
161
+ this.addTokenKey(newKey, CredentialType.REFRESH_TOKEN, correlationId);
153
162
  return;
154
163
  }
155
164
  else {
@@ -170,7 +179,7 @@ class BrowserCacheManager extends CacheManager {
170
179
  AccountEntity.isAccountEntity(accountObj)) {
171
180
  this.logger.trace("BrowserCacheManager:createKeyMaps - account found, saving key to account key map");
172
181
  this.logger.tracePii(`BrowserCacheManager:createKeyMaps - account with key: ${key} found, saving key to account key map`);
173
- this.addAccountKeyToMap(key);
182
+ this.addAccountKeyToMap(key, correlationId);
174
183
  }
175
184
  }
176
185
  }
@@ -209,17 +218,58 @@ class BrowserCacheManager extends CacheManager {
209
218
  * @param key
210
219
  * @param value
211
220
  */
212
- setItem(key, value) {
213
- this.browserStorage.setItem(key, value);
221
+ setItem(key, value, correlationId) {
222
+ let accessTokenKeys = [];
223
+ const maxRetries = 20;
224
+ for (let i = 0; i <= maxRetries; i++) {
225
+ try {
226
+ this.browserStorage.setItem(key, value);
227
+ if (i > 0) {
228
+ // Finally update the token keys array with the tokens removed
229
+ this.removeAccessTokenKeys(accessTokenKeys.slice(0, i), correlationId);
230
+ }
231
+ break; // If setItem succeeds, exit the loop
232
+ }
233
+ catch (e) {
234
+ const cacheError = createCacheError(e);
235
+ if (cacheError.errorCode ===
236
+ CacheErrorCodes.cacheQuotaExceeded &&
237
+ i < maxRetries) {
238
+ if (!accessTokenKeys.length) {
239
+ if (key ===
240
+ `${StaticCacheKeys.TOKEN_KEYS}.${this.clientId}`) {
241
+ // If we are currently trying to set the token keys, use the value we're trying to set
242
+ accessTokenKeys = JSON.parse(value)
243
+ .accessToken;
244
+ }
245
+ else {
246
+ // If token keys have not been initialized, get them
247
+ accessTokenKeys = this.getTokenKeys().accessToken;
248
+ }
249
+ }
250
+ if (accessTokenKeys.length <= i) {
251
+ // Nothing to remove, rethrow the error
252
+ throw cacheError;
253
+ }
254
+ // When cache quota is exceeded, start removing access tokens until we can successfully set the item
255
+ this.removeAccessToken(accessTokenKeys[i], correlationId, false // Don't save token keys yet, do it at the end
256
+ );
257
+ }
258
+ else {
259
+ // If the error is not a quota exceeded error, rethrow it
260
+ throw cacheError;
261
+ }
262
+ }
263
+ }
214
264
  }
215
265
  /**
216
266
  * fetch the account entity from the platform cache
217
267
  * @param accountKey
218
268
  */
219
- getAccount(accountKey, logger) {
269
+ getAccount(accountKey, correlationId, logger) {
220
270
  this.logger.trace("BrowserCacheManager.getAccount called");
221
- const accountEntity = this.getCachedAccountEntity(accountKey);
222
- return this.updateOutdatedCachedAccount(accountKey, accountEntity, logger);
271
+ const accountEntity = this.getCachedAccountEntity(accountKey, correlationId);
272
+ return this.updateOutdatedCachedAccount(accountKey, accountEntity, correlationId, logger);
223
273
  }
224
274
  /**
225
275
  * Reads account from cache, deserializes it into an account entity and returns it.
@@ -227,15 +277,14 @@ class BrowserCacheManager extends CacheManager {
227
277
  * @param accountKey
228
278
  * @returns
229
279
  */
230
- getCachedAccountEntity(accountKey) {
280
+ getCachedAccountEntity(accountKey, correlationId) {
231
281
  const serializedAccount = this.getItem(accountKey);
232
282
  if (!serializedAccount) {
233
- this.removeAccountKeyFromMap(accountKey);
283
+ this.removeAccountKeyFromMap(accountKey, correlationId);
234
284
  return null;
235
285
  }
236
286
  const parsedAccount = this.validateAndParseJson(serializedAccount);
237
287
  if (!parsedAccount || !AccountEntity.isAccountEntity(parsedAccount)) {
238
- this.removeAccountKeyFromMap(accountKey);
239
288
  return null;
240
289
  }
241
290
  return CacheManager.toObject(new AccountEntity(), parsedAccount);
@@ -244,11 +293,12 @@ class BrowserCacheManager extends CacheManager {
244
293
  * set account entity in the platform cache
245
294
  * @param account
246
295
  */
247
- setAccount(account) {
296
+ setAccount(account, correlationId) {
248
297
  this.logger.trace("BrowserCacheManager.setAccount called");
249
298
  const key = account.generateAccountKey();
250
- this.setItem(key, JSON.stringify(account));
251
- this.addAccountKeyToMap(key);
299
+ account.lastUpdatedAt = Date.now().toString();
300
+ this.setItem(key, JSON.stringify(account), correlationId);
301
+ this.addAccountKeyToMap(key, correlationId);
252
302
  }
253
303
  /**
254
304
  * Returns the array of account keys currently cached
@@ -267,14 +317,14 @@ class BrowserCacheManager extends CacheManager {
267
317
  * Add a new account to the key map
268
318
  * @param key
269
319
  */
270
- addAccountKeyToMap(key) {
320
+ addAccountKeyToMap(key, correlationId) {
271
321
  this.logger.trace("BrowserCacheManager.addAccountKeyToMap called");
272
322
  this.logger.tracePii(`BrowserCacheManager.addAccountKeyToMap called with key: ${key}`);
273
323
  const accountKeys = this.getAccountKeys();
274
324
  if (accountKeys.indexOf(key) === -1) {
275
325
  // Only add key if it does not already exist in the map
276
326
  accountKeys.push(key);
277
- this.setItem(StaticCacheKeys.ACCOUNT_KEYS, JSON.stringify(accountKeys));
327
+ this.setItem(StaticCacheKeys.ACCOUNT_KEYS, JSON.stringify(accountKeys), correlationId);
278
328
  this.logger.verbose("BrowserCacheManager.addAccountKeyToMap account key added");
279
329
  }
280
330
  else {
@@ -285,14 +335,21 @@ class BrowserCacheManager extends CacheManager {
285
335
  * Remove an account from the key map
286
336
  * @param key
287
337
  */
288
- removeAccountKeyFromMap(key) {
338
+ removeAccountKeyFromMap(key, correlationId) {
289
339
  this.logger.trace("BrowserCacheManager.removeAccountKeyFromMap called");
290
340
  this.logger.tracePii(`BrowserCacheManager.removeAccountKeyFromMap called with key: ${key}`);
291
341
  const accountKeys = this.getAccountKeys();
292
342
  const removalIndex = accountKeys.indexOf(key);
293
343
  if (removalIndex > -1) {
294
344
  accountKeys.splice(removalIndex, 1);
295
- this.setItem(StaticCacheKeys.ACCOUNT_KEYS, JSON.stringify(accountKeys));
345
+ if (accountKeys.length === 0) {
346
+ // If no keys left, remove the map
347
+ this.removeItem(StaticCacheKeys.ACCOUNT_KEYS);
348
+ return;
349
+ }
350
+ else {
351
+ this.setItem(StaticCacheKeys.ACCOUNT_KEYS, JSON.stringify(accountKeys), correlationId);
352
+ }
296
353
  this.logger.trace("BrowserCacheManager.removeAccountKeyFromMap account key removed");
297
354
  }
298
355
  else {
@@ -303,41 +360,60 @@ class BrowserCacheManager extends CacheManager {
303
360
  * Extends inherited removeAccount function to include removal of the account key from the map
304
361
  * @param key
305
362
  */
306
- async removeAccount(key) {
307
- void super.removeAccount(key);
308
- this.removeAccountKeyFromMap(key);
363
+ async removeAccount(key, correlationId) {
364
+ void super.removeAccount(key, correlationId);
365
+ this.removeAccountKeyFromMap(key, correlationId);
309
366
  }
310
367
  /**
311
368
  * Remove account entity from the platform cache if it's outdated
312
369
  * @param accountKey
313
370
  */
314
- removeOutdatedAccount(accountKey) {
371
+ removeOutdatedAccount(accountKey, correlationId) {
315
372
  this.removeItem(accountKey);
316
- this.removeAccountKeyFromMap(accountKey);
373
+ this.removeAccountKeyFromMap(accountKey, correlationId);
317
374
  }
318
375
  /**
319
376
  * Removes given idToken from the cache and from the key map
320
377
  * @param key
321
378
  */
322
- removeIdToken(key) {
323
- super.removeIdToken(key);
324
- this.removeTokenKey(key, CredentialType.ID_TOKEN);
379
+ removeIdToken(key, correlationId) {
380
+ super.removeIdToken(key, correlationId);
381
+ this.removeTokenKey(key, CredentialType.ID_TOKEN, correlationId);
325
382
  }
326
383
  /**
327
384
  * Removes given accessToken from the cache and from the key map
328
385
  * @param key
329
386
  */
330
- async removeAccessToken(key) {
331
- void super.removeAccessToken(key);
332
- this.removeTokenKey(key, CredentialType.ACCESS_TOKEN);
387
+ removeAccessToken(key, correlationId, updateTokenKeys = true) {
388
+ super.removeAccessToken(key, correlationId);
389
+ this.performanceClient?.incrementFields({ accessTokensRemoved: 1 }, correlationId);
390
+ updateTokenKeys &&
391
+ this.removeTokenKey(key, CredentialType.ACCESS_TOKEN, correlationId);
392
+ }
393
+ removeAccessTokenKeys(keys, correlationId) {
394
+ this.logger.trace("removeAccessTokenKey called");
395
+ const tokenKeys = this.getTokenKeys();
396
+ let keysRemoved = 0;
397
+ keys.forEach((key) => {
398
+ const accessRemoval = tokenKeys.accessToken.indexOf(key);
399
+ if (accessRemoval > -1) {
400
+ tokenKeys.accessToken.splice(accessRemoval, 1);
401
+ keysRemoved++;
402
+ }
403
+ });
404
+ if (keysRemoved > 0) {
405
+ this.logger.info(`removed ${keysRemoved} accessToken keys from tokenKeys map`);
406
+ this.setTokenKeys(tokenKeys, correlationId);
407
+ return;
408
+ }
333
409
  }
334
410
  /**
335
411
  * Removes given refreshToken from the cache and from the key map
336
412
  * @param key
337
413
  */
338
- removeRefreshToken(key) {
339
- super.removeRefreshToken(key);
340
- this.removeTokenKey(key, CredentialType.REFRESH_TOKEN);
414
+ removeRefreshToken(key, correlationId) {
415
+ super.removeRefreshToken(key, correlationId);
416
+ this.removeTokenKey(key, CredentialType.REFRESH_TOKEN, correlationId);
341
417
  }
342
418
  /**
343
419
  * Gets the keys for the cached tokens associated with this clientId
@@ -367,12 +443,30 @@ class BrowserCacheManager extends CacheManager {
367
443
  refreshToken: [],
368
444
  };
369
445
  }
446
+ /**
447
+ * Stores the token keys in the cache
448
+ * @param tokenKeys
449
+ * @param correlationId
450
+ * @returns
451
+ */
452
+ setTokenKeys(tokenKeys, correlationId) {
453
+ if (tokenKeys.idToken.length === 0 &&
454
+ tokenKeys.accessToken.length === 0 &&
455
+ tokenKeys.refreshToken.length === 0) {
456
+ // If no keys left, remove the map
457
+ this.removeItem(`${StaticCacheKeys.TOKEN_KEYS}.${this.clientId}`);
458
+ return;
459
+ }
460
+ else {
461
+ this.setItem(`${StaticCacheKeys.TOKEN_KEYS}.${this.clientId}`, JSON.stringify(tokenKeys), correlationId);
462
+ }
463
+ }
370
464
  /**
371
465
  * Adds the given key to the token key map
372
466
  * @param key
373
467
  * @param type
374
468
  */
375
- addTokenKey(key, type) {
469
+ addTokenKey(key, type, correlationId) {
376
470
  this.logger.trace("BrowserCacheManager addTokenKey called");
377
471
  const tokenKeys = this.getTokenKeys();
378
472
  switch (type) {
@@ -383,10 +477,12 @@ class BrowserCacheManager extends CacheManager {
383
477
  }
384
478
  break;
385
479
  case CredentialType.ACCESS_TOKEN:
386
- if (tokenKeys.accessToken.indexOf(key) === -1) {
387
- this.logger.info("BrowserCacheManager: addTokenKey - accessToken added to map");
388
- tokenKeys.accessToken.push(key);
480
+ const index = tokenKeys.accessToken.indexOf(key);
481
+ if (index !== -1) {
482
+ tokenKeys.accessToken.splice(index, 1); // Remove existing key before pushing to the end
389
483
  }
484
+ this.logger.trace(`access token ${index === -1 ? "added to" : "updated in"} map`);
485
+ tokenKeys.accessToken.push(key);
390
486
  break;
391
487
  case CredentialType.REFRESH_TOKEN:
392
488
  if (tokenKeys.refreshToken.indexOf(key) === -1) {
@@ -398,16 +494,15 @@ class BrowserCacheManager extends CacheManager {
398
494
  this.logger.error(`BrowserCacheManager:addTokenKey - CredentialType provided invalid. CredentialType: ${type}`);
399
495
  throw createClientAuthError(ClientAuthErrorCodes.unexpectedCredentialType);
400
496
  }
401
- this.setItem(`${StaticCacheKeys.TOKEN_KEYS}.${this.clientId}`, JSON.stringify(tokenKeys));
497
+ this.setTokenKeys(tokenKeys, correlationId);
402
498
  }
403
499
  /**
404
500
  * Removes the given key from the token key map
405
501
  * @param key
406
502
  * @param type
407
503
  */
408
- removeTokenKey(key, type) {
504
+ removeTokenKey(key, type, correlationId, tokenKeys = this.getTokenKeys()) {
409
505
  this.logger.trace("BrowserCacheManager removeTokenKey called");
410
- const tokenKeys = this.getTokenKeys();
411
506
  switch (type) {
412
507
  case CredentialType.ID_TOKEN:
413
508
  this.logger.infoPii(`BrowserCacheManager: removeTokenKey - attempting to remove idToken with key: ${key} from map`);
@@ -446,23 +541,22 @@ class BrowserCacheManager extends CacheManager {
446
541
  this.logger.error(`BrowserCacheManager:removeTokenKey - CredentialType provided invalid. CredentialType: ${type}`);
447
542
  throw createClientAuthError(ClientAuthErrorCodes.unexpectedCredentialType);
448
543
  }
449
- this.setItem(`${StaticCacheKeys.TOKEN_KEYS}.${this.clientId}`, JSON.stringify(tokenKeys));
544
+ this.setTokenKeys(tokenKeys, correlationId);
450
545
  }
451
546
  /**
452
547
  * generates idToken entity from a string
453
548
  * @param idTokenKey
454
549
  */
455
- getIdTokenCredential(idTokenKey) {
550
+ getIdTokenCredential(idTokenKey, correlationId) {
456
551
  const value = this.getItem(idTokenKey);
457
552
  if (!value) {
458
553
  this.logger.trace("BrowserCacheManager.getIdTokenCredential: called, no cache hit");
459
- this.removeTokenKey(idTokenKey, CredentialType.ID_TOKEN);
554
+ this.removeIdToken(idTokenKey, correlationId);
460
555
  return null;
461
556
  }
462
557
  const parsedIdToken = this.validateAndParseJson(value);
463
558
  if (!parsedIdToken || !CacheHelpers.isIdTokenEntity(parsedIdToken)) {
464
559
  this.logger.trace("BrowserCacheManager.getIdTokenCredential: called, no cache hit");
465
- this.removeTokenKey(idTokenKey, CredentialType.ID_TOKEN);
466
560
  return null;
467
561
  }
468
562
  this.logger.trace("BrowserCacheManager.getIdTokenCredential: cache hit");
@@ -472,28 +566,28 @@ class BrowserCacheManager extends CacheManager {
472
566
  * set IdToken credential to the platform cache
473
567
  * @param idToken
474
568
  */
475
- setIdTokenCredential(idToken) {
569
+ setIdTokenCredential(idToken, correlationId) {
476
570
  this.logger.trace("BrowserCacheManager.setIdTokenCredential called");
477
571
  const idTokenKey = CacheHelpers.generateCredentialKey(idToken);
478
- this.setItem(idTokenKey, JSON.stringify(idToken));
479
- this.addTokenKey(idTokenKey, CredentialType.ID_TOKEN);
572
+ idToken.lastUpdatedAt = Date.now().toString();
573
+ this.setItem(idTokenKey, JSON.stringify(idToken), correlationId);
574
+ this.addTokenKey(idTokenKey, CredentialType.ID_TOKEN, correlationId);
480
575
  }
481
576
  /**
482
577
  * generates accessToken entity from a string
483
578
  * @param key
484
579
  */
485
- getAccessTokenCredential(accessTokenKey) {
580
+ getAccessTokenCredential(accessTokenKey, correlationId) {
486
581
  const value = this.getItem(accessTokenKey);
487
582
  if (!value) {
488
583
  this.logger.trace("BrowserCacheManager.getAccessTokenCredential: called, no cache hit");
489
- this.removeTokenKey(accessTokenKey, CredentialType.ACCESS_TOKEN);
584
+ this.removeTokenKey(accessTokenKey, CredentialType.ACCESS_TOKEN, correlationId);
490
585
  return null;
491
586
  }
492
587
  const parsedAccessToken = this.validateAndParseJson(value);
493
588
  if (!parsedAccessToken ||
494
589
  !CacheHelpers.isAccessTokenEntity(parsedAccessToken)) {
495
590
  this.logger.trace("BrowserCacheManager.getAccessTokenCredential: called, no cache hit");
496
- this.removeTokenKey(accessTokenKey, CredentialType.ACCESS_TOKEN);
497
591
  return null;
498
592
  }
499
593
  this.logger.trace("BrowserCacheManager.getAccessTokenCredential: cache hit");
@@ -503,28 +597,28 @@ class BrowserCacheManager extends CacheManager {
503
597
  * set accessToken credential to the platform cache
504
598
  * @param accessToken
505
599
  */
506
- setAccessTokenCredential(accessToken) {
600
+ setAccessTokenCredential(accessToken, correlationId) {
507
601
  this.logger.trace("BrowserCacheManager.setAccessTokenCredential called");
508
602
  const accessTokenKey = CacheHelpers.generateCredentialKey(accessToken);
509
- this.setItem(accessTokenKey, JSON.stringify(accessToken));
510
- this.addTokenKey(accessTokenKey, CredentialType.ACCESS_TOKEN);
603
+ accessToken.lastUpdatedAt = Date.now().toString();
604
+ this.setItem(accessTokenKey, JSON.stringify(accessToken), correlationId);
605
+ this.addTokenKey(accessTokenKey, CredentialType.ACCESS_TOKEN, correlationId);
511
606
  }
512
607
  /**
513
608
  * generates refreshToken entity from a string
514
609
  * @param refreshTokenKey
515
610
  */
516
- getRefreshTokenCredential(refreshTokenKey) {
611
+ getRefreshTokenCredential(refreshTokenKey, correlationId) {
517
612
  const value = this.getItem(refreshTokenKey);
518
613
  if (!value) {
519
614
  this.logger.trace("BrowserCacheManager.getRefreshTokenCredential: called, no cache hit");
520
- this.removeTokenKey(refreshTokenKey, CredentialType.REFRESH_TOKEN);
615
+ this.removeTokenKey(refreshTokenKey, CredentialType.REFRESH_TOKEN, correlationId);
521
616
  return null;
522
617
  }
523
618
  const parsedRefreshToken = this.validateAndParseJson(value);
524
619
  if (!parsedRefreshToken ||
525
620
  !CacheHelpers.isRefreshTokenEntity(parsedRefreshToken)) {
526
621
  this.logger.trace("BrowserCacheManager.getRefreshTokenCredential: called, no cache hit");
527
- this.removeTokenKey(refreshTokenKey, CredentialType.REFRESH_TOKEN);
528
622
  return null;
529
623
  }
530
624
  this.logger.trace("BrowserCacheManager.getRefreshTokenCredential: cache hit");
@@ -534,11 +628,12 @@ class BrowserCacheManager extends CacheManager {
534
628
  * set refreshToken credential to the platform cache
535
629
  * @param refreshToken
536
630
  */
537
- setRefreshTokenCredential(refreshToken) {
631
+ setRefreshTokenCredential(refreshToken, correlationId) {
538
632
  this.logger.trace("BrowserCacheManager.setRefreshTokenCredential called");
539
633
  const refreshTokenKey = CacheHelpers.generateCredentialKey(refreshToken);
540
- this.setItem(refreshTokenKey, JSON.stringify(refreshToken));
541
- this.addTokenKey(refreshTokenKey, CredentialType.REFRESH_TOKEN);
634
+ refreshToken.lastUpdatedAt = Date.now().toString();
635
+ this.setItem(refreshTokenKey, JSON.stringify(refreshToken), correlationId);
636
+ this.addTokenKey(refreshTokenKey, CredentialType.REFRESH_TOKEN, correlationId);
542
637
  }
543
638
  /**
544
639
  * fetch appMetadata entity from the platform cache
@@ -563,10 +658,10 @@ class BrowserCacheManager extends CacheManager {
563
658
  * set appMetadata entity to the platform cache
564
659
  * @param appMetadata
565
660
  */
566
- setAppMetadata(appMetadata) {
661
+ setAppMetadata(appMetadata, correlationId) {
567
662
  this.logger.trace("BrowserCacheManager.setAppMetadata called");
568
663
  const appMetadataKey = CacheHelpers.generateAppMetadataKey(appMetadata);
569
- this.setItem(appMetadataKey, JSON.stringify(appMetadata));
664
+ this.setItem(appMetadataKey, JSON.stringify(appMetadata), correlationId);
570
665
  }
571
666
  /**
572
667
  * fetch server telemetry entity from the platform cache
@@ -592,9 +687,9 @@ class BrowserCacheManager extends CacheManager {
592
687
  * @param serverTelemetryKey
593
688
  * @param serverTelemetry
594
689
  */
595
- setServerTelemetry(serverTelemetryKey, serverTelemetry) {
690
+ setServerTelemetry(serverTelemetryKey, serverTelemetry, correlationId) {
596
691
  this.logger.trace("BrowserCacheManager.setServerTelemetry called");
597
- this.setItem(serverTelemetryKey, JSON.stringify(serverTelemetry));
692
+ this.setItem(serverTelemetryKey, JSON.stringify(serverTelemetry), correlationId);
598
693
  }
599
694
  /**
600
695
  *
@@ -652,7 +747,7 @@ class BrowserCacheManager extends CacheManager {
652
747
  /**
653
748
  * Gets the active account
654
749
  */
655
- getActiveAccount() {
750
+ getActiveAccount(correlationId) {
656
751
  const activeAccountKeyFilters = this.generateCacheKey(PersistentCacheKeys.ACTIVE_ACCOUNT_FILTERS);
657
752
  const activeAccountValueFilters = this.getItem(activeAccountKeyFilters);
658
753
  if (!activeAccountValueFilters) {
@@ -666,11 +761,11 @@ class BrowserCacheManager extends CacheManager {
666
761
  }
667
762
  const activeAccount = this.getAccountInfoFilteredBy({
668
763
  localAccountId: activeAccountValueLocal,
669
- });
764
+ }, correlationId);
670
765
  if (activeAccount) {
671
766
  this.logger.trace("BrowserCacheManager.getActiveAccount: Legacy active account cache schema found");
672
767
  this.logger.trace("BrowserCacheManager.getActiveAccount: Adding active account filters cache schema");
673
- this.setActiveAccount(activeAccount);
768
+ this.setActiveAccount(activeAccount, correlationId);
674
769
  return activeAccount;
675
770
  }
676
771
  return null;
@@ -682,7 +777,7 @@ class BrowserCacheManager extends CacheManager {
682
777
  homeAccountId: activeAccountValueObj.homeAccountId,
683
778
  localAccountId: activeAccountValueObj.localAccountId,
684
779
  tenantId: activeAccountValueObj.tenantId,
685
- });
780
+ }, correlationId);
686
781
  }
687
782
  this.logger.trace("BrowserCacheManager.getActiveAccount: No active account found");
688
783
  return null;
@@ -691,7 +786,7 @@ class BrowserCacheManager extends CacheManager {
691
786
  * Sets the active account's localAccountId in cache
692
787
  * @param account
693
788
  */
694
- setActiveAccount(account) {
789
+ setActiveAccount(account, correlationId) {
695
790
  const activeAccountKey = this.generateCacheKey(PersistentCacheKeys.ACTIVE_ACCOUNT_FILTERS);
696
791
  const activeAccountKeyLocal = this.generateCacheKey(PersistentCacheKeys.ACTIVE_ACCOUNT);
697
792
  if (account) {
@@ -700,9 +795,10 @@ class BrowserCacheManager extends CacheManager {
700
795
  homeAccountId: account.homeAccountId,
701
796
  localAccountId: account.localAccountId,
702
797
  tenantId: account.tenantId,
798
+ lastUpdatedAt: Date.now().toString(),
703
799
  };
704
- this.browserStorage.setItem(activeAccountKey, JSON.stringify(activeAccountValue));
705
- this.browserStorage.setItem(activeAccountKeyLocal, account.localAccountId);
800
+ this.setItem(activeAccountKey, JSON.stringify(activeAccountValue), correlationId);
801
+ this.setItem(activeAccountKeyLocal, account.localAccountId, correlationId);
706
802
  }
707
803
  else {
708
804
  this.logger.verbose("setActiveAccount: No account passed, active account not set");
@@ -734,9 +830,9 @@ class BrowserCacheManager extends CacheManager {
734
830
  * @param throttlingCacheKey
735
831
  * @param throttlingCache
736
832
  */
737
- setThrottlingCache(throttlingCacheKey, throttlingCache) {
833
+ setThrottlingCache(throttlingCacheKey, throttlingCache, correlationId) {
738
834
  this.logger.trace("BrowserCacheManager.setThrottlingCache called");
739
- this.setItem(throttlingCacheKey, JSON.stringify(throttlingCache));
835
+ this.setItem(throttlingCacheKey, JSON.stringify(throttlingCache), correlationId);
740
836
  }
741
837
  /**
742
838
  * Gets cache item with given key.
@@ -812,10 +908,10 @@ class BrowserCacheManager extends CacheManager {
812
908
  /**
813
909
  * Clears all cache entries created by MSAL.
814
910
  */
815
- async clear() {
911
+ async clear(correlationId) {
816
912
  // Removes all accounts and their credentials
817
- await this.removeAllAccounts();
818
- this.removeAppMetadata();
913
+ await this.removeAllAccounts(correlationId);
914
+ this.removeAppMetadata(correlationId);
819
915
  // Remove temp storage first to make sure any cookies are cleared
820
916
  this.temporaryCacheStorage.getKeys().forEach((cacheKey) => {
821
917
  if (cacheKey.indexOf(Constants.CACHE_PREFIX) !== -1 ||
@@ -841,19 +937,19 @@ class BrowserCacheManager extends CacheManager {
841
937
  async clearTokensAndKeysWithClaims(performanceClient, correlationId) {
842
938
  performanceClient.addQueueMeasurement(PerformanceEvents.ClearTokensAndKeysWithClaims, correlationId);
843
939
  const tokenKeys = this.getTokenKeys();
844
- const removedAccessTokens = [];
940
+ let removedAccessTokens = 0;
845
941
  tokenKeys.accessToken.forEach((key) => {
846
942
  // if the access token has claims in its key, remove the token key and the token
847
- const credential = this.getAccessTokenCredential(key);
943
+ const credential = this.getAccessTokenCredential(key, correlationId);
848
944
  if (credential?.requestedClaimsHash &&
849
945
  key.includes(credential.requestedClaimsHash.toLowerCase())) {
850
- removedAccessTokens.push(this.removeAccessToken(key));
946
+ this.removeAccessToken(key, correlationId);
947
+ removedAccessTokens++;
851
948
  }
852
949
  });
853
- await Promise.all(removedAccessTokens);
854
950
  // warn if any access tokens are removed
855
- if (removedAccessTokens.length > 0) {
856
- this.logger.warning(`${removedAccessTokens.length} access tokens with claims in the cache keys have been removed from the cache.`);
951
+ if (removedAccessTokens > 0) {
952
+ this.logger.warning(`${removedAccessTokens} access tokens with claims in the cache keys have been removed from the cache.`);
857
953
  }
858
954
  }
859
955
  /**
@@ -1128,13 +1224,13 @@ class BrowserCacheManager extends CacheManager {
1128
1224
  /**
1129
1225
  * Updates a credential's cache key if the current cache key is outdated
1130
1226
  */
1131
- updateCredentialCacheKey(currentCacheKey, credential) {
1227
+ updateCredentialCacheKey(currentCacheKey, credential, correlationId) {
1132
1228
  const updatedCacheKey = CacheHelpers.generateCredentialKey(credential);
1133
1229
  if (currentCacheKey !== updatedCacheKey) {
1134
1230
  const cacheItem = this.getItem(currentCacheKey);
1135
1231
  if (cacheItem) {
1136
1232
  this.browserStorage.removeItem(currentCacheKey);
1137
- this.setItem(updatedCacheKey, cacheItem);
1233
+ this.setItem(updatedCacheKey, cacheItem, correlationId);
1138
1234
  this.logger.verbose(`Updated an outdated ${credential.credentialType} cache key`);
1139
1235
  return updatedCacheKey;
1140
1236
  }
@@ -1169,7 +1265,7 @@ class BrowserCacheManager extends CacheManager {
1169
1265
  idToken: idTokenEntity,
1170
1266
  accessToken: accessTokenEntity,
1171
1267
  };
1172
- return this.saveCacheRecord(cacheRecord);
1268
+ return this.saveCacheRecord(cacheRecord, result.correlationId);
1173
1269
  }
1174
1270
  /**
1175
1271
  * saves a cache record
@@ -1177,9 +1273,9 @@ class BrowserCacheManager extends CacheManager {
1177
1273
  * @param storeInCache {?StoreInCache}
1178
1274
  * @param correlationId {?string} correlation id
1179
1275
  */
1180
- async saveCacheRecord(cacheRecord, storeInCache, correlationId) {
1276
+ async saveCacheRecord(cacheRecord, correlationId, storeInCache) {
1181
1277
  try {
1182
- await super.saveCacheRecord(cacheRecord, storeInCache, correlationId);
1278
+ await super.saveCacheRecord(cacheRecord, correlationId, storeInCache);
1183
1279
  }
1184
1280
  catch (e) {
1185
1281
  if (e instanceof CacheError &&