@azure/msal-common 15.9.0 → 15.11.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 (143) hide show
  1. package/dist/account/AccountInfo.d.ts +2 -1
  2. package/dist/account/AccountInfo.d.ts.map +1 -1
  3. package/dist/account/AccountInfo.mjs +5 -2
  4. package/dist/account/AccountInfo.mjs.map +1 -1
  5. package/dist/account/AuthToken.mjs +1 -1
  6. package/dist/account/CcsCredential.mjs +1 -1
  7. package/dist/account/ClientInfo.mjs +1 -1
  8. package/dist/account/TokenClaims.mjs +1 -1
  9. package/dist/authority/Authority.mjs +1 -1
  10. package/dist/authority/AuthorityFactory.mjs +1 -1
  11. package/dist/authority/AuthorityMetadata.mjs +1 -1
  12. package/dist/authority/AuthorityOptions.mjs +1 -1
  13. package/dist/authority/AuthorityType.mjs +1 -1
  14. package/dist/authority/CloudInstanceDiscoveryErrorResponse.mjs +1 -1
  15. package/dist/authority/CloudInstanceDiscoveryResponse.mjs +1 -1
  16. package/dist/authority/OpenIdConfigResponse.mjs +1 -1
  17. package/dist/authority/ProtocolMode.mjs +1 -1
  18. package/dist/authority/RegionDiscovery.mjs +1 -1
  19. package/dist/cache/CacheManager.d.ts +15 -20
  20. package/dist/cache/CacheManager.d.ts.map +1 -1
  21. package/dist/cache/CacheManager.mjs +37 -97
  22. package/dist/cache/CacheManager.mjs.map +1 -1
  23. package/dist/cache/entities/AccountEntity.d.ts +2 -14
  24. package/dist/cache/entities/AccountEntity.d.ts.map +1 -1
  25. package/dist/cache/entities/AccountEntity.mjs +6 -34
  26. package/dist/cache/entities/AccountEntity.mjs.map +1 -1
  27. package/dist/cache/entities/CredentialEntity.d.ts +1 -1
  28. package/dist/cache/entities/CredentialEntity.d.ts.map +1 -1
  29. package/dist/cache/interface/ICacheManager.d.ts +2 -10
  30. package/dist/cache/interface/ICacheManager.d.ts.map +1 -1
  31. package/dist/cache/persistence/TokenCacheContext.mjs +1 -1
  32. package/dist/cache/utils/CacheHelpers.d.ts +4 -13
  33. package/dist/cache/utils/CacheHelpers.d.ts.map +1 -1
  34. package/dist/cache/utils/CacheHelpers.mjs +6 -71
  35. package/dist/cache/utils/CacheHelpers.mjs.map +1 -1
  36. package/dist/client/AuthorizationCodeClient.mjs +1 -1
  37. package/dist/client/BaseClient.mjs +1 -1
  38. package/dist/client/RefreshTokenClient.d.ts.map +1 -1
  39. package/dist/client/RefreshTokenClient.mjs +2 -3
  40. package/dist/client/RefreshTokenClient.mjs.map +1 -1
  41. package/dist/client/SilentFlowClient.mjs +2 -2
  42. package/dist/client/SilentFlowClient.mjs.map +1 -1
  43. package/dist/config/ClientConfiguration.mjs +1 -1
  44. package/dist/constants/AADServerParamKeys.mjs +1 -1
  45. package/dist/crypto/ICrypto.mjs +1 -1
  46. package/dist/crypto/JoseHeader.mjs +1 -1
  47. package/dist/crypto/PopTokenGenerator.mjs +1 -1
  48. package/dist/error/AuthError.mjs +1 -1
  49. package/dist/error/AuthErrorCodes.mjs +1 -1
  50. package/dist/error/CacheError.mjs +1 -1
  51. package/dist/error/CacheErrorCodes.mjs +1 -1
  52. package/dist/error/ClientAuthError.mjs +1 -1
  53. package/dist/error/ClientAuthErrorCodes.mjs +1 -1
  54. package/dist/error/ClientConfigurationError.mjs +1 -1
  55. package/dist/error/ClientConfigurationErrorCodes.mjs +1 -1
  56. package/dist/error/InteractionRequiredAuthError.mjs +1 -1
  57. package/dist/error/InteractionRequiredAuthErrorCodes.mjs +1 -1
  58. package/dist/error/JoseHeaderError.mjs +1 -1
  59. package/dist/error/JoseHeaderErrorCodes.mjs +1 -1
  60. package/dist/error/NetworkError.mjs +1 -1
  61. package/dist/error/ServerError.mjs +1 -1
  62. package/dist/index-browser.mjs +1 -1
  63. package/dist/index-node.mjs +1 -1
  64. package/dist/index.mjs +1 -1
  65. package/dist/logger/Logger.mjs +1 -1
  66. package/dist/network/INetworkModule.mjs +1 -1
  67. package/dist/network/RequestThumbprint.mjs +1 -1
  68. package/dist/network/ThrottlingUtils.mjs +1 -1
  69. package/dist/packageMetadata.d.ts +1 -1
  70. package/dist/packageMetadata.d.ts.map +1 -1
  71. package/dist/packageMetadata.mjs +2 -2
  72. package/dist/protocol/Authorize.mjs +2 -2
  73. package/dist/protocol/Authorize.mjs.map +1 -1
  74. package/dist/request/AuthenticationHeaderParser.mjs +1 -1
  75. package/dist/request/RequestParameterBuilder.mjs +1 -1
  76. package/dist/request/ScopeSet.mjs +1 -1
  77. package/dist/response/ResponseHandler.d.ts.map +1 -1
  78. package/dist/response/ResponseHandler.mjs +3 -3
  79. package/dist/response/ResponseHandler.mjs.map +1 -1
  80. package/dist/telemetry/performance/PerformanceClient.mjs +1 -1
  81. package/dist/telemetry/performance/PerformanceEvent.d.ts +3 -0
  82. package/dist/telemetry/performance/PerformanceEvent.d.ts.map +1 -1
  83. package/dist/telemetry/performance/PerformanceEvent.mjs +11 -1
  84. package/dist/telemetry/performance/PerformanceEvent.mjs.map +1 -1
  85. package/dist/telemetry/performance/StubPerformanceClient.mjs +1 -1
  86. package/dist/telemetry/server/ServerTelemetryManager.mjs +1 -1
  87. package/dist/url/UrlString.mjs +1 -1
  88. package/dist/utils/ClientAssertionUtils.mjs +1 -1
  89. package/dist/utils/Constants.d.ts +0 -1
  90. package/dist/utils/Constants.d.ts.map +1 -1
  91. package/dist/utils/Constants.mjs +1 -3
  92. package/dist/utils/Constants.mjs.map +1 -1
  93. package/dist/utils/FunctionWrappers.mjs +1 -1
  94. package/dist/utils/ProtocolUtils.mjs +1 -1
  95. package/dist/utils/StringUtils.mjs +1 -1
  96. package/dist/utils/TimeUtils.d.ts +7 -0
  97. package/dist/utils/TimeUtils.d.ts.map +1 -1
  98. package/dist/utils/TimeUtils.mjs +12 -2
  99. package/dist/utils/TimeUtils.mjs.map +1 -1
  100. package/dist/utils/UrlUtils.mjs +1 -1
  101. package/lib/index-browser.cjs +2 -2
  102. package/lib/{index-node-C5c-lcoe.js → index-node-CtW_2rqJ.js} +465 -595
  103. package/lib/index-node-CtW_2rqJ.js.map +1 -0
  104. package/lib/index-node.cjs +2 -2
  105. package/lib/index.cjs +2 -2
  106. package/lib/types/account/AccountInfo.d.ts +2 -1
  107. package/lib/types/account/AccountInfo.d.ts.map +1 -1
  108. package/lib/types/cache/CacheManager.d.ts +15 -20
  109. package/lib/types/cache/CacheManager.d.ts.map +1 -1
  110. package/lib/types/cache/entities/AccountEntity.d.ts +2 -14
  111. package/lib/types/cache/entities/AccountEntity.d.ts.map +1 -1
  112. package/lib/types/cache/entities/CredentialEntity.d.ts +1 -1
  113. package/lib/types/cache/entities/CredentialEntity.d.ts.map +1 -1
  114. package/lib/types/cache/interface/ICacheManager.d.ts +2 -10
  115. package/lib/types/cache/interface/ICacheManager.d.ts.map +1 -1
  116. package/lib/types/cache/utils/CacheHelpers.d.ts +4 -13
  117. package/lib/types/cache/utils/CacheHelpers.d.ts.map +1 -1
  118. package/lib/types/client/RefreshTokenClient.d.ts.map +1 -1
  119. package/lib/types/packageMetadata.d.ts +1 -1
  120. package/lib/types/packageMetadata.d.ts.map +1 -1
  121. package/lib/types/response/ResponseHandler.d.ts.map +1 -1
  122. package/lib/types/telemetry/performance/PerformanceEvent.d.ts +3 -0
  123. package/lib/types/telemetry/performance/PerformanceEvent.d.ts.map +1 -1
  124. package/lib/types/utils/Constants.d.ts +0 -1
  125. package/lib/types/utils/Constants.d.ts.map +1 -1
  126. package/lib/types/utils/TimeUtils.d.ts +7 -0
  127. package/lib/types/utils/TimeUtils.d.ts.map +1 -1
  128. package/package.json +1 -1
  129. package/src/account/AccountInfo.ts +16 -2
  130. package/src/cache/CacheManager.ts +59 -125
  131. package/src/cache/entities/AccountEntity.ts +7 -38
  132. package/src/cache/entities/CredentialEntity.ts +1 -1
  133. package/src/cache/interface/ICacheManager.ts +2 -15
  134. package/src/cache/utils/CacheHelpers.ts +11 -83
  135. package/src/client/RefreshTokenClient.ts +1 -2
  136. package/src/client/SilentFlowClient.ts +2 -2
  137. package/src/packageMetadata.ts +1 -1
  138. package/src/protocol/Authorize.ts +1 -1
  139. package/src/response/ResponseHandler.ts +3 -1
  140. package/src/telemetry/performance/PerformanceEvent.ts +16 -0
  141. package/src/utils/Constants.ts +0 -2
  142. package/src/utils/TimeUtils.ts +15 -0
  143. package/lib/index-node-C5c-lcoe.js.map +0 -1
@@ -1,4 +1,4 @@
1
- /*! @azure/msal-common v15.9.0 2025-07-23 */
1
+ /*! @azure/msal-common v15.11.0 2025-08-12 */
2
2
  'use strict';
3
3
  'use strict';
4
4
 
@@ -9,8 +9,6 @@
9
9
  const Constants = {
10
10
  LIBRARY_NAME: "MSAL.JS",
11
11
  SKU: "msal.js.common",
12
- // Prefix for all library cache entries
13
- CACHE_PREFIX: "msal",
14
12
  // default authority
15
13
  DEFAULT_AUTHORITY: "https://login.microsoftonline.com/common/",
16
14
  DEFAULT_AUTHORITY_HOST: "login.microsoftonline.com",
@@ -2057,6 +2055,16 @@ const IntFields = new Set([
2057
2055
  "multiMatchedRT",
2058
2056
  "unencryptedCacheCount",
2059
2057
  "encryptedCacheExpiredCount",
2058
+ "oldAccountCount",
2059
+ "oldAccessCount",
2060
+ "oldIdCount",
2061
+ "oldRefreshCount",
2062
+ "currAccountCount",
2063
+ "currAccessCount",
2064
+ "currIdCount",
2065
+ "currRefreshCount",
2066
+ "expiredCacheRemovedCount",
2067
+ "upgradedCacheCount",
2060
2068
  ]);
2061
2069
 
2062
2070
  /*
@@ -2301,6 +2309,16 @@ function isTokenExpired(expiresOn, offset) {
2301
2309
  // If current time + offset is greater than token expiration time, then token is expired.
2302
2310
  return offsetCurrentTimeSec > expirationSec;
2303
2311
  }
2312
+ /**
2313
+ * Checks if a cache entry is expired based on the last updated time and cache retention days.
2314
+ * @param lastUpdatedAt
2315
+ * @param cacheRetentionDays
2316
+ * @returns
2317
+ */
2318
+ function isCacheExpired(lastUpdatedAt, cacheRetentionDays) {
2319
+ const cacheExpirationTimestamp = Number(lastUpdatedAt) + cacheRetentionDays * 24 * 60 * 60 * 1000;
2320
+ return Date.now() > cacheExpirationTimestamp;
2321
+ }
2304
2322
  /**
2305
2323
  * If the current time is earlier than the time that a token was cached at, we must discard the token
2306
2324
  * i.e. The system clock was turned back after acquiring the cached token
@@ -2323,6 +2341,7 @@ function delay(t, value) {
2323
2341
  var TimeUtils = /*#__PURE__*/Object.freeze({
2324
2342
  __proto__: null,
2325
2343
  delay: delay,
2344
+ isCacheExpired: isCacheExpired,
2326
2345
  isTokenExpired: isTokenExpired,
2327
2346
  nowSeconds: nowSeconds,
2328
2347
  toDateFromSeconds: toDateFromSeconds,
@@ -2334,24 +2353,6 @@ var TimeUtils = /*#__PURE__*/Object.freeze({
2334
2353
  * Copyright (c) Microsoft Corporation. All rights reserved.
2335
2354
  * Licensed under the MIT License.
2336
2355
  */
2337
- /**
2338
- * Cache Key: <home_account_id>-<environment>-<credential_type>-<client_id or familyId>-<realm>-<scopes>-<claims hash>-<scheme>
2339
- * IdToken Example: uid.utid-login.microsoftonline.com-idtoken-app_client_id-contoso.com
2340
- * AccessToken Example: uid.utid-login.microsoftonline.com-accesstoken-app_client_id-contoso.com-scope1 scope2--pop
2341
- * RefreshToken Example: uid.utid-login.microsoftonline.com-refreshtoken-1-contoso.com
2342
- * @param credentialEntity
2343
- * @returns
2344
- */
2345
- function generateCredentialKey(credentialEntity) {
2346
- const credentialKey = [
2347
- generateAccountId(credentialEntity),
2348
- generateCredentialId(credentialEntity),
2349
- generateTarget(credentialEntity),
2350
- generateClaimsHash(credentialEntity),
2351
- generateScheme(credentialEntity),
2352
- ];
2353
- return credentialKey.join(Separators.CACHE_KEY_SEPARATOR).toLowerCase();
2354
- }
2355
2356
  /**
2356
2357
  * Create IdTokenEntity
2357
2358
  * @param homeAccountId
@@ -2367,6 +2368,7 @@ function createIdTokenEntity(homeAccountId, environment, idToken, clientId, tena
2367
2368
  clientId: clientId,
2368
2369
  secret: idToken,
2369
2370
  realm: tenantId,
2371
+ lastUpdatedAt: Date.now().toString(), // Set the last updated time to now
2370
2372
  };
2371
2373
  return idTokenEntity;
2372
2374
  }
@@ -2394,6 +2396,7 @@ function createAccessTokenEntity(homeAccountId, environment, accessToken, client
2394
2396
  realm: tenantId,
2395
2397
  target: scopes,
2396
2398
  tokenType: tokenType || AuthenticationScheme.BEARER,
2399
+ lastUpdatedAt: Date.now().toString(), // Set the last updated time to now
2397
2400
  };
2398
2401
  if (userAssertionHash) {
2399
2402
  atEntity.userAssertionHash = userAssertionHash;
@@ -2441,6 +2444,7 @@ function createRefreshTokenEntity(homeAccountId, environment, refreshToken, clie
2441
2444
  environment: environment,
2442
2445
  clientId: clientId,
2443
2446
  secret: refreshToken,
2447
+ lastUpdatedAt: Date.now().toString(),
2444
2448
  };
2445
2449
  if (userAssertionHash) {
2446
2450
  rtEntity.userAssertionHash = userAssertionHash;
@@ -2498,56 +2502,6 @@ function isRefreshTokenEntity(entity) {
2498
2502
  return (isCredentialEntity(entity) &&
2499
2503
  entity["credentialType"] === CredentialType.REFRESH_TOKEN);
2500
2504
  }
2501
- /**
2502
- * Generate Account Id key component as per the schema: <home_account_id>-<environment>
2503
- */
2504
- function generateAccountId(credentialEntity) {
2505
- const accountId = [
2506
- credentialEntity.homeAccountId,
2507
- credentialEntity.environment,
2508
- ];
2509
- return accountId.join(Separators.CACHE_KEY_SEPARATOR).toLowerCase();
2510
- }
2511
- /**
2512
- * Generate Credential Id key component as per the schema: <credential_type>-<client_id>-<realm>
2513
- */
2514
- function generateCredentialId(credentialEntity) {
2515
- const clientOrFamilyId = credentialEntity.credentialType === CredentialType.REFRESH_TOKEN
2516
- ? credentialEntity.familyId || credentialEntity.clientId
2517
- : credentialEntity.clientId;
2518
- const credentialId = [
2519
- credentialEntity.credentialType,
2520
- clientOrFamilyId,
2521
- credentialEntity.realm || "",
2522
- ];
2523
- return credentialId.join(Separators.CACHE_KEY_SEPARATOR).toLowerCase();
2524
- }
2525
- /**
2526
- * Generate target key component as per schema: <target>
2527
- */
2528
- function generateTarget(credentialEntity) {
2529
- return (credentialEntity.target || "").toLowerCase();
2530
- }
2531
- /**
2532
- * Generate requested claims key component as per schema: <requestedClaims>
2533
- */
2534
- function generateClaimsHash(credentialEntity) {
2535
- return (credentialEntity.requestedClaimsHash || "").toLowerCase();
2536
- }
2537
- /**
2538
- * Generate scheme key componenet as per schema: <scheme>
2539
- */
2540
- function generateScheme(credentialEntity) {
2541
- /*
2542
- * PoP Tokens and SSH certs include scheme in cache key
2543
- * Cast to lowercase to handle "bearer" from ADFS
2544
- */
2545
- return credentialEntity.tokenType &&
2546
- credentialEntity.tokenType.toLowerCase() !==
2547
- AuthenticationScheme.BEARER.toLowerCase()
2548
- ? credentialEntity.tokenType.toLowerCase()
2549
- : "";
2550
- }
2551
2505
  /**
2552
2506
  * validates if a given cache entry is "Telemetry", parses <key,value>
2553
2507
  * @param key
@@ -2662,7 +2616,6 @@ var CacheHelpers = /*#__PURE__*/Object.freeze({
2662
2616
  createRefreshTokenEntity: createRefreshTokenEntity,
2663
2617
  generateAppMetadataKey: generateAppMetadataKey,
2664
2618
  generateAuthorityMetadataExpiresAt: generateAuthorityMetadataExpiresAt,
2665
- generateCredentialKey: generateCredentialKey,
2666
2619
  isAccessTokenEntity: isAccessTokenEntity,
2667
2620
  isAppMetadataEntity: isAppMetadataEntity,
2668
2621
  isAuthorityMetadataEntity: isAuthorityMetadataEntity,
@@ -3900,7 +3853,7 @@ class Logger {
3900
3853
 
3901
3854
  /* eslint-disable header/header */
3902
3855
  const name = "@azure/msal-common";
3903
- const version = "15.9.0";
3856
+ const version = "15.11.0";
3904
3857
 
3905
3858
  /*
3906
3859
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -4091,44 +4044,6 @@ class ScopeSet {
4091
4044
  }
4092
4045
  }
4093
4046
 
4094
- /*
4095
- * Copyright (c) Microsoft Corporation. All rights reserved.
4096
- * Licensed under the MIT License.
4097
- */
4098
- /**
4099
- * Function to build a client info object from server clientInfo string
4100
- * @param rawClientInfo
4101
- * @param crypto
4102
- */
4103
- function buildClientInfo(rawClientInfo, base64Decode) {
4104
- if (!rawClientInfo) {
4105
- throw createClientAuthError(clientInfoEmptyError);
4106
- }
4107
- try {
4108
- const decodedClientInfo = base64Decode(rawClientInfo);
4109
- return JSON.parse(decodedClientInfo);
4110
- }
4111
- catch (e) {
4112
- throw createClientAuthError(clientInfoDecodingError);
4113
- }
4114
- }
4115
- /**
4116
- * Function to build a client info object from cached homeAccountId string
4117
- * @param homeAccountId
4118
- */
4119
- function buildClientInfoFromHomeAccountId(homeAccountId) {
4120
- if (!homeAccountId) {
4121
- throw createClientAuthError(clientInfoDecodingError);
4122
- }
4123
- const clientInfoParts = homeAccountId.split(Separators.CLIENT_INFO_SEPARATOR, 2);
4124
- return {
4125
- uid: clientInfoParts[0],
4126
- utid: clientInfoParts.length < 2
4127
- ? Constants.EMPTY_STRING
4128
- : clientInfoParts[1],
4129
- };
4130
- }
4131
-
4132
4047
  /*
4133
4048
  * Copyright (c) Microsoft Corporation. All rights reserved.
4134
4049
  * Licensed under the MIT License.
@@ -4154,7 +4069,7 @@ function tenantIdMatchesHomeTenant(tenantId, homeAccountId) {
4154
4069
  */
4155
4070
  function buildTenantProfile(homeAccountId, localAccountId, tenantId, idTokenClaims) {
4156
4071
  if (idTokenClaims) {
4157
- const { oid, sub, tid, name, tfp, acr } = idTokenClaims;
4072
+ const { oid, sub, tid, name, tfp, acr, preferred_username, upn, login_hint, } = idTokenClaims;
4158
4073
  /**
4159
4074
  * Since there is no way to determine if the authority is AAD or B2C, we exhaust all the possible claims that can serve as tenant ID with the following precedence:
4160
4075
  * tid - TenantID claim that identifies the tenant that issued the token in AAD. Expected in all AAD ID tokens, not present in B2C ID Tokens.
@@ -4166,6 +4081,8 @@ function buildTenantProfile(homeAccountId, localAccountId, tenantId, idTokenClai
4166
4081
  tenantId: tenantId,
4167
4082
  localAccountId: oid || sub || "",
4168
4083
  name: name,
4084
+ username: preferred_username || upn || "",
4085
+ loginHint: login_hint,
4169
4086
  isHomeTenant: tenantIdMatchesHomeTenant(tenantId, homeAccountId),
4170
4087
  };
4171
4088
  }
@@ -4173,6 +4090,7 @@ function buildTenantProfile(homeAccountId, localAccountId, tenantId, idTokenClai
4173
4090
  return {
4174
4091
  tenantId,
4175
4092
  localAccountId,
4093
+ username: "",
4176
4094
  isHomeTenant: tenantIdMatchesHomeTenant(tenantId, homeAccountId),
4177
4095
  };
4178
4096
  }
@@ -4211,21 +4129,56 @@ function updateAccountTenantProfileData(baseAccountInfo, tenantProfile, idTokenC
4211
4129
  * Copyright (c) Microsoft Corporation. All rights reserved.
4212
4130
  * Licensed under the MIT License.
4213
4131
  */
4132
+ const cacheQuotaExceeded = "cache_quota_exceeded";
4133
+ const cacheErrorUnknown = "cache_error_unknown";
4134
+
4135
+ var CacheErrorCodes = /*#__PURE__*/Object.freeze({
4136
+ __proto__: null,
4137
+ cacheErrorUnknown: cacheErrorUnknown,
4138
+ cacheQuotaExceeded: cacheQuotaExceeded
4139
+ });
4140
+
4141
+ /*
4142
+ * Copyright (c) Microsoft Corporation. All rights reserved.
4143
+ * Licensed under the MIT License.
4144
+ */
4145
+ const CacheErrorMessages = {
4146
+ [cacheQuotaExceeded]: "Exceeded cache storage capacity.",
4147
+ [cacheErrorUnknown]: "Unexpected error occurred when using cache storage.",
4148
+ };
4214
4149
  /**
4215
- * Gets tenantId from available ID token claims to set as credential realm with the following precedence:
4216
- * 1. tid - if the token is acquired from an Azure AD tenant tid will be present
4217
- * 2. tfp - if the token is acquired from a modern B2C tenant tfp should be present
4218
- * 3. acr - if the token is acquired from a legacy B2C tenant acr should be present
4219
- * Downcased to match the realm case-insensitive comparison requirements
4220
- * @param idTokenClaims
4150
+ * Error thrown when there is an error with the cache
4151
+ */
4152
+ class CacheError extends AuthError {
4153
+ constructor(errorCode, errorMessage) {
4154
+ const message = errorMessage ||
4155
+ (CacheErrorMessages[errorCode]
4156
+ ? CacheErrorMessages[errorCode]
4157
+ : CacheErrorMessages[cacheErrorUnknown]);
4158
+ super(`${errorCode}: ${message}`);
4159
+ Object.setPrototypeOf(this, CacheError.prototype);
4160
+ this.name = "CacheError";
4161
+ this.errorCode = errorCode;
4162
+ this.errorMessage = message;
4163
+ }
4164
+ }
4165
+ /**
4166
+ * Helper function to wrap browser errors in a CacheError object
4167
+ * @param e
4221
4168
  * @returns
4222
4169
  */
4223
- function getTenantIdFromIdTokenClaims(idTokenClaims) {
4224
- if (idTokenClaims) {
4225
- const tenantId = idTokenClaims.tid || idTokenClaims.tfp || idTokenClaims.acr;
4226
- return tenantId || null;
4170
+ function createCacheError(e) {
4171
+ if (!(e instanceof Error)) {
4172
+ return new CacheError(cacheErrorUnknown);
4173
+ }
4174
+ if (e.name === "QuotaExceededError" ||
4175
+ e.name === "NS_ERROR_DOM_QUOTA_REACHED" ||
4176
+ e.message.includes("exceeded the quota")) {
4177
+ return new CacheError(cacheQuotaExceeded);
4178
+ }
4179
+ else {
4180
+ return new CacheError(e.name, e.message);
4227
4181
  }
4228
- return null;
4229
4182
  }
4230
4183
 
4231
4184
  /*
@@ -4233,383 +4186,91 @@ function getTenantIdFromIdTokenClaims(idTokenClaims) {
4233
4186
  * Licensed under the MIT License.
4234
4187
  */
4235
4188
  /**
4236
- * Type that defines required and optional parameters for an Account field (based on universal cache schema implemented by all MSALs).
4237
- *
4238
- * Key : Value Schema
4239
- *
4240
- * Key: <home_account_id>-<environment>-<realm*>
4241
- *
4242
- * Value Schema:
4243
- * {
4244
- * homeAccountId: home account identifier for the auth scheme,
4245
- * environment: entity that issued the token, represented as a full host
4246
- * realm: Full tenant or organizational identifier that the account belongs to
4247
- * localAccountId: Original tenant-specific accountID, usually used for legacy cases
4248
- * username: primary username that represents the user, usually corresponds to preferred_username in the v2 endpt
4249
- * authorityType: Accounts authority type as a string
4250
- * name: Full name for the account, including given name and family name,
4251
- * lastModificationTime: last time this entity was modified in the cache
4252
- * lastModificationApp:
4253
- * nativeAccountId: Account identifier on the native device
4254
- * tenantProfiles: Array of tenant profile objects for each tenant that the account has authenticated with in the browser
4255
- * }
4189
+ * Interface class which implement cache storage functions used by MSAL to perform validity checks, and store tokens.
4256
4190
  * @internal
4257
4191
  */
4258
- class AccountEntity {
4259
- /**
4260
- * Generate Account Id key component as per the schema: <home_account_id>-<environment>
4261
- */
4262
- generateAccountId() {
4263
- const accountId = [this.homeAccountId, this.environment];
4264
- return accountId.join(Separators.CACHE_KEY_SEPARATOR).toLowerCase();
4192
+ class CacheManager {
4193
+ constructor(clientId, cryptoImpl, logger, performanceClient, staticAuthorityOptions) {
4194
+ this.clientId = clientId;
4195
+ this.cryptoImpl = cryptoImpl;
4196
+ this.commonLogger = logger.clone(name, version);
4197
+ this.staticAuthorityOptions = staticAuthorityOptions;
4198
+ this.performanceClient = performanceClient;
4265
4199
  }
4266
4200
  /**
4267
- * Generate Account Cache Key as per the schema: <home_account_id>-<environment>-<realm*>
4201
+ * Returns all the accounts in the cache that match the optional filter. If no filter is provided, all accounts are returned.
4202
+ * @param accountFilter - (Optional) filter to narrow down the accounts returned
4203
+ * @returns Array of AccountInfo objects in cache
4268
4204
  */
4269
- generateAccountKey() {
4270
- return AccountEntity.generateAccountCacheKey({
4271
- homeAccountId: this.homeAccountId,
4272
- environment: this.environment,
4273
- tenantId: this.realm,
4274
- username: this.username,
4275
- localAccountId: this.localAccountId,
4276
- });
4205
+ getAllAccounts(accountFilter, correlationId) {
4206
+ return this.buildTenantProfiles(this.getAccountsFilteredBy(accountFilter, correlationId), correlationId, accountFilter);
4277
4207
  }
4278
4208
  /**
4279
- * Returns the AccountInfo interface for this account.
4209
+ * Gets first tenanted AccountInfo object found based on provided filters
4280
4210
  */
4281
- getAccountInfo() {
4282
- return {
4283
- homeAccountId: this.homeAccountId,
4284
- environment: this.environment,
4285
- tenantId: this.realm,
4286
- username: this.username,
4287
- localAccountId: this.localAccountId,
4288
- name: this.name,
4289
- nativeAccountId: this.nativeAccountId,
4290
- authorityType: this.authorityType,
4291
- // Deserialize tenant profiles array into a Map
4292
- tenantProfiles: new Map((this.tenantProfiles || []).map((tenantProfile) => {
4293
- return [tenantProfile.tenantId, tenantProfile];
4294
- })),
4295
- };
4211
+ getAccountInfoFilteredBy(accountFilter, correlationId) {
4212
+ if (Object.keys(accountFilter).length === 0 ||
4213
+ Object.values(accountFilter).every((value) => !value)) {
4214
+ this.commonLogger.warning("getAccountInfoFilteredBy: Account filter is empty or invalid, returning null");
4215
+ return null;
4216
+ }
4217
+ const allAccounts = this.getAllAccounts(accountFilter, correlationId);
4218
+ if (allAccounts.length > 1) {
4219
+ // If one or more accounts are found, prioritize accounts that have an ID token
4220
+ const sortedAccounts = allAccounts.sort((account) => {
4221
+ return account.idTokenClaims ? -1 : 1;
4222
+ });
4223
+ return sortedAccounts[0];
4224
+ }
4225
+ else if (allAccounts.length === 1) {
4226
+ // If only one account is found, return it regardless of whether a matching ID token was found
4227
+ return allAccounts[0];
4228
+ }
4229
+ else {
4230
+ return null;
4231
+ }
4296
4232
  }
4297
4233
  /**
4298
- * Returns true if the account entity is in single tenant format (outdated), false otherwise
4234
+ * Returns a single matching
4235
+ * @param accountFilter
4236
+ * @returns
4299
4237
  */
4300
- isSingleTenant() {
4301
- return !this.tenantProfiles;
4238
+ getBaseAccountInfo(accountFilter, correlationId) {
4239
+ const accountEntities = this.getAccountsFilteredBy(accountFilter, correlationId);
4240
+ if (accountEntities.length > 0) {
4241
+ return accountEntities[0].getAccountInfo();
4242
+ }
4243
+ else {
4244
+ return null;
4245
+ }
4302
4246
  }
4303
4247
  /**
4304
- * Generates account key from interface
4305
- * @param accountInterface
4248
+ * Matches filtered account entities with cached ID tokens that match the tenant profile-specific account filters
4249
+ * and builds the account info objects from the matching ID token's claims
4250
+ * @param cachedAccounts
4251
+ * @param accountFilter
4252
+ * @returns Array of AccountInfo objects that match account and tenant profile filters
4306
4253
  */
4307
- static generateAccountCacheKey(accountInterface) {
4308
- const homeTenantId = accountInterface.homeAccountId.split(".")[1];
4309
- const accountKey = [
4310
- accountInterface.homeAccountId,
4311
- accountInterface.environment || "",
4312
- homeTenantId || accountInterface.tenantId || "",
4313
- ];
4314
- return accountKey.join(Separators.CACHE_KEY_SEPARATOR).toLowerCase();
4254
+ buildTenantProfiles(cachedAccounts, correlationId, accountFilter) {
4255
+ return cachedAccounts.flatMap((accountEntity) => {
4256
+ return this.getTenantProfilesFromAccountEntity(accountEntity, correlationId, accountFilter?.tenantId, accountFilter);
4257
+ });
4315
4258
  }
4316
- /**
4317
- * Build Account cache from IdToken, clientInfo and authority/policy. Associated with AAD.
4318
- * @param accountDetails
4319
- */
4320
- static createAccount(accountDetails, authority, base64Decode) {
4321
- const account = new AccountEntity();
4322
- if (authority.authorityType === AuthorityType.Adfs) {
4323
- account.authorityType = CacheAccountType.ADFS_ACCOUNT_TYPE;
4324
- }
4325
- else if (authority.protocolMode === ProtocolMode.OIDC) {
4326
- account.authorityType = CacheAccountType.GENERIC_ACCOUNT_TYPE;
4327
- }
4328
- else {
4329
- account.authorityType = CacheAccountType.MSSTS_ACCOUNT_TYPE;
4259
+ getTenantedAccountInfoByFilter(accountInfo, tokenKeys, tenantProfile, correlationId, tenantProfileFilter) {
4260
+ let tenantedAccountInfo = null;
4261
+ let idTokenClaims;
4262
+ if (tenantProfileFilter) {
4263
+ if (!this.tenantProfileMatchesFilter(tenantProfile, tenantProfileFilter)) {
4264
+ return null;
4265
+ }
4330
4266
  }
4331
- let clientInfo;
4332
- if (accountDetails.clientInfo && base64Decode) {
4333
- clientInfo = buildClientInfo(accountDetails.clientInfo, base64Decode);
4334
- }
4335
- account.clientInfo = accountDetails.clientInfo;
4336
- account.homeAccountId = accountDetails.homeAccountId;
4337
- account.nativeAccountId = accountDetails.nativeAccountId;
4338
- const env = accountDetails.environment ||
4339
- (authority && authority.getPreferredCache());
4340
- if (!env) {
4341
- throw createClientAuthError(invalidCacheEnvironment);
4342
- }
4343
- account.environment = env;
4344
- // non AAD scenarios can have empty realm
4345
- account.realm =
4346
- clientInfo?.utid ||
4347
- getTenantIdFromIdTokenClaims(accountDetails.idTokenClaims) ||
4348
- "";
4349
- // How do you account for MSA CID here?
4350
- account.localAccountId =
4351
- clientInfo?.uid ||
4352
- accountDetails.idTokenClaims?.oid ||
4353
- accountDetails.idTokenClaims?.sub ||
4354
- "";
4355
- /*
4356
- * In B2C scenarios the emails claim is used instead of preferred_username and it is an array.
4357
- * In most cases it will contain a single email. This field should not be relied upon if a custom
4358
- * policy is configured to return more than 1 email.
4359
- */
4360
- const preferredUsername = accountDetails.idTokenClaims?.preferred_username ||
4361
- accountDetails.idTokenClaims?.upn;
4362
- const email = accountDetails.idTokenClaims?.emails
4363
- ? accountDetails.idTokenClaims.emails[0]
4364
- : null;
4365
- account.username = preferredUsername || email || "";
4366
- account.name = accountDetails.idTokenClaims?.name || "";
4367
- account.cloudGraphHostName = accountDetails.cloudGraphHostName;
4368
- account.msGraphHost = accountDetails.msGraphHost;
4369
- if (accountDetails.tenantProfiles) {
4370
- account.tenantProfiles = accountDetails.tenantProfiles;
4371
- }
4372
- else {
4373
- const tenantProfile = buildTenantProfile(accountDetails.homeAccountId, account.localAccountId, account.realm, accountDetails.idTokenClaims);
4374
- account.tenantProfiles = [tenantProfile];
4375
- }
4376
- return account;
4377
- }
4378
- /**
4379
- * Creates an AccountEntity object from AccountInfo
4380
- * @param accountInfo
4381
- * @param cloudGraphHostName
4382
- * @param msGraphHost
4383
- * @returns
4384
- */
4385
- static createFromAccountInfo(accountInfo, cloudGraphHostName, msGraphHost) {
4386
- const account = new AccountEntity();
4387
- account.authorityType =
4388
- accountInfo.authorityType || CacheAccountType.GENERIC_ACCOUNT_TYPE;
4389
- account.homeAccountId = accountInfo.homeAccountId;
4390
- account.localAccountId = accountInfo.localAccountId;
4391
- account.nativeAccountId = accountInfo.nativeAccountId;
4392
- account.realm = accountInfo.tenantId;
4393
- account.environment = accountInfo.environment;
4394
- account.username = accountInfo.username;
4395
- account.name = accountInfo.name;
4396
- account.cloudGraphHostName = cloudGraphHostName;
4397
- account.msGraphHost = msGraphHost;
4398
- // Serialize tenant profiles map into an array
4399
- account.tenantProfiles = Array.from(accountInfo.tenantProfiles?.values() || []);
4400
- return account;
4401
- }
4402
- /**
4403
- * Generate HomeAccountId from server response
4404
- * @param serverClientInfo
4405
- * @param authType
4406
- */
4407
- static generateHomeAccountId(serverClientInfo, authType, logger, cryptoObj, idTokenClaims) {
4408
- // since ADFS/DSTS do not have tid and does not set client_info
4409
- if (!(authType === AuthorityType.Adfs ||
4410
- authType === AuthorityType.Dsts)) {
4411
- // for cases where there is clientInfo
4412
- if (serverClientInfo) {
4413
- try {
4414
- const clientInfo = buildClientInfo(serverClientInfo, cryptoObj.base64Decode);
4415
- if (clientInfo.uid && clientInfo.utid) {
4416
- return `${clientInfo.uid}.${clientInfo.utid}`;
4417
- }
4418
- }
4419
- catch (e) { }
4420
- }
4421
- logger.warning("No client info in response");
4422
- }
4423
- // default to "sub" claim
4424
- return idTokenClaims?.sub || "";
4425
- }
4426
- /**
4427
- * Validates an entity: checks for all expected params
4428
- * @param entity
4429
- */
4430
- static isAccountEntity(entity) {
4431
- if (!entity) {
4432
- return false;
4433
- }
4434
- return (entity.hasOwnProperty("homeAccountId") &&
4435
- entity.hasOwnProperty("environment") &&
4436
- entity.hasOwnProperty("realm") &&
4437
- entity.hasOwnProperty("localAccountId") &&
4438
- entity.hasOwnProperty("username") &&
4439
- entity.hasOwnProperty("authorityType"));
4440
- }
4441
- /**
4442
- * Helper function to determine whether 2 accountInfo objects represent the same account
4443
- * @param accountA
4444
- * @param accountB
4445
- * @param compareClaims - If set to true idTokenClaims will also be compared to determine account equality
4446
- */
4447
- static accountInfoIsEqual(accountA, accountB, compareClaims) {
4448
- if (!accountA || !accountB) {
4449
- return false;
4450
- }
4451
- let claimsMatch = true; // default to true so as to not fail comparison below if compareClaims: false
4452
- if (compareClaims) {
4453
- const accountAClaims = (accountA.idTokenClaims ||
4454
- {});
4455
- const accountBClaims = (accountB.idTokenClaims ||
4456
- {});
4457
- // issued at timestamp and nonce are expected to change each time a new id token is acquired
4458
- claimsMatch =
4459
- accountAClaims.iat === accountBClaims.iat &&
4460
- accountAClaims.nonce === accountBClaims.nonce;
4461
- }
4462
- return (accountA.homeAccountId === accountB.homeAccountId &&
4463
- accountA.localAccountId === accountB.localAccountId &&
4464
- accountA.username === accountB.username &&
4465
- accountA.tenantId === accountB.tenantId &&
4466
- accountA.environment === accountB.environment &&
4467
- accountA.nativeAccountId === accountB.nativeAccountId &&
4468
- claimsMatch);
4469
- }
4470
- }
4471
-
4472
- /*
4473
- * Copyright (c) Microsoft Corporation. All rights reserved.
4474
- * Licensed under the MIT License.
4475
- */
4476
- const cacheQuotaExceeded = "cache_quota_exceeded";
4477
- const cacheErrorUnknown = "cache_error_unknown";
4478
-
4479
- var CacheErrorCodes = /*#__PURE__*/Object.freeze({
4480
- __proto__: null,
4481
- cacheErrorUnknown: cacheErrorUnknown,
4482
- cacheQuotaExceeded: cacheQuotaExceeded
4483
- });
4484
-
4485
- /*
4486
- * Copyright (c) Microsoft Corporation. All rights reserved.
4487
- * Licensed under the MIT License.
4488
- */
4489
- const CacheErrorMessages = {
4490
- [cacheQuotaExceeded]: "Exceeded cache storage capacity.",
4491
- [cacheErrorUnknown]: "Unexpected error occurred when using cache storage.",
4492
- };
4493
- /**
4494
- * Error thrown when there is an error with the cache
4495
- */
4496
- class CacheError extends AuthError {
4497
- constructor(errorCode, errorMessage) {
4498
- const message = errorMessage ||
4499
- (CacheErrorMessages[errorCode]
4500
- ? CacheErrorMessages[errorCode]
4501
- : CacheErrorMessages[cacheErrorUnknown]);
4502
- super(`${errorCode}: ${message}`);
4503
- Object.setPrototypeOf(this, CacheError.prototype);
4504
- this.name = "CacheError";
4505
- this.errorCode = errorCode;
4506
- this.errorMessage = message;
4507
- }
4508
- }
4509
- /**
4510
- * Helper function to wrap browser errors in a CacheError object
4511
- * @param e
4512
- * @returns
4513
- */
4514
- function createCacheError(e) {
4515
- if (!(e instanceof Error)) {
4516
- return new CacheError(cacheErrorUnknown);
4517
- }
4518
- if (e.name === "QuotaExceededError" ||
4519
- e.name === "NS_ERROR_DOM_QUOTA_REACHED" ||
4520
- e.message.includes("exceeded the quota")) {
4521
- return new CacheError(cacheQuotaExceeded);
4522
- }
4523
- else {
4524
- return new CacheError(e.name, e.message);
4525
- }
4526
- }
4527
-
4528
- /*
4529
- * Copyright (c) Microsoft Corporation. All rights reserved.
4530
- * Licensed under the MIT License.
4531
- */
4532
- /**
4533
- * Interface class which implement cache storage functions used by MSAL to perform validity checks, and store tokens.
4534
- * @internal
4535
- */
4536
- class CacheManager {
4537
- constructor(clientId, cryptoImpl, logger, performanceClient, staticAuthorityOptions) {
4538
- this.clientId = clientId;
4539
- this.cryptoImpl = cryptoImpl;
4540
- this.commonLogger = logger.clone(name, version);
4541
- this.staticAuthorityOptions = staticAuthorityOptions;
4542
- this.performanceClient = performanceClient;
4543
- }
4544
- /**
4545
- * Returns all the accounts in the cache that match the optional filter. If no filter is provided, all accounts are returned.
4546
- * @param accountFilter - (Optional) filter to narrow down the accounts returned
4547
- * @returns Array of AccountInfo objects in cache
4548
- */
4549
- getAllAccounts(accountFilter, correlationId) {
4550
- return this.buildTenantProfiles(this.getAccountsFilteredBy(accountFilter, correlationId), correlationId, accountFilter);
4551
- }
4552
- /**
4553
- * Gets first tenanted AccountInfo object found based on provided filters
4554
- */
4555
- getAccountInfoFilteredBy(accountFilter, correlationId) {
4556
- const allAccounts = this.getAllAccounts(accountFilter, correlationId);
4557
- if (allAccounts.length > 1) {
4558
- // If one or more accounts are found, prioritize accounts that have an ID token
4559
- const sortedAccounts = allAccounts.sort((account) => {
4560
- return account.idTokenClaims ? -1 : 1;
4561
- });
4562
- return sortedAccounts[0];
4563
- }
4564
- else if (allAccounts.length === 1) {
4565
- // If only one account is found, return it regardless of whether a matching ID token was found
4566
- return allAccounts[0];
4567
- }
4568
- else {
4569
- return null;
4570
- }
4571
- }
4572
- /**
4573
- * Returns a single matching
4574
- * @param accountFilter
4575
- * @returns
4576
- */
4577
- getBaseAccountInfo(accountFilter, correlationId) {
4578
- const accountEntities = this.getAccountsFilteredBy(accountFilter, correlationId);
4579
- if (accountEntities.length > 0) {
4580
- return accountEntities[0].getAccountInfo();
4581
- }
4582
- else {
4583
- return null;
4584
- }
4585
- }
4586
- /**
4587
- * Matches filtered account entities with cached ID tokens that match the tenant profile-specific account filters
4588
- * and builds the account info objects from the matching ID token's claims
4589
- * @param cachedAccounts
4590
- * @param accountFilter
4591
- * @returns Array of AccountInfo objects that match account and tenant profile filters
4592
- */
4593
- buildTenantProfiles(cachedAccounts, correlationId, accountFilter) {
4594
- return cachedAccounts.flatMap((accountEntity) => {
4595
- return this.getTenantProfilesFromAccountEntity(accountEntity, correlationId, accountFilter?.tenantId, accountFilter);
4596
- });
4597
- }
4598
- getTenantedAccountInfoByFilter(accountInfo, tokenKeys, tenantProfile, correlationId, tenantProfileFilter) {
4599
- let tenantedAccountInfo = null;
4600
- let idTokenClaims;
4601
- if (tenantProfileFilter) {
4602
- if (!this.tenantProfileMatchesFilter(tenantProfile, tenantProfileFilter)) {
4603
- return null;
4604
- }
4605
- }
4606
- const idToken = this.getIdToken(accountInfo, correlationId, tokenKeys, tenantProfile.tenantId);
4607
- if (idToken) {
4608
- idTokenClaims = extractTokenClaims(idToken.secret, this.cryptoImpl.base64Decode);
4609
- if (!this.idTokenClaimsMatchTenantProfileFilter(idTokenClaims, tenantProfileFilter)) {
4610
- // ID token sourced claims don't match so this tenant profile is not a match
4611
- return null;
4612
- }
4267
+ const idToken = this.getIdToken(accountInfo, correlationId, tokenKeys, tenantProfile.tenantId);
4268
+ if (idToken) {
4269
+ idTokenClaims = extractTokenClaims(idToken.secret, this.cryptoImpl.base64Decode);
4270
+ if (!this.idTokenClaimsMatchTenantProfileFilter(idTokenClaims, tenantProfileFilter)) {
4271
+ // ID token sourced claims don't match so this tenant profile is not a match
4272
+ return null;
4273
+ }
4613
4274
  }
4614
4275
  // Expand tenant profile into account info based on matching tenant profile and if available matching ID token claims
4615
4276
  tenantedAccountInfo = updateAccountTenantProfileData(accountInfo, tenantProfile, idTokenClaims, idToken?.secret);
@@ -4762,10 +4423,6 @@ class CacheManager {
4762
4423
  const allAccountKeys = this.getAccountKeys();
4763
4424
  const matchingAccounts = [];
4764
4425
  allAccountKeys.forEach((cacheKey) => {
4765
- if (!this.isAccountKey(cacheKey, accountFilter.homeAccountId)) {
4766
- // Don't parse value if the key doesn't match the account filters
4767
- return;
4768
- }
4769
4426
  const entity = this.getAccount(cacheKey, correlationId);
4770
4427
  // Match base account fields
4771
4428
  if (!entity) {
@@ -4811,64 +4468,6 @@ class CacheManager {
4811
4468
  });
4812
4469
  return matchingAccounts;
4813
4470
  }
4814
- /**
4815
- * Returns true if the given key matches our account key schema. Also matches homeAccountId and/or tenantId if provided
4816
- * @param key
4817
- * @param homeAccountId
4818
- * @param tenantId
4819
- * @returns
4820
- */
4821
- isAccountKey(key, homeAccountId, tenantId) {
4822
- if (key.split(Separators.CACHE_KEY_SEPARATOR).length < 3) {
4823
- // Account cache keys contain 3 items separated by '-' (each item may also contain '-')
4824
- return false;
4825
- }
4826
- if (homeAccountId &&
4827
- !key.toLowerCase().includes(homeAccountId.toLowerCase())) {
4828
- return false;
4829
- }
4830
- if (tenantId && !key.toLowerCase().includes(tenantId.toLowerCase())) {
4831
- return false;
4832
- }
4833
- // Do not check environment as aliasing can cause false negatives
4834
- return true;
4835
- }
4836
- /**
4837
- * Returns true if the given key matches our credential key schema.
4838
- * @param key
4839
- */
4840
- isCredentialKey(key) {
4841
- if (key.split(Separators.CACHE_KEY_SEPARATOR).length < 6) {
4842
- // Credential cache keys contain 6 items separated by '-' (each item may also contain '-')
4843
- return false;
4844
- }
4845
- const lowerCaseKey = key.toLowerCase();
4846
- // Credential keys must indicate what credential type they represent
4847
- if (lowerCaseKey.indexOf(CredentialType.ID_TOKEN.toLowerCase()) ===
4848
- -1 &&
4849
- lowerCaseKey.indexOf(CredentialType.ACCESS_TOKEN.toLowerCase()) ===
4850
- -1 &&
4851
- lowerCaseKey.indexOf(CredentialType.ACCESS_TOKEN_WITH_AUTH_SCHEME.toLowerCase()) === -1 &&
4852
- lowerCaseKey.indexOf(CredentialType.REFRESH_TOKEN.toLowerCase()) ===
4853
- -1) {
4854
- return false;
4855
- }
4856
- if (lowerCaseKey.indexOf(CredentialType.REFRESH_TOKEN.toLowerCase()) >
4857
- -1) {
4858
- // Refresh tokens must contain the client id or family id
4859
- const clientIdValidation = `${CredentialType.REFRESH_TOKEN}${Separators.CACHE_KEY_SEPARATOR}${this.clientId}${Separators.CACHE_KEY_SEPARATOR}`;
4860
- const familyIdValidation = `${CredentialType.REFRESH_TOKEN}${Separators.CACHE_KEY_SEPARATOR}${THE_FAMILY_ID}${Separators.CACHE_KEY_SEPARATOR}`;
4861
- if (lowerCaseKey.indexOf(clientIdValidation.toLowerCase()) === -1 &&
4862
- lowerCaseKey.indexOf(familyIdValidation.toLowerCase()) === -1) {
4863
- return false;
4864
- }
4865
- }
4866
- else if (lowerCaseKey.indexOf(this.clientId.toLowerCase()) === -1) {
4867
- // Tokens must contain the clientId
4868
- return false;
4869
- }
4870
- return true;
4871
- }
4872
4471
  /**
4873
4472
  * Returns whether or not the given credential entity matches the filter
4874
4473
  * @param entity
@@ -4993,22 +4592,26 @@ class CacheManager {
4993
4592
  * Removes all accounts and related tokens from cache.
4994
4593
  */
4995
4594
  removeAllAccounts(correlationId) {
4996
- const allAccountKeys = this.getAccountKeys();
4997
- allAccountKeys.forEach((cacheKey) => {
4998
- this.removeAccount(cacheKey, correlationId);
4595
+ const accounts = this.getAllAccounts({}, correlationId);
4596
+ accounts.forEach((account) => {
4597
+ this.removeAccount(account, correlationId);
4999
4598
  });
5000
4599
  }
5001
4600
  /**
5002
4601
  * Removes the account and related tokens for a given account key
5003
4602
  * @param account
5004
4603
  */
5005
- removeAccount(accountKey, correlationId) {
5006
- const account = this.getAccount(accountKey, correlationId);
5007
- if (!account) {
5008
- return;
5009
- }
4604
+ removeAccount(account, correlationId) {
5010
4605
  this.removeAccountContext(account, correlationId);
5011
- this.removeItem(accountKey, correlationId);
4606
+ const accountKeys = this.getAccountKeys();
4607
+ const keyFilter = (key) => {
4608
+ return (key.includes(account.homeAccountId) &&
4609
+ key.includes(account.environment));
4610
+ };
4611
+ accountKeys.filter(keyFilter).forEach((key) => {
4612
+ this.removeItem(key, correlationId);
4613
+ this.performanceClient.incrementFields({ accountsRemoved: 1 }, correlationId);
4614
+ });
5012
4615
  }
5013
4616
  /**
5014
4617
  * Removes credentials associated with the provided account
@@ -5016,21 +4619,18 @@ class CacheManager {
5016
4619
  */
5017
4620
  removeAccountContext(account, correlationId) {
5018
4621
  const allTokenKeys = this.getTokenKeys();
5019
- const accountId = account.generateAccountId();
5020
- allTokenKeys.idToken.forEach((key) => {
5021
- if (key.indexOf(accountId) === 0) {
5022
- this.removeIdToken(key, correlationId);
5023
- }
4622
+ const keyFilter = (key) => {
4623
+ return (key.includes(account.homeAccountId) &&
4624
+ key.includes(account.environment));
4625
+ };
4626
+ allTokenKeys.idToken.filter(keyFilter).forEach((key) => {
4627
+ this.removeIdToken(key, correlationId);
5024
4628
  });
5025
- allTokenKeys.accessToken.forEach((key) => {
5026
- if (key.indexOf(accountId) === 0) {
5027
- this.removeAccessToken(key, correlationId);
5028
- }
4629
+ allTokenKeys.accessToken.filter(keyFilter).forEach((key) => {
4630
+ this.removeAccessToken(key, correlationId);
5029
4631
  });
5030
- allTokenKeys.refreshToken.forEach((key) => {
5031
- if (key.indexOf(accountId) === 0) {
5032
- this.removeRefreshToken(key, correlationId);
5033
- }
4632
+ allTokenKeys.refreshToken.filter(keyFilter).forEach((key) => {
4633
+ this.removeRefreshToken(key, correlationId);
5034
4634
  });
5035
4635
  }
5036
4636
  /**
@@ -5070,14 +4670,6 @@ class CacheManager {
5070
4670
  });
5071
4671
  return true;
5072
4672
  }
5073
- /**
5074
- * Retrieve AccountEntity from cache
5075
- * @param account
5076
- */
5077
- readAccountFromCache(account, correlationId) {
5078
- const accountKey = AccountEntity.generateAccountCacheKey(account);
5079
- return this.getAccount(accountKey, correlationId);
5080
- }
5081
4673
  /**
5082
4674
  * Retrieve IdTokenEntity from cache
5083
4675
  * @param account {AccountInfo}
@@ -5247,7 +4839,7 @@ class CacheManager {
5247
4839
  else if (numAccessTokens > 1) {
5248
4840
  this.commonLogger.info("CacheManager:getAccessToken - Multiple access tokens found, clearing them", correlationId);
5249
4841
  accessTokens.forEach((accessToken) => {
5250
- this.removeAccessToken(generateCredentialKey(accessToken), correlationId);
4842
+ this.removeAccessToken(this.generateCredentialKey(accessToken), correlationId);
5251
4843
  });
5252
4844
  this.performanceClient.addFields({ multiMatchedAT: accessTokens.length }, correlationId);
5253
4845
  return null;
@@ -5688,6 +5280,12 @@ class DefaultStorageClass extends CacheManager {
5688
5280
  getTokenKeys() {
5689
5281
  throw createClientAuthError(methodNotImplemented);
5690
5282
  }
5283
+ generateCredentialKey() {
5284
+ throw createClientAuthError(methodNotImplemented);
5285
+ }
5286
+ generateAccountKey() {
5287
+ throw createClientAuthError(methodNotImplemented);
5288
+ }
5691
5289
  }
5692
5290
 
5693
5291
  /*
@@ -5858,22 +5456,60 @@ function buildAuthOptions(authOptions) {
5858
5456
  };
5859
5457
  }
5860
5458
  /**
5861
- * Returns true if config has protocolMode set to ProtocolMode.OIDC, false otherwise
5862
- * @param ClientConfiguration
5459
+ * Returns true if config has protocolMode set to ProtocolMode.OIDC, false otherwise
5460
+ * @param ClientConfiguration
5461
+ */
5462
+ function isOidcProtocolMode(config) {
5463
+ return (config.authOptions.authority.options.protocolMode === ProtocolMode.OIDC);
5464
+ }
5465
+
5466
+ /*
5467
+ * Copyright (c) Microsoft Corporation. All rights reserved.
5468
+ * Licensed under the MIT License.
5469
+ */
5470
+ const CcsCredentialType = {
5471
+ HOME_ACCOUNT_ID: "home_account_id",
5472
+ UPN: "UPN",
5473
+ };
5474
+
5475
+ /*
5476
+ * Copyright (c) Microsoft Corporation. All rights reserved.
5477
+ * Licensed under the MIT License.
5478
+ */
5479
+ /**
5480
+ * Function to build a client info object from server clientInfo string
5481
+ * @param rawClientInfo
5482
+ * @param crypto
5483
+ */
5484
+ function buildClientInfo(rawClientInfo, base64Decode) {
5485
+ if (!rawClientInfo) {
5486
+ throw createClientAuthError(clientInfoEmptyError);
5487
+ }
5488
+ try {
5489
+ const decodedClientInfo = base64Decode(rawClientInfo);
5490
+ return JSON.parse(decodedClientInfo);
5491
+ }
5492
+ catch (e) {
5493
+ throw createClientAuthError(clientInfoDecodingError);
5494
+ }
5495
+ }
5496
+ /**
5497
+ * Function to build a client info object from cached homeAccountId string
5498
+ * @param homeAccountId
5863
5499
  */
5864
- function isOidcProtocolMode(config) {
5865
- return (config.authOptions.authority.options.protocolMode === ProtocolMode.OIDC);
5500
+ function buildClientInfoFromHomeAccountId(homeAccountId) {
5501
+ if (!homeAccountId) {
5502
+ throw createClientAuthError(clientInfoDecodingError);
5503
+ }
5504
+ const clientInfoParts = homeAccountId.split(Separators.CLIENT_INFO_SEPARATOR, 2);
5505
+ return {
5506
+ uid: clientInfoParts[0],
5507
+ utid: clientInfoParts.length < 2
5508
+ ? Constants.EMPTY_STRING
5509
+ : clientInfoParts[1],
5510
+ };
5866
5511
  }
5867
5512
 
5868
- /*
5869
- * Copyright (c) Microsoft Corporation. All rights reserved.
5870
- * Licensed under the MIT License.
5871
- */
5872
- const CcsCredentialType = {
5873
- HOME_ACCOUNT_ID: "home_account_id",
5874
- UPN: "UPN",
5875
- };
5876
-
5877
5513
  /*
5878
5514
  * Copyright (c) Microsoft Corporation. All rights reserved.
5879
5515
  * Licensed under the MIT License.
@@ -6634,6 +6270,240 @@ class BaseClient {
6634
6270
  }
6635
6271
  }
6636
6272
 
6273
+ /*
6274
+ * Copyright (c) Microsoft Corporation. All rights reserved.
6275
+ * Licensed under the MIT License.
6276
+ */
6277
+ /**
6278
+ * Gets tenantId from available ID token claims to set as credential realm with the following precedence:
6279
+ * 1. tid - if the token is acquired from an Azure AD tenant tid will be present
6280
+ * 2. tfp - if the token is acquired from a modern B2C tenant tfp should be present
6281
+ * 3. acr - if the token is acquired from a legacy B2C tenant acr should be present
6282
+ * Downcased to match the realm case-insensitive comparison requirements
6283
+ * @param idTokenClaims
6284
+ * @returns
6285
+ */
6286
+ function getTenantIdFromIdTokenClaims(idTokenClaims) {
6287
+ if (idTokenClaims) {
6288
+ const tenantId = idTokenClaims.tid || idTokenClaims.tfp || idTokenClaims.acr;
6289
+ return tenantId || null;
6290
+ }
6291
+ return null;
6292
+ }
6293
+
6294
+ /*
6295
+ * Copyright (c) Microsoft Corporation. All rights reserved.
6296
+ * Licensed under the MIT License.
6297
+ */
6298
+ /**
6299
+ * Type that defines required and optional parameters for an Account field (based on universal cache schema implemented by all MSALs).
6300
+ *
6301
+ * Key : Value Schema
6302
+ *
6303
+ * Key: <home_account_id>-<environment>-<realm*>
6304
+ *
6305
+ * Value Schema:
6306
+ * {
6307
+ * homeAccountId: home account identifier for the auth scheme,
6308
+ * environment: entity that issued the token, represented as a full host
6309
+ * realm: Full tenant or organizational identifier that the account belongs to
6310
+ * localAccountId: Original tenant-specific accountID, usually used for legacy cases
6311
+ * username: primary username that represents the user, usually corresponds to preferred_username in the v2 endpt
6312
+ * authorityType: Accounts authority type as a string
6313
+ * name: Full name for the account, including given name and family name,
6314
+ * lastModificationTime: last time this entity was modified in the cache
6315
+ * lastModificationApp:
6316
+ * nativeAccountId: Account identifier on the native device
6317
+ * tenantProfiles: Array of tenant profile objects for each tenant that the account has authenticated with in the browser
6318
+ * }
6319
+ * @internal
6320
+ */
6321
+ class AccountEntity {
6322
+ /**
6323
+ * Returns the AccountInfo interface for this account.
6324
+ */
6325
+ getAccountInfo() {
6326
+ return {
6327
+ homeAccountId: this.homeAccountId,
6328
+ environment: this.environment,
6329
+ tenantId: this.realm,
6330
+ username: this.username,
6331
+ localAccountId: this.localAccountId,
6332
+ loginHint: this.loginHint,
6333
+ name: this.name,
6334
+ nativeAccountId: this.nativeAccountId,
6335
+ authorityType: this.authorityType,
6336
+ // Deserialize tenant profiles array into a Map
6337
+ tenantProfiles: new Map((this.tenantProfiles || []).map((tenantProfile) => {
6338
+ return [tenantProfile.tenantId, tenantProfile];
6339
+ })),
6340
+ };
6341
+ }
6342
+ /**
6343
+ * Returns true if the account entity is in single tenant format (outdated), false otherwise
6344
+ */
6345
+ isSingleTenant() {
6346
+ return !this.tenantProfiles;
6347
+ }
6348
+ /**
6349
+ * Build Account cache from IdToken, clientInfo and authority/policy. Associated with AAD.
6350
+ * @param accountDetails
6351
+ */
6352
+ static createAccount(accountDetails, authority, base64Decode) {
6353
+ const account = new AccountEntity();
6354
+ if (authority.authorityType === AuthorityType.Adfs) {
6355
+ account.authorityType = CacheAccountType.ADFS_ACCOUNT_TYPE;
6356
+ }
6357
+ else if (authority.protocolMode === ProtocolMode.OIDC) {
6358
+ account.authorityType = CacheAccountType.GENERIC_ACCOUNT_TYPE;
6359
+ }
6360
+ else {
6361
+ account.authorityType = CacheAccountType.MSSTS_ACCOUNT_TYPE;
6362
+ }
6363
+ let clientInfo;
6364
+ if (accountDetails.clientInfo && base64Decode) {
6365
+ clientInfo = buildClientInfo(accountDetails.clientInfo, base64Decode);
6366
+ }
6367
+ account.clientInfo = accountDetails.clientInfo;
6368
+ account.homeAccountId = accountDetails.homeAccountId;
6369
+ account.nativeAccountId = accountDetails.nativeAccountId;
6370
+ const env = accountDetails.environment ||
6371
+ (authority && authority.getPreferredCache());
6372
+ if (!env) {
6373
+ throw createClientAuthError(invalidCacheEnvironment);
6374
+ }
6375
+ account.environment = env;
6376
+ // non AAD scenarios can have empty realm
6377
+ account.realm =
6378
+ clientInfo?.utid ||
6379
+ getTenantIdFromIdTokenClaims(accountDetails.idTokenClaims) ||
6380
+ "";
6381
+ // How do you account for MSA CID here?
6382
+ account.localAccountId =
6383
+ clientInfo?.uid ||
6384
+ accountDetails.idTokenClaims?.oid ||
6385
+ accountDetails.idTokenClaims?.sub ||
6386
+ "";
6387
+ /*
6388
+ * In B2C scenarios the emails claim is used instead of preferred_username and it is an array.
6389
+ * In most cases it will contain a single email. This field should not be relied upon if a custom
6390
+ * policy is configured to return more than 1 email.
6391
+ */
6392
+ const preferredUsername = accountDetails.idTokenClaims?.preferred_username ||
6393
+ accountDetails.idTokenClaims?.upn;
6394
+ const email = accountDetails.idTokenClaims?.emails
6395
+ ? accountDetails.idTokenClaims.emails[0]
6396
+ : null;
6397
+ account.username = preferredUsername || email || "";
6398
+ account.loginHint = accountDetails.idTokenClaims?.login_hint;
6399
+ account.name = accountDetails.idTokenClaims?.name || "";
6400
+ account.cloudGraphHostName = accountDetails.cloudGraphHostName;
6401
+ account.msGraphHost = accountDetails.msGraphHost;
6402
+ if (accountDetails.tenantProfiles) {
6403
+ account.tenantProfiles = accountDetails.tenantProfiles;
6404
+ }
6405
+ else {
6406
+ const tenantProfile = buildTenantProfile(accountDetails.homeAccountId, account.localAccountId, account.realm, accountDetails.idTokenClaims);
6407
+ account.tenantProfiles = [tenantProfile];
6408
+ }
6409
+ return account;
6410
+ }
6411
+ /**
6412
+ * Creates an AccountEntity object from AccountInfo
6413
+ * @param accountInfo
6414
+ * @param cloudGraphHostName
6415
+ * @param msGraphHost
6416
+ * @returns
6417
+ */
6418
+ static createFromAccountInfo(accountInfo, cloudGraphHostName, msGraphHost) {
6419
+ const account = new AccountEntity();
6420
+ account.authorityType =
6421
+ accountInfo.authorityType || CacheAccountType.GENERIC_ACCOUNT_TYPE;
6422
+ account.homeAccountId = accountInfo.homeAccountId;
6423
+ account.localAccountId = accountInfo.localAccountId;
6424
+ account.nativeAccountId = accountInfo.nativeAccountId;
6425
+ account.realm = accountInfo.tenantId;
6426
+ account.environment = accountInfo.environment;
6427
+ account.username = accountInfo.username;
6428
+ account.name = accountInfo.name;
6429
+ account.loginHint = accountInfo.loginHint;
6430
+ account.cloudGraphHostName = cloudGraphHostName;
6431
+ account.msGraphHost = msGraphHost;
6432
+ // Serialize tenant profiles map into an array
6433
+ account.tenantProfiles = Array.from(accountInfo.tenantProfiles?.values() || []);
6434
+ return account;
6435
+ }
6436
+ /**
6437
+ * Generate HomeAccountId from server response
6438
+ * @param serverClientInfo
6439
+ * @param authType
6440
+ */
6441
+ static generateHomeAccountId(serverClientInfo, authType, logger, cryptoObj, idTokenClaims) {
6442
+ // since ADFS/DSTS do not have tid and does not set client_info
6443
+ if (!(authType === AuthorityType.Adfs ||
6444
+ authType === AuthorityType.Dsts)) {
6445
+ // for cases where there is clientInfo
6446
+ if (serverClientInfo) {
6447
+ try {
6448
+ const clientInfo = buildClientInfo(serverClientInfo, cryptoObj.base64Decode);
6449
+ if (clientInfo.uid && clientInfo.utid) {
6450
+ return `${clientInfo.uid}.${clientInfo.utid}`;
6451
+ }
6452
+ }
6453
+ catch (e) { }
6454
+ }
6455
+ logger.warning("No client info in response");
6456
+ }
6457
+ // default to "sub" claim
6458
+ return idTokenClaims?.sub || "";
6459
+ }
6460
+ /**
6461
+ * Validates an entity: checks for all expected params
6462
+ * @param entity
6463
+ */
6464
+ static isAccountEntity(entity) {
6465
+ if (!entity) {
6466
+ return false;
6467
+ }
6468
+ return (entity.hasOwnProperty("homeAccountId") &&
6469
+ entity.hasOwnProperty("environment") &&
6470
+ entity.hasOwnProperty("realm") &&
6471
+ entity.hasOwnProperty("localAccountId") &&
6472
+ entity.hasOwnProperty("username") &&
6473
+ entity.hasOwnProperty("authorityType"));
6474
+ }
6475
+ /**
6476
+ * Helper function to determine whether 2 accountInfo objects represent the same account
6477
+ * @param accountA
6478
+ * @param accountB
6479
+ * @param compareClaims - If set to true idTokenClaims will also be compared to determine account equality
6480
+ */
6481
+ static accountInfoIsEqual(accountA, accountB, compareClaims) {
6482
+ if (!accountA || !accountB) {
6483
+ return false;
6484
+ }
6485
+ let claimsMatch = true; // default to true so as to not fail comparison below if compareClaims: false
6486
+ if (compareClaims) {
6487
+ const accountAClaims = (accountA.idTokenClaims ||
6488
+ {});
6489
+ const accountBClaims = (accountB.idTokenClaims ||
6490
+ {});
6491
+ // issued at timestamp and nonce are expected to change each time a new id token is acquired
6492
+ claimsMatch =
6493
+ accountAClaims.iat === accountBClaims.iat &&
6494
+ accountAClaims.nonce === accountBClaims.nonce;
6495
+ }
6496
+ return (accountA.homeAccountId === accountB.homeAccountId &&
6497
+ accountA.localAccountId === accountB.localAccountId &&
6498
+ accountA.username === accountB.username &&
6499
+ accountA.tenantId === accountB.tenantId &&
6500
+ accountA.loginHint === accountB.loginHint &&
6501
+ accountA.environment === accountB.environment &&
6502
+ accountA.nativeAccountId === accountB.nativeAccountId &&
6503
+ claimsMatch);
6504
+ }
6505
+ }
6506
+
6637
6507
  /*
6638
6508
  * Copyright (c) Microsoft Corporation. All rights reserved.
6639
6509
  * Licensed under the MIT License.
@@ -7035,7 +6905,7 @@ class ResponseHandler {
7035
6905
  if (handlingRefreshTokenResponse &&
7036
6906
  !forceCacheRefreshTokenResponse &&
7037
6907
  cacheRecord.account) {
7038
- const key = cacheRecord.account.generateAccountKey();
6908
+ const key = this.cacheStorage.generateAccountKey(cacheRecord.account.getAccountInfo());
7039
6909
  const account = this.cacheStorage.getAccount(key, request.correlationId);
7040
6910
  if (!account) {
7041
6911
  this.logger.warning("Account used to refresh tokens not in persistence, refreshed tokens will not be stored in the cache");
@@ -7609,7 +7479,7 @@ class RefreshTokenClient extends BaseClient {
7609
7479
  if (e.subError === badToken) {
7610
7480
  // Remove bad refresh token from cache
7611
7481
  this.logger.verbose("acquireTokenWithRefreshToken: bad refresh token, removing from cache");
7612
- const badRefreshTokenKey = generateCredentialKey(refreshToken);
7482
+ const badRefreshTokenKey = this.cacheManager.generateCredentialKey(refreshToken);
7613
7483
  this.cacheManager.removeRefreshToken(badRefreshTokenKey, request.correlationId);
7614
7484
  }
7615
7485
  }
@@ -7766,7 +7636,7 @@ class SilentFlowClient extends BaseClient {
7766
7636
  }
7767
7637
  const environment = request.authority || this.authority.getPreferredCache();
7768
7638
  const cacheRecord = {
7769
- account: this.cacheManager.readAccountFromCache(request.account, request.correlationId),
7639
+ account: this.cacheManager.getAccount(this.cacheManager.generateAccountKey(request.account), request.correlationId),
7770
7640
  accessToken: cachedAccessToken,
7771
7641
  idToken: this.cacheManager.getIdToken(request.account, request.correlationId, tokenKeys, requestTenantId, this.performanceClient),
7772
7642
  refreshToken: null,
@@ -8044,7 +7914,7 @@ function extractAccountSid(account) {
8044
7914
  return account.idTokenClaims?.sid || null;
8045
7915
  }
8046
7916
  function extractLoginHint(account) {
8047
- return account.idTokenClaims?.login_hint || null;
7917
+ return account.loginHint || account.idTokenClaims?.login_hint || null;
8048
7918
  }
8049
7919
 
8050
7920
  var Authorize = /*#__PURE__*/Object.freeze({
@@ -8476,4 +8346,4 @@ exports.invokeAsync = invokeAsync;
8476
8346
  exports.tenantIdMatchesHomeTenant = tenantIdMatchesHomeTenant;
8477
8347
  exports.updateAccountTenantProfileData = updateAccountTenantProfileData;
8478
8348
  exports.version = version;
8479
- //# sourceMappingURL=index-node-C5c-lcoe.js.map
8349
+ //# sourceMappingURL=index-node-CtW_2rqJ.js.map