@azure/msal-browser 4.8.0 → 4.9.1

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 (202) 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.mjs +1 -1
  7. package/dist/cache/AsyncMemoryStorage.mjs +1 -1
  8. package/dist/cache/BrowserCacheManager.d.ts +4 -41
  9. package/dist/cache/BrowserCacheManager.d.ts.map +1 -1
  10. package/dist/cache/BrowserCacheManager.mjs +18 -143
  11. package/dist/cache/BrowserCacheManager.mjs.map +1 -1
  12. package/dist/cache/CacheHelpers.mjs +1 -1
  13. package/dist/cache/CookieStorage.mjs +1 -1
  14. package/dist/cache/DatabaseStorage.mjs +1 -1
  15. package/dist/cache/LocalStorage.mjs +2 -2
  16. package/dist/cache/MemoryStorage.mjs +1 -1
  17. package/dist/cache/SessionStorage.mjs +1 -1
  18. package/dist/cache/TokenCache.mjs +1 -1
  19. package/dist/config/Configuration.mjs +5 -5
  20. package/dist/config/Configuration.mjs.map +1 -1
  21. package/dist/controllers/ControllerFactory.mjs +1 -1
  22. package/dist/controllers/NestedAppAuthController.d.ts +2 -2
  23. package/dist/controllers/NestedAppAuthController.d.ts.map +1 -1
  24. package/dist/controllers/NestedAppAuthController.mjs +1 -1
  25. package/dist/controllers/NestedAppAuthController.mjs.map +1 -1
  26. package/dist/controllers/StandardController.d.ts.map +1 -1
  27. package/dist/controllers/StandardController.mjs +28 -16
  28. package/dist/controllers/StandardController.mjs.map +1 -1
  29. package/dist/controllers/UnknownOperatingContextController.d.ts +2 -2
  30. package/dist/controllers/UnknownOperatingContextController.d.ts.map +1 -1
  31. package/dist/controllers/UnknownOperatingContextController.mjs +1 -1
  32. package/dist/controllers/UnknownOperatingContextController.mjs.map +1 -1
  33. package/dist/crypto/BrowserCrypto.d.ts +11 -0
  34. package/dist/crypto/BrowserCrypto.d.ts.map +1 -1
  35. package/dist/crypto/BrowserCrypto.mjs +68 -5
  36. package/dist/crypto/BrowserCrypto.mjs.map +1 -1
  37. package/dist/crypto/CryptoOps.mjs +1 -1
  38. package/dist/crypto/PkceGenerator.mjs +1 -1
  39. package/dist/crypto/SignedHttpRequest.mjs +1 -1
  40. package/dist/encode/Base64Decode.mjs +1 -1
  41. package/dist/encode/Base64Encode.mjs +1 -1
  42. package/dist/error/BrowserAuthError.d.ts +3 -5
  43. package/dist/error/BrowserAuthError.d.ts.map +1 -1
  44. package/dist/error/BrowserAuthError.mjs +5 -7
  45. package/dist/error/BrowserAuthError.mjs.map +1 -1
  46. package/dist/error/BrowserAuthErrorCodes.d.ts +3 -1
  47. package/dist/error/BrowserAuthErrorCodes.d.ts.map +1 -1
  48. package/dist/error/BrowserAuthErrorCodes.mjs +6 -4
  49. package/dist/error/BrowserAuthErrorCodes.mjs.map +1 -1
  50. package/dist/error/BrowserConfigurationAuthError.mjs +2 -2
  51. package/dist/error/BrowserConfigurationAuthErrorCodes.mjs +1 -1
  52. package/dist/error/NativeAuthError.mjs +1 -1
  53. package/dist/error/NativeAuthErrorCodes.mjs +1 -1
  54. package/dist/error/NestedAppAuthError.mjs +1 -1
  55. package/dist/event/EventHandler.mjs +1 -1
  56. package/dist/event/EventMessage.mjs +1 -1
  57. package/dist/event/EventType.mjs +1 -1
  58. package/dist/index.mjs +1 -1
  59. package/dist/interaction_client/BaseInteractionClient.mjs +1 -1
  60. package/dist/interaction_client/HybridSpaAuthorizationCodeClient.mjs +1 -1
  61. package/dist/interaction_client/NativeInteractionClient.d.ts.map +1 -1
  62. package/dist/interaction_client/NativeInteractionClient.mjs +1 -3
  63. package/dist/interaction_client/NativeInteractionClient.mjs.map +1 -1
  64. package/dist/interaction_client/PopupClient.d.ts +14 -1
  65. package/dist/interaction_client/PopupClient.d.ts.map +1 -1
  66. package/dist/interaction_client/PopupClient.mjs +65 -64
  67. package/dist/interaction_client/PopupClient.mjs.map +1 -1
  68. package/dist/interaction_client/RedirectClient.d.ts +20 -3
  69. package/dist/interaction_client/RedirectClient.d.ts.map +1 -1
  70. package/dist/interaction_client/RedirectClient.mjs +132 -76
  71. package/dist/interaction_client/RedirectClient.mjs.map +1 -1
  72. package/dist/interaction_client/SilentAuthCodeClient.d.ts.map +1 -1
  73. package/dist/interaction_client/SilentAuthCodeClient.mjs +1 -1
  74. package/dist/interaction_client/SilentAuthCodeClient.mjs.map +1 -1
  75. package/dist/interaction_client/SilentCacheClient.mjs +1 -1
  76. package/dist/interaction_client/SilentIframeClient.d.ts +13 -3
  77. package/dist/interaction_client/SilentIframeClient.d.ts.map +1 -1
  78. package/dist/interaction_client/SilentIframeClient.mjs +57 -44
  79. package/dist/interaction_client/SilentIframeClient.mjs.map +1 -1
  80. package/dist/interaction_client/SilentRefreshClient.mjs +1 -1
  81. package/dist/interaction_client/StandardInteractionClient.d.ts +2 -3
  82. package/dist/interaction_client/StandardInteractionClient.d.ts.map +1 -1
  83. package/dist/interaction_client/StandardInteractionClient.mjs +1 -1
  84. package/dist/interaction_client/StandardInteractionClient.mjs.map +1 -1
  85. package/dist/interaction_handler/InteractionHandler.d.ts +4 -5
  86. package/dist/interaction_handler/InteractionHandler.d.ts.map +1 -1
  87. package/dist/interaction_handler/InteractionHandler.mjs +1 -1
  88. package/dist/interaction_handler/InteractionHandler.mjs.map +1 -1
  89. package/dist/interaction_handler/SilentHandler.d.ts +4 -2
  90. package/dist/interaction_handler/SilentHandler.d.ts.map +1 -1
  91. package/dist/interaction_handler/SilentHandler.mjs +15 -5
  92. package/dist/interaction_handler/SilentHandler.mjs.map +1 -1
  93. package/dist/naa/BridgeError.mjs +1 -1
  94. package/dist/naa/BridgeProxy.mjs +1 -1
  95. package/dist/naa/BridgeStatusCode.mjs +1 -1
  96. package/dist/naa/mapping/NestedAppAuthAdapter.mjs +2 -2
  97. package/dist/navigation/NavigationClient.mjs +1 -1
  98. package/dist/network/FetchClient.mjs +1 -1
  99. package/dist/operatingcontext/BaseOperatingContext.mjs +1 -1
  100. package/dist/operatingcontext/NestedAppOperatingContext.mjs +1 -1
  101. package/dist/operatingcontext/StandardOperatingContext.mjs +1 -1
  102. package/dist/operatingcontext/UnknownOperatingContext.mjs +1 -1
  103. package/dist/packageMetadata.d.ts +1 -1
  104. package/dist/packageMetadata.mjs +2 -2
  105. package/dist/protocol/Authorize.d.ts +53 -1
  106. package/dist/protocol/Authorize.d.ts.map +1 -1
  107. package/dist/protocol/Authorize.mjs +147 -4
  108. package/dist/protocol/Authorize.mjs.map +1 -1
  109. package/dist/request/AuthorizationUrlRequest.d.ts +2 -4
  110. package/dist/request/AuthorizationUrlRequest.d.ts.map +1 -1
  111. package/dist/request/PopupRequest.d.ts +1 -1
  112. package/dist/request/PopupRequest.d.ts.map +1 -1
  113. package/dist/request/RedirectRequest.d.ts +1 -1
  114. package/dist/request/RedirectRequest.d.ts.map +1 -1
  115. package/dist/request/RequestHelpers.mjs +1 -1
  116. package/dist/request/SsoSilentRequest.d.ts +1 -1
  117. package/dist/request/SsoSilentRequest.d.ts.map +1 -1
  118. package/dist/response/ResponseHandler.mjs +1 -1
  119. package/dist/telemetry/BrowserPerformanceClient.mjs +1 -1
  120. package/dist/telemetry/BrowserPerformanceMeasurement.mjs +1 -1
  121. package/dist/utils/BrowserConstants.d.ts +1 -10
  122. package/dist/utils/BrowserConstants.d.ts.map +1 -1
  123. package/dist/utils/BrowserConstants.mjs +2 -15
  124. package/dist/utils/BrowserConstants.mjs.map +1 -1
  125. package/dist/utils/BrowserProtocolUtils.mjs +1 -1
  126. package/dist/utils/BrowserUtils.mjs +1 -1
  127. package/lib/msal-browser.cjs +1588 -1555
  128. package/lib/msal-browser.cjs.map +1 -1
  129. package/lib/msal-browser.js +1588 -1555
  130. package/lib/msal-browser.js.map +1 -1
  131. package/lib/msal-browser.min.js +68 -67
  132. package/lib/types/cache/BrowserCacheManager.d.ts +4 -41
  133. package/lib/types/cache/BrowserCacheManager.d.ts.map +1 -1
  134. package/lib/types/controllers/NestedAppAuthController.d.ts +2 -2
  135. package/lib/types/controllers/NestedAppAuthController.d.ts.map +1 -1
  136. package/lib/types/controllers/StandardController.d.ts.map +1 -1
  137. package/lib/types/controllers/UnknownOperatingContextController.d.ts +2 -2
  138. package/lib/types/controllers/UnknownOperatingContextController.d.ts.map +1 -1
  139. package/lib/types/crypto/BrowserCrypto.d.ts +11 -0
  140. package/lib/types/crypto/BrowserCrypto.d.ts.map +1 -1
  141. package/lib/types/error/BrowserAuthError.d.ts +3 -5
  142. package/lib/types/error/BrowserAuthError.d.ts.map +1 -1
  143. package/lib/types/error/BrowserAuthErrorCodes.d.ts +3 -1
  144. package/lib/types/error/BrowserAuthErrorCodes.d.ts.map +1 -1
  145. package/lib/types/interaction_client/NativeInteractionClient.d.ts.map +1 -1
  146. package/lib/types/interaction_client/PopupClient.d.ts +14 -1
  147. package/lib/types/interaction_client/PopupClient.d.ts.map +1 -1
  148. package/lib/types/interaction_client/RedirectClient.d.ts +20 -3
  149. package/lib/types/interaction_client/RedirectClient.d.ts.map +1 -1
  150. package/lib/types/interaction_client/SilentAuthCodeClient.d.ts.map +1 -1
  151. package/lib/types/interaction_client/SilentIframeClient.d.ts +13 -3
  152. package/lib/types/interaction_client/SilentIframeClient.d.ts.map +1 -1
  153. package/lib/types/interaction_client/StandardInteractionClient.d.ts +2 -3
  154. package/lib/types/interaction_client/StandardInteractionClient.d.ts.map +1 -1
  155. package/lib/types/interaction_handler/InteractionHandler.d.ts +4 -5
  156. package/lib/types/interaction_handler/InteractionHandler.d.ts.map +1 -1
  157. package/lib/types/interaction_handler/SilentHandler.d.ts +4 -2
  158. package/lib/types/interaction_handler/SilentHandler.d.ts.map +1 -1
  159. package/lib/types/packageMetadata.d.ts +1 -1
  160. package/lib/types/protocol/Authorize.d.ts +53 -1
  161. package/lib/types/protocol/Authorize.d.ts.map +1 -1
  162. package/lib/types/request/AuthorizationUrlRequest.d.ts +2 -4
  163. package/lib/types/request/AuthorizationUrlRequest.d.ts.map +1 -1
  164. package/lib/types/request/PopupRequest.d.ts +1 -1
  165. package/lib/types/request/PopupRequest.d.ts.map +1 -1
  166. package/lib/types/request/RedirectRequest.d.ts +1 -1
  167. package/lib/types/request/RedirectRequest.d.ts.map +1 -1
  168. package/lib/types/request/SsoSilentRequest.d.ts +1 -1
  169. package/lib/types/request/SsoSilentRequest.d.ts.map +1 -1
  170. package/lib/types/utils/BrowserConstants.d.ts +1 -10
  171. package/lib/types/utils/BrowserConstants.d.ts.map +1 -1
  172. package/package.json +2 -2
  173. package/src/cache/BrowserCacheManager.ts +30 -205
  174. package/src/config/Configuration.ts +2 -2
  175. package/src/controllers/NestedAppAuthController.ts +2 -0
  176. package/src/controllers/StandardController.ts +35 -24
  177. package/src/controllers/UnknownOperatingContextController.ts +2 -0
  178. package/src/crypto/BrowserCrypto.ts +91 -2
  179. package/src/error/BrowserAuthError.ts +6 -8
  180. package/src/error/BrowserAuthErrorCodes.ts +3 -1
  181. package/src/interaction_client/NativeInteractionClient.ts +0 -2
  182. package/src/interaction_client/PopupClient.ts +163 -119
  183. package/src/interaction_client/RedirectClient.ts +258 -140
  184. package/src/interaction_client/SilentAuthCodeClient.ts +2 -2
  185. package/src/interaction_client/SilentIframeClient.ts +154 -99
  186. package/src/interaction_client/StandardInteractionClient.ts +3 -3
  187. package/src/interaction_handler/InteractionHandler.ts +4 -4
  188. package/src/interaction_handler/SilentHandler.ts +31 -2
  189. package/src/packageMetadata.ts +1 -1
  190. package/src/protocol/Authorize.ts +356 -2
  191. package/src/request/AuthorizationUrlRequest.ts +3 -5
  192. package/src/request/PopupRequest.ts +1 -0
  193. package/src/request/RedirectRequest.ts +1 -0
  194. package/src/request/SsoSilentRequest.ts +1 -0
  195. package/src/utils/BrowserConstants.ts +1 -10
  196. package/dist/interaction_handler/RedirectHandler.d.ts +0 -33
  197. package/dist/interaction_handler/RedirectHandler.d.ts.map +0 -1
  198. package/dist/interaction_handler/RedirectHandler.mjs +0 -144
  199. package/dist/interaction_handler/RedirectHandler.mjs.map +0 -1
  200. package/lib/types/interaction_handler/RedirectHandler.d.ts +0 -33
  201. package/lib/types/interaction_handler/RedirectHandler.d.ts.map +0 -1
  202. package/src/interaction_handler/RedirectHandler.ts +0 -252
@@ -1,8 +1,8 @@
1
- /*! @azure/msal-browser v4.8.0 2025-03-20 */
1
+ /*! @azure/msal-browser v4.9.1 2025-03-26 */
2
2
  'use strict';
3
3
  'use strict';
4
4
 
5
- /*! @azure/msal-common v15.3.0 2025-03-20 */
5
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
6
6
  /*
7
7
  * Copyright (c) Microsoft Corporation. All rights reserved.
8
8
  * Licensed under the MIT License.
@@ -37,11 +37,8 @@ const Constants = {
37
37
  PROFILE_SCOPE: "profile",
38
38
  OFFLINE_ACCESS_SCOPE: "offline_access",
39
39
  EMAIL_SCOPE: "email",
40
- // Default response type for authorization code flow
41
- CODE_RESPONSE_TYPE: "code",
42
40
  CODE_GRANT_TYPE: "authorization_code",
43
41
  RT_GRANT_TYPE: "refresh_token",
44
- FRAGMENT_RESPONSE_MODE: "fragment",
45
42
  S256_CODE_CHALLENGE_METHOD: "S256",
46
43
  URL_FORM_CONTENT_TYPE: "application/x-www-form-urlencoded;charset=utf-8",
47
44
  AUTHORIZATION_PENDING: "authorization_pending",
@@ -61,31 +58,14 @@ const Constants = {
61
58
  "login.microsoft.com",
62
59
  "sts.windows.net",
63
60
  ],
64
- TOKEN_RESPONSE_TYPE: "token",
65
- ID_TOKEN_RESPONSE_TYPE: "id_token",
66
61
  SHR_NONCE_VALIDITY: 240,
67
62
  INVALID_INSTANCE: "invalid_instance",
68
63
  };
69
64
  const HttpStatus = {
70
- SUCCESS: 200,
71
- SUCCESS_RANGE_START: 200,
72
- SUCCESS_RANGE_END: 299,
73
- REDIRECT: 302,
74
- CLIENT_ERROR: 400,
75
65
  CLIENT_ERROR_RANGE_START: 400,
76
- BAD_REQUEST: 400,
77
- UNAUTHORIZED: 401,
78
- NOT_FOUND: 404,
79
- REQUEST_TIMEOUT: 408,
80
- TOO_MANY_REQUESTS: 429,
81
66
  CLIENT_ERROR_RANGE_END: 499,
82
- SERVER_ERROR: 500,
83
67
  SERVER_ERROR_RANGE_START: 500,
84
- SERVICE_UNAVAILABLE: 503,
85
- GATEWAY_TIMEOUT: 504,
86
- SERVER_ERROR_RANGE_END: 599,
87
- MULTI_SIDED_ERROR: 600,
88
- };
68
+ SERVER_ERROR_RANGE_END: 599};
89
69
  const OIDC_DEFAULT_SCOPES = [
90
70
  Constants.OPENID_SCOPE,
91
71
  Constants.PROFILE_SCOPE,
@@ -146,8 +126,16 @@ const CodeChallengeMethodValues = {
146
126
  PLAIN: "plain",
147
127
  S256: "S256",
148
128
  };
129
+ /**
130
+ * Allowed values for response_type
131
+ */
132
+ const OAuthResponseType = {
133
+ CODE: "code",
134
+ IDTOKEN_TOKEN_REFRESHTOKEN: "id_token token refresh_token",
135
+ };
149
136
  /**
150
137
  * allowed values for server response type
138
+ * @deprecated Use ResponseMode instead
151
139
  */
152
140
  const ServerResponseType = {
153
141
  QUERY: "query",
@@ -157,28 +145,19 @@ const ServerResponseType = {
157
145
  * allowed values for response_mode
158
146
  */
159
147
  const ResponseMode = {
160
- ...ServerResponseType,
161
- FORM_POST: "form_post",
162
- };
148
+ QUERY: "query"};
163
149
  /**
164
150
  * allowed grant_type
165
151
  */
166
152
  const GrantType = {
167
- IMPLICIT_GRANT: "implicit",
168
153
  AUTHORIZATION_CODE_GRANT: "authorization_code",
169
- CLIENT_CREDENTIALS_GRANT: "client_credentials",
170
- RESOURCE_OWNER_PASSWORD_GRANT: "password",
171
- REFRESH_TOKEN_GRANT: "refresh_token",
172
- DEVICE_CODE_GRANT: "device_code",
173
- JWT_BEARER: "urn:ietf:params:oauth:grant-type:jwt-bearer",
174
- };
154
+ REFRESH_TOKEN_GRANT: "refresh_token"};
175
155
  /**
176
156
  * Account types in Cache
177
157
  */
178
158
  const CacheAccountType = {
179
159
  MSSTS_ACCOUNT_TYPE: "MSSTS",
180
160
  ADFS_ACCOUNT_TYPE: "ADFS",
181
- MSAV1_ACCOUNT_TYPE: "MSA",
182
161
  GENERIC_ACCOUNT_TYPE: "Generic", // NTLM, Kerberos, FBA, Basic etc
183
162
  };
184
163
  /**
@@ -215,7 +194,6 @@ const AuthorityMetadataSource = {
215
194
  };
216
195
  const SERVER_TELEM_CONSTANTS = {
217
196
  SCHEMA_VERSION: 5,
218
- MAX_CUR_HEADER_BYTES: 80,
219
197
  MAX_LAST_HEADER_BYTES: 330,
220
198
  MAX_CACHED_ERRORS: 50,
221
199
  CACHE_KEY: "server-telemetry",
@@ -270,9 +248,7 @@ const RegionDiscoverySources = {
270
248
  * Region Discovery Outcomes
271
249
  */
272
250
  const RegionDiscoveryOutcomes = {
273
- CONFIGURED_MATCHES_DETECTED: "1",
274
251
  CONFIGURED_NO_AUTO_DETECTION: "2",
275
- CONFIGURED_NOT_DETECTED: "3",
276
252
  AUTO_DETECTION_REQUESTED_SUCCESSFUL: "4",
277
253
  AUTO_DETECTION_REQUESTED_FAILED: "5",
278
254
  };
@@ -299,7 +275,7 @@ const JsonWebTokenTypes = {
299
275
  // Token renewal offset default in seconds
300
276
  const DEFAULT_TOKEN_RENEWAL_OFFSET_SEC = 300;
301
277
 
302
- /*! @azure/msal-common v15.3.0 2025-03-20 */
278
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
303
279
  /*
304
280
  * Copyright (c) Microsoft Corporation. All rights reserved.
305
281
  * Licensed under the MIT License.
@@ -316,7 +292,7 @@ var AuthErrorCodes = /*#__PURE__*/Object.freeze({
316
292
  unexpectedError: unexpectedError
317
293
  });
318
294
 
319
- /*! @azure/msal-common v15.3.0 2025-03-20 */
295
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
320
296
 
321
297
  /*
322
298
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -365,7 +341,7 @@ function createAuthError(code, additionalMessage) {
365
341
  : AuthErrorMessages[code]);
366
342
  }
367
343
 
368
- /*! @azure/msal-common v15.3.0 2025-03-20 */
344
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
369
345
  /*
370
346
  * Copyright (c) Microsoft Corporation. All rights reserved.
371
347
  * Licensed under the MIT License.
@@ -463,7 +439,7 @@ var ClientAuthErrorCodes = /*#__PURE__*/Object.freeze({
463
439
  userTimeoutReached: userTimeoutReached
464
440
  });
465
441
 
466
- /*! @azure/msal-common v15.3.0 2025-03-20 */
442
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
467
443
 
468
444
  /*
469
445
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -715,7 +691,7 @@ function createClientAuthError(errorCode, additionalMessage) {
715
691
  return new ClientAuthError(errorCode, additionalMessage);
716
692
  }
717
693
 
718
- /*! @azure/msal-common v15.3.0 2025-03-20 */
694
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
719
695
 
720
696
  /*
721
697
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -754,7 +730,7 @@ const DEFAULT_CRYPTO_IMPLEMENTATION = {
754
730
  },
755
731
  };
756
732
 
757
- /*! @azure/msal-common v15.3.0 2025-03-20 */
733
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
758
734
 
759
735
  /*
760
736
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -945,12 +921,12 @@ class Logger {
945
921
  }
946
922
  }
947
923
 
948
- /*! @azure/msal-common v15.3.0 2025-03-20 */
924
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
949
925
  /* eslint-disable header/header */
950
926
  const name$1 = "@azure/msal-common";
951
- const version$1 = "15.3.0";
927
+ const version$1 = "15.4.0";
952
928
 
953
- /*! @azure/msal-common v15.3.0 2025-03-20 */
929
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
954
930
  /*
955
931
  * Copyright (c) Microsoft Corporation. All rights reserved.
956
932
  * Licensed under the MIT License.
@@ -970,7 +946,7 @@ const AzureCloudInstance = {
970
946
  AzureUsGovernment: "https://login.microsoftonline.us",
971
947
  };
972
948
 
973
- /*! @azure/msal-common v15.3.0 2025-03-20 */
949
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
974
950
 
975
951
  /*
976
952
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -1031,7 +1007,7 @@ function checkMaxAge(authTime, maxAge) {
1031
1007
  }
1032
1008
  }
1033
1009
 
1034
- /*! @azure/msal-common v15.3.0 2025-03-20 */
1010
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
1035
1011
  /*
1036
1012
  * Copyright (c) Microsoft Corporation. All rights reserved.
1037
1013
  * Licensed under the MIT License.
@@ -1086,7 +1062,7 @@ function wasClockTurnedBack(cachedAt) {
1086
1062
  return cachedAtSec > nowSeconds();
1087
1063
  }
1088
1064
 
1089
- /*! @azure/msal-common v15.3.0 2025-03-20 */
1065
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
1090
1066
 
1091
1067
  /*
1092
1068
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -1413,7 +1389,7 @@ function isAuthorityMetadataExpired(metadata) {
1413
1389
  return metadata.expiresAt <= nowSeconds();
1414
1390
  }
1415
1391
 
1416
- /*! @azure/msal-common v15.3.0 2025-03-20 */
1392
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
1417
1393
  /*
1418
1394
  * Copyright (c) Microsoft Corporation. All rights reserved.
1419
1395
  * Licensed under the MIT License.
@@ -1467,7 +1443,7 @@ var ClientConfigurationErrorCodes = /*#__PURE__*/Object.freeze({
1467
1443
  urlParseError: urlParseError
1468
1444
  });
1469
1445
 
1470
- /*! @azure/msal-common v15.3.0 2025-03-20 */
1446
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
1471
1447
 
1472
1448
  /*
1473
1449
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -1605,7 +1581,7 @@ function createClientConfigurationError(errorCode) {
1605
1581
  return new ClientConfigurationError(errorCode);
1606
1582
  }
1607
1583
 
1608
- /*! @azure/msal-common v15.3.0 2025-03-20 */
1584
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
1609
1585
  /*
1610
1586
  * Copyright (c) Microsoft Corporation. All rights reserved.
1611
1587
  * Licensed under the MIT License.
@@ -1702,7 +1678,7 @@ class StringUtils {
1702
1678
  }
1703
1679
  }
1704
1680
 
1705
- /*! @azure/msal-common v15.3.0 2025-03-20 */
1681
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
1706
1682
 
1707
1683
  /*
1708
1684
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -1893,7 +1869,7 @@ class ScopeSet {
1893
1869
  }
1894
1870
  }
1895
1871
 
1896
- /*! @azure/msal-common v15.3.0 2025-03-20 */
1872
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
1897
1873
 
1898
1874
  /*
1899
1875
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -1933,7 +1909,7 @@ function buildClientInfoFromHomeAccountId(homeAccountId) {
1933
1909
  };
1934
1910
  }
1935
1911
 
1936
- /*! @azure/msal-common v15.3.0 2025-03-20 */
1912
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
1937
1913
  /*
1938
1914
  * Copyright (c) Microsoft Corporation. All rights reserved.
1939
1915
  * Licensed under the MIT License.
@@ -2012,7 +1988,7 @@ function updateAccountTenantProfileData(baseAccountInfo, tenantProfile, idTokenC
2012
1988
  return updatedAccountInfo;
2013
1989
  }
2014
1990
 
2015
- /*! @azure/msal-common v15.3.0 2025-03-20 */
1991
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
2016
1992
  /*
2017
1993
  * Copyright (c) Microsoft Corporation. All rights reserved.
2018
1994
  * Licensed under the MIT License.
@@ -2027,7 +2003,7 @@ const AuthorityType = {
2027
2003
  Ciam: 3,
2028
2004
  };
2029
2005
 
2030
- /*! @azure/msal-common v15.3.0 2025-03-20 */
2006
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
2031
2007
  /*
2032
2008
  * Copyright (c) Microsoft Corporation. All rights reserved.
2033
2009
  * Licensed under the MIT License.
@@ -2049,7 +2025,7 @@ function getTenantIdFromIdTokenClaims(idTokenClaims) {
2049
2025
  return null;
2050
2026
  }
2051
2027
 
2052
- /*! @azure/msal-common v15.3.0 2025-03-20 */
2028
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
2053
2029
  /*
2054
2030
  * Copyright (c) Microsoft Corporation. All rights reserved.
2055
2031
  * Licensed under the MIT License.
@@ -2058,11 +2034,22 @@ function getTenantIdFromIdTokenClaims(idTokenClaims) {
2058
2034
  * Protocol modes supported by MSAL.
2059
2035
  */
2060
2036
  const ProtocolMode = {
2037
+ /**
2038
+ * Auth Code + PKCE with Entra ID (formerly AAD) specific optimizations and features
2039
+ */
2061
2040
  AAD: "AAD",
2041
+ /**
2042
+ * Auth Code + PKCE without Entra ID specific optimizations and features. For use only with non-Microsoft owned authorities.
2043
+ * Support is limited for this mode.
2044
+ */
2062
2045
  OIDC: "OIDC",
2046
+ /**
2047
+ * Encrypted Authorize Response (EAR) with Entra ID specific optimizations and features
2048
+ */
2049
+ EAR: "EAR",
2063
2050
  };
2064
2051
 
2065
- /*! @azure/msal-common v15.3.0 2025-03-20 */
2052
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
2066
2053
 
2067
2054
  /*
2068
2055
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -2158,11 +2145,11 @@ class AccountEntity {
2158
2145
  if (authority.authorityType === AuthorityType.Adfs) {
2159
2146
  account.authorityType = CacheAccountType.ADFS_ACCOUNT_TYPE;
2160
2147
  }
2161
- else if (authority.protocolMode === ProtocolMode.AAD) {
2162
- account.authorityType = CacheAccountType.MSSTS_ACCOUNT_TYPE;
2148
+ else if (authority.protocolMode === ProtocolMode.OIDC) {
2149
+ account.authorityType = CacheAccountType.GENERIC_ACCOUNT_TYPE;
2163
2150
  }
2164
2151
  else {
2165
- account.authorityType = CacheAccountType.GENERIC_ACCOUNT_TYPE;
2152
+ account.authorityType = CacheAccountType.MSSTS_ACCOUNT_TYPE;
2166
2153
  }
2167
2154
  let clientInfo;
2168
2155
  if (accountDetails.clientInfo && base64Decode) {
@@ -2305,7 +2292,7 @@ class AccountEntity {
2305
2292
  }
2306
2293
  }
2307
2294
 
2308
- /*! @azure/msal-common v15.3.0 2025-03-20 */
2295
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
2309
2296
 
2310
2297
  /*
2311
2298
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -2340,6 +2327,7 @@ function getDeserializedResponse(responseString) {
2340
2327
  const deserializedHash = Object.fromEntries(new URLSearchParams(normalizedResponse));
2341
2328
  // Check for known response properties
2342
2329
  if (deserializedHash.code ||
2330
+ deserializedHash.ear_jwe ||
2343
2331
  deserializedHash.error ||
2344
2332
  deserializedHash.error_description ||
2345
2333
  deserializedHash.state) {
@@ -2362,7 +2350,7 @@ function mapToQueryString(parameters) {
2362
2350
  return queryParameterArray.join("&");
2363
2351
  }
2364
2352
 
2365
- /*! @azure/msal-common v15.3.0 2025-03-20 */
2353
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
2366
2354
 
2367
2355
  /*
2368
2356
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -2526,7 +2514,7 @@ class UrlString {
2526
2514
  }
2527
2515
  }
2528
2516
 
2529
- /*! @azure/msal-common v15.3.0 2025-03-20 */
2517
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
2530
2518
 
2531
2519
  /*
2532
2520
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -2557,7 +2545,6 @@ const rawMetdataJSON = {
2557
2545
  },
2558
2546
  },
2559
2547
  instanceDiscoveryMetadata: {
2560
- tenant_discovery_endpoint: "https://{canonicalAuthority}/v2.0/.well-known/openid-configuration",
2561
2548
  metadata: [
2562
2549
  {
2563
2550
  preferred_network: "login.microsoftonline.com",
@@ -2666,7 +2653,7 @@ function getCloudDiscoveryMetadataFromNetworkResponse(response, authorityHost) {
2666
2653
  return null;
2667
2654
  }
2668
2655
 
2669
- /*! @azure/msal-common v15.3.0 2025-03-20 */
2656
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
2670
2657
  /*
2671
2658
  * Copyright (c) Microsoft Corporation. All rights reserved.
2672
2659
  * Licensed under the MIT License.
@@ -2674,7 +2661,7 @@ function getCloudDiscoveryMetadataFromNetworkResponse(response, authorityHost) {
2674
2661
  const cacheQuotaExceededErrorCode = "cache_quota_exceeded";
2675
2662
  const cacheUnknownErrorCode = "cache_error_unknown";
2676
2663
 
2677
- /*! @azure/msal-common v15.3.0 2025-03-20 */
2664
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
2678
2665
 
2679
2666
  /*
2680
2667
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -2701,7 +2688,7 @@ class CacheError extends Error {
2701
2688
  }
2702
2689
  }
2703
2690
 
2704
- /*! @azure/msal-common v15.3.0 2025-03-20 */
2691
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
2705
2692
 
2706
2693
  /*
2707
2694
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -3886,7 +3873,7 @@ class DefaultStorageClass extends CacheManager {
3886
3873
  }
3887
3874
  }
3888
3875
 
3889
- /*! @azure/msal-common v15.3.0 2025-03-20 */
3876
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
3890
3877
 
3891
3878
  /*
3892
3879
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -3985,7 +3972,7 @@ function isOidcProtocolMode(config) {
3985
3972
  return (config.authOptions.authority.options.protocolMode === ProtocolMode.OIDC);
3986
3973
  }
3987
3974
 
3988
- /*! @azure/msal-common v15.3.0 2025-03-20 */
3975
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
3989
3976
  /*
3990
3977
  * Copyright (c) Microsoft Corporation. All rights reserved.
3991
3978
  * Licensed under the MIT License.
@@ -3995,7 +3982,7 @@ const CcsCredentialType = {
3995
3982
  UPN: "UPN",
3996
3983
  };
3997
3984
 
3998
- /*! @azure/msal-common v15.3.0 2025-03-20 */
3985
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
3999
3986
  /*
4000
3987
  * Copyright (c) Microsoft Corporation. All rights reserved.
4001
3988
  * Licensed under the MIT License.
@@ -4041,9 +4028,11 @@ const DOMAIN_HINT = "domain_hint";
4041
4028
  const X_CLIENT_EXTRA_SKU = "x-client-xtra-sku";
4042
4029
  const BROKER_CLIENT_ID = "brk_client_id";
4043
4030
  const BROKER_REDIRECT_URI = "brk_redirect_uri";
4044
- const INSTANCE_AWARE = "instance_aware";
4031
+ const INSTANCE_AWARE = "instance_aware";
4032
+ const EAR_JWK = "ear_jwk";
4033
+ const EAR_JWE_CRYPTO = "ear_jwe_crypto";
4045
4034
 
4046
- /*! @azure/msal-common v15.3.0 2025-03-20 */
4035
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
4047
4036
 
4048
4037
  /*
4049
4038
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -4062,10 +4051,12 @@ function instrumentBrokerParams(parameters, correlationId, performanceClient) {
4062
4051
  }
4063
4052
  }
4064
4053
  /**
4065
- * add response_type = code
4054
+ * Add the given response_type
4055
+ * @param parameters
4056
+ * @param responseType
4066
4057
  */
4067
- function addResponseTypeCode(parameters) {
4068
- parameters.set(RESPONSE_TYPE, Constants.CODE_RESPONSE_TYPE);
4058
+ function addResponseType(parameters, responseType) {
4059
+ parameters.set(RESPONSE_TYPE, responseType);
4069
4060
  }
4070
4061
  /**
4071
4062
  * add response_mode. defaults to query.
@@ -4396,9 +4387,20 @@ function addBrokerParameters(parameters, brokerClientId, brokerRedirectUri) {
4396
4387
  if (!parameters.has(BROKER_REDIRECT_URI)) {
4397
4388
  parameters.set(BROKER_REDIRECT_URI, brokerRedirectUri);
4398
4389
  }
4390
+ }
4391
+ /**
4392
+ * Add EAR (Encrypted Authorize Response) request parameters
4393
+ * @param parameters
4394
+ * @param jwk
4395
+ */
4396
+ function addEARParameters(parameters, jwk) {
4397
+ parameters.set(EAR_JWK, encodeURIComponent(jwk));
4398
+ // ear_jwe_crypto will always have value: {"alg":"dir","enc":"A256GCM"} so we can hardcode this
4399
+ const jweCryptoB64Encoded = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0";
4400
+ parameters.set(EAR_JWE_CRYPTO, jweCryptoB64Encoded);
4399
4401
  }
4400
4402
 
4401
- /*! @azure/msal-common v15.3.0 2025-03-20 */
4403
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
4402
4404
  /*
4403
4405
  * Copyright (c) Microsoft Corporation. All rights reserved.
4404
4406
  * Licensed under the MIT License.
@@ -4410,7 +4412,7 @@ function isOpenIdConfigResponse(response) {
4410
4412
  response.hasOwnProperty("jwks_uri"));
4411
4413
  }
4412
4414
 
4413
- /*! @azure/msal-common v15.3.0 2025-03-20 */
4415
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
4414
4416
  /*
4415
4417
  * Copyright (c) Microsoft Corporation. All rights reserved.
4416
4418
  * Licensed under the MIT License.
@@ -4420,7 +4422,7 @@ function isCloudInstanceDiscoveryResponse(response) {
4420
4422
  response.hasOwnProperty("metadata"));
4421
4423
  }
4422
4424
 
4423
- /*! @azure/msal-common v15.3.0 2025-03-20 */
4425
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
4424
4426
  /*
4425
4427
  * Copyright (c) Microsoft Corporation. All rights reserved.
4426
4428
  * Licensed under the MIT License.
@@ -4430,7 +4432,7 @@ function isCloudInstanceDiscoveryErrorResponse(response) {
4430
4432
  response.hasOwnProperty("error_description"));
4431
4433
  }
4432
4434
 
4433
- /*! @azure/msal-common v15.3.0 2025-03-20 */
4435
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
4434
4436
  /*
4435
4437
  * Copyright (c) Microsoft Corporation. All rights reserved.
4436
4438
  * Licensed under the MIT License.
@@ -4616,6 +4618,9 @@ const PerformanceEvents = {
4616
4618
  */
4617
4619
  HandleCodeResponseFromServer: "handleCodeResponseFromServer",
4618
4620
  HandleCodeResponse: "handleCodeResponse",
4621
+ HandleResponseEar: "handleResponseEar",
4622
+ HandleResponsePlatformBroker: "handleResponsePlatformBroker",
4623
+ HandleResponseCode: "handleResponseCode",
4619
4624
  UpdateTokenEndpointAuthority: "updateTokenEndpointAuthority",
4620
4625
  /**
4621
4626
  * APIs in Authorization Code Client (msal-common)
@@ -4682,6 +4687,8 @@ const PerformanceEvents = {
4682
4687
  UrlEncodeArr: "urlEncodeArr",
4683
4688
  Encrypt: "encrypt",
4684
4689
  Decrypt: "decrypt",
4690
+ GenerateEarKey: "generateEarKey",
4691
+ DecryptEarResponse: "decryptEarResponse",
4685
4692
  };
4686
4693
  const PerformanceEventAbbreviations = new Map([
4687
4694
  [PerformanceEvents.AcquireTokenByCode, "ATByCode"],
@@ -4799,6 +4806,12 @@ const PerformanceEventAbbreviations = new Map([
4799
4806
  "HandleCodeResFromServer",
4800
4807
  ],
4801
4808
  [PerformanceEvents.HandleCodeResponse, "HandleCodeResp"],
4809
+ [PerformanceEvents.HandleResponseEar, "HandleRespEar"],
4810
+ [PerformanceEvents.HandleResponseCode, "HandleRespCode"],
4811
+ [
4812
+ PerformanceEvents.HandleResponsePlatformBroker,
4813
+ "HandleRespPlatBroker",
4814
+ ],
4802
4815
  [PerformanceEvents.UpdateTokenEndpointAuthority, "UpdTEndpointAuth"],
4803
4816
  [PerformanceEvents.AuthClientAcquireToken, "AuthClientAT"],
4804
4817
  [PerformanceEvents.AuthClientExecuteTokenRequest, "AuthClientExecTReq"],
@@ -4901,6 +4914,8 @@ const PerformanceEventAbbreviations = new Map([
4901
4914
  [PerformanceEvents.UrlEncodeArr, "urlEncArr"],
4902
4915
  [PerformanceEvents.Encrypt, "encrypt"],
4903
4916
  [PerformanceEvents.Decrypt, "decrypt"],
4917
+ [PerformanceEvents.GenerateEarKey, "genEarKey"],
4918
+ [PerformanceEvents.DecryptEarResponse, "decryptEarResp"],
4904
4919
  ]);
4905
4920
  /**
4906
4921
  * State of the performance event.
@@ -4909,7 +4924,6 @@ const PerformanceEventAbbreviations = new Map([
4909
4924
  * @enum {number}
4910
4925
  */
4911
4926
  const PerformanceEventStatus = {
4912
- NotStarted: 0,
4913
4927
  InProgress: 1,
4914
4928
  Completed: 2,
4915
4929
  };
@@ -4930,7 +4944,7 @@ const IntFields = new Set([
4930
4944
  "encryptedCacheExpiredCount",
4931
4945
  ]);
4932
4946
 
4933
- /*! @azure/msal-common v15.3.0 2025-03-20 */
4947
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
4934
4948
  /*
4935
4949
  * Copyright (c) Microsoft Corporation. All rights reserved.
4936
4950
  * Licensed under the MIT License.
@@ -5026,7 +5040,7 @@ const invokeAsync = (callback, eventName, logger, telemetryClient, correlationId
5026
5040
  };
5027
5041
  };
5028
5042
 
5029
- /*! @azure/msal-common v15.3.0 2025-03-20 */
5043
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
5030
5044
 
5031
5045
  /*
5032
5046
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -5135,7 +5149,7 @@ RegionDiscovery.IMDS_OPTIONS = {
5135
5149
  },
5136
5150
  };
5137
5151
 
5138
- /*! @azure/msal-common v15.3.0 2025-03-20 */
5152
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
5139
5153
 
5140
5154
  /*
5141
5155
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -5313,7 +5327,7 @@ class Authority {
5313
5327
  return (authorityUri.PathSegments.length === 1 &&
5314
5328
  !Authority.reservedTenantDomains.has(authorityUri.PathSegments[0]) &&
5315
5329
  this.getAuthorityType(authorityUri) === AuthorityType.Default &&
5316
- this.protocolMode === ProtocolMode.AAD);
5330
+ this.protocolMode !== ProtocolMode.OIDC);
5317
5331
  }
5318
5332
  /**
5319
5333
  * Replaces tenant in url path with current tenant. Defaults to common.
@@ -5360,7 +5374,7 @@ class Authority {
5360
5374
  const canonicalAuthorityHost = this.hostnameAndPort;
5361
5375
  if (this.canonicalAuthority.endsWith("v2.0/") ||
5362
5376
  this.authorityType === AuthorityType.Adfs ||
5363
- (this.protocolMode !== ProtocolMode.AAD &&
5377
+ (this.protocolMode === ProtocolMode.OIDC &&
5364
5378
  !this.isAliasOfKnownMicrosoftAuthority(canonicalAuthorityHost))) {
5365
5379
  return `${this.canonicalAuthority}.well-known/openid-configuration`;
5366
5380
  }
@@ -5974,7 +5988,7 @@ function buildStaticAuthorityOptions(authOptions) {
5974
5988
  };
5975
5989
  }
5976
5990
 
5977
- /*! @azure/msal-common v15.3.0 2025-03-20 */
5991
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
5978
5992
 
5979
5993
  /*
5980
5994
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -6005,7 +6019,7 @@ async function createDiscoveredInstance(authorityUri, networkClient, cacheManage
6005
6019
  }
6006
6020
  }
6007
6021
 
6008
- /*! @azure/msal-common v15.3.0 2025-03-20 */
6022
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
6009
6023
 
6010
6024
  /*
6011
6025
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -6024,7 +6038,7 @@ class ServerError extends AuthError {
6024
6038
  }
6025
6039
  }
6026
6040
 
6027
- /*! @azure/msal-common v15.3.0 2025-03-20 */
6041
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
6028
6042
  /*
6029
6043
  * Copyright (c) Microsoft Corporation. All rights reserved.
6030
6044
  * Licensed under the MIT License.
@@ -6045,7 +6059,7 @@ function getRequestThumbprint(clientId, request, homeAccountId) {
6045
6059
  };
6046
6060
  }
6047
6061
 
6048
- /*! @azure/msal-common v15.3.0 2025-03-20 */
6062
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
6049
6063
 
6050
6064
  /*
6051
6065
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -6132,7 +6146,7 @@ class ThrottlingUtils {
6132
6146
  }
6133
6147
  }
6134
6148
 
6135
- /*! @azure/msal-common v15.3.0 2025-03-20 */
6149
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
6136
6150
 
6137
6151
  /*
6138
6152
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -6162,7 +6176,7 @@ function createNetworkError(error, httpStatus, responseHeaders) {
6162
6176
  return new NetworkError(error, httpStatus, responseHeaders);
6163
6177
  }
6164
6178
 
6165
- /*! @azure/msal-common v15.3.0 2025-03-20 */
6179
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
6166
6180
 
6167
6181
  /*
6168
6182
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -6310,7 +6324,7 @@ class BaseClient {
6310
6324
  }
6311
6325
  }
6312
6326
 
6313
- /*! @azure/msal-common v15.3.0 2025-03-20 */
6327
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
6314
6328
  /*
6315
6329
  * Copyright (c) Microsoft Corporation. All rights reserved.
6316
6330
  * Licensed under the MIT License.
@@ -6336,7 +6350,7 @@ var InteractionRequiredAuthErrorCodes = /*#__PURE__*/Object.freeze({
6336
6350
  refreshTokenExpired: refreshTokenExpired
6337
6351
  });
6338
6352
 
6339
- /*! @azure/msal-common v15.3.0 2025-03-20 */
6353
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
6340
6354
 
6341
6355
  /*
6342
6356
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -6424,7 +6438,7 @@ function createInteractionRequiredAuthError(errorCode) {
6424
6438
  return new InteractionRequiredAuthError(errorCode, InteractionRequiredAuthErrorMessages[errorCode]);
6425
6439
  }
6426
6440
 
6427
- /*! @azure/msal-common v15.3.0 2025-03-20 */
6441
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
6428
6442
 
6429
6443
  /*
6430
6444
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -6496,16 +6510,14 @@ class ProtocolUtils {
6496
6510
  }
6497
6511
  }
6498
6512
 
6499
- /*! @azure/msal-common v15.3.0 2025-03-20 */
6513
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
6500
6514
 
6501
6515
  /*
6502
6516
  * Copyright (c) Microsoft Corporation. All rights reserved.
6503
6517
  * Licensed under the MIT License.
6504
6518
  */
6505
6519
  const KeyLocation = {
6506
- SW: "sw",
6507
- UHW: "uhw",
6508
- };
6520
+ SW: "sw"};
6509
6521
  /** @internal */
6510
6522
  class PopTokenGenerator {
6511
6523
  constructor(cryptoUtils, performanceClient) {
@@ -6580,7 +6592,7 @@ class PopTokenGenerator {
6580
6592
  }
6581
6593
  }
6582
6594
 
6583
- /*! @azure/msal-common v15.3.0 2025-03-20 */
6595
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
6584
6596
  /*
6585
6597
  * Copyright (c) Microsoft Corporation. All rights reserved.
6586
6598
  * Licensed under the MIT License.
@@ -6607,7 +6619,7 @@ class PopTokenGenerator {
6607
6619
  }
6608
6620
  }
6609
6621
 
6610
- /*! @azure/msal-common v15.3.0 2025-03-20 */
6622
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
6611
6623
 
6612
6624
  /*
6613
6625
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -6938,7 +6950,7 @@ function buildAccountToCache(cacheStorage, authority, homeAccountId, base64Decod
6938
6950
  return baseAccount;
6939
6951
  }
6940
6952
 
6941
- /*! @azure/msal-common v15.3.0 2025-03-20 */
6953
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
6942
6954
 
6943
6955
  /*
6944
6956
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -7005,7 +7017,7 @@ class RequestValidator {
7005
7017
  }
7006
7018
  }
7007
7019
 
7008
- /*! @azure/msal-common v15.3.0 2025-03-20 */
7020
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
7009
7021
  /*
7010
7022
  * Copyright (c) Microsoft Corporation. All rights reserved.
7011
7023
  * Licensed under the MIT License.
@@ -7023,7 +7035,7 @@ async function getClientAssertion(clientAssertion, clientId, tokenEndpoint) {
7023
7035
  }
7024
7036
  }
7025
7037
 
7026
- /*! @azure/msal-common v15.3.0 2025-03-20 */
7038
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
7027
7039
 
7028
7040
  /*
7029
7041
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -7256,7 +7268,7 @@ class AuthorizationCodeClient extends BaseClient {
7256
7268
  }
7257
7269
  }
7258
7270
 
7259
- /*! @azure/msal-common v15.3.0 2025-03-20 */
7271
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
7260
7272
 
7261
7273
  /*
7262
7274
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -7465,7 +7477,7 @@ class RefreshTokenClient extends BaseClient {
7465
7477
  }
7466
7478
  }
7467
7479
 
7468
- /*! @azure/msal-common v15.3.0 2025-03-20 */
7480
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
7469
7481
 
7470
7482
  /*
7471
7483
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -7563,7 +7575,7 @@ class SilentFlowClient extends BaseClient {
7563
7575
  }
7564
7576
  }
7565
7577
 
7566
- /*! @azure/msal-common v15.3.0 2025-03-20 */
7578
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
7567
7579
 
7568
7580
  /*
7569
7581
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -7578,7 +7590,7 @@ const StubbedNetworkModule = {
7578
7590
  },
7579
7591
  };
7580
7592
 
7581
- /*! @azure/msal-common v15.3.0 2025-03-20 */
7593
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
7582
7594
 
7583
7595
  /*
7584
7596
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -7707,10 +7719,10 @@ function getStandardAuthorizeRequestParameters(authOptions, request, logger, per
7707
7719
  if (request.embeddedClientId) {
7708
7720
  addBrokerParameters(parameters, authOptions.clientId, authOptions.redirectUri);
7709
7721
  }
7710
- if (request.extraQueryParameters) {
7711
- addExtraQueryParameters(parameters, request.extraQueryParameters);
7712
- }
7713
- if (authOptions.instanceAware) {
7722
+ // If extraQueryParameters includes instance_aware its value will be added when extraQueryParameters are added
7723
+ if (authOptions.instanceAware &&
7724
+ (!request.extraQueryParameters ||
7725
+ !Object.keys(request.extraQueryParameters).includes(INSTANCE_AWARE))) {
7714
7726
  addInstanceAware(parameters);
7715
7727
  }
7716
7728
  return parameters;
@@ -7802,7 +7814,7 @@ function extractLoginHint(account) {
7802
7814
  return account.idTokenClaims?.login_hint || null;
7803
7815
  }
7804
7816
 
7805
- /*! @azure/msal-common v15.3.0 2025-03-20 */
7817
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
7806
7818
 
7807
7819
  /*
7808
7820
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -7860,7 +7872,7 @@ class AuthenticationHeaderParser {
7860
7872
  }
7861
7873
  }
7862
7874
 
7863
- /*! @azure/msal-common v15.3.0 2025-03-20 */
7875
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
7864
7876
 
7865
7877
  /*
7866
7878
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -8123,7 +8135,7 @@ class ServerTelemetryManager {
8123
8135
  }
8124
8136
  }
8125
8137
 
8126
- /*! @azure/msal-common v15.3.0 2025-03-20 */
8138
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
8127
8139
  /*
8128
8140
  * Copyright (c) Microsoft Corporation. All rights reserved.
8129
8141
  * Licensed under the MIT License.
@@ -8131,7 +8143,7 @@ class ServerTelemetryManager {
8131
8143
  const missingKidError = "missing_kid_error";
8132
8144
  const missingAlgError = "missing_alg_error";
8133
8145
 
8134
- /*! @azure/msal-common v15.3.0 2025-03-20 */
8146
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
8135
8147
 
8136
8148
  /*
8137
8149
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -8156,7 +8168,7 @@ function createJoseHeaderError(code) {
8156
8168
  return new JoseHeaderError(code, JoseHeaderErrorMessages[code]);
8157
8169
  }
8158
8170
 
8159
- /*! @azure/msal-common v15.3.0 2025-03-20 */
8171
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
8160
8172
 
8161
8173
  /*
8162
8174
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -8196,7 +8208,7 @@ class JoseHeader {
8196
8208
  }
8197
8209
  }
8198
8210
 
8199
- /*! @azure/msal-common v15.3.0 2025-03-20 */
8211
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
8200
8212
 
8201
8213
  /*
8202
8214
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -8275,7 +8287,7 @@ class StubPerformanceClient {
8275
8287
  }
8276
8288
  }
8277
8289
 
8278
- /*! @azure/msal-common v15.3.0 2025-03-20 */
8290
+ /*! @azure/msal-common v15.4.0 2025-03-26 */
8279
8291
 
8280
8292
  /*
8281
8293
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -8889,6 +8901,8 @@ class PerformanceClient {
8889
8901
  * Licensed under the MIT License.
8890
8902
  */
8891
8903
  const pkceNotCreated = "pkce_not_created";
8904
+ const earJwkEmpty = "ear_jwk_empty";
8905
+ const earJweEmpty = "ear_jwe_empty";
8892
8906
  const cryptoNonExistent = "crypto_nonexistent";
8893
8907
  const emptyNavigateUri = "empty_navigate_uri";
8894
8908
  const hashEmptyError = "hash_empty_error";
@@ -8911,7 +8925,6 @@ const noAccountError = "no_account_error";
8911
8925
  const silentPromptValueError = "silent_prompt_value_error";
8912
8926
  const noTokenRequestCacheError = "no_token_request_cache_error";
8913
8927
  const unableToParseTokenRequestCacheError = "unable_to_parse_token_request_cache_error";
8914
- const noCachedAuthorityError = "no_cached_authority_error";
8915
8928
  const authRequestNotSetError = "auth_request_not_set_error";
8916
8929
  const invalidCacheType = "invalid_cache_type";
8917
8930
  const nonBrowserEnvironment = "non_browser_environment";
@@ -8935,7 +8948,8 @@ const nativePromptNotSupported = "native_prompt_not_supported";
8935
8948
  const invalidBase64String = "invalid_base64_string";
8936
8949
  const invalidPopTokenRequest = "invalid_pop_token_request";
8937
8950
  const failedToBuildHeaders = "failed_to_build_headers";
8938
- const failedToParseHeaders = "failed_to_parse_headers";
8951
+ const failedToParseHeaders = "failed_to_parse_headers";
8952
+ const failedToDecryptEarResponse = "failed_to_decrypt_ear_response";
8939
8953
 
8940
8954
  var BrowserAuthErrorCodes = /*#__PURE__*/Object.freeze({
8941
8955
  __proto__: null,
@@ -8948,9 +8962,12 @@ var BrowserAuthErrorCodes = /*#__PURE__*/Object.freeze({
8948
8962
  cryptoNonExistent: cryptoNonExistent,
8949
8963
  databaseNotOpen: databaseNotOpen,
8950
8964
  databaseUnavailable: databaseUnavailable,
8965
+ earJweEmpty: earJweEmpty,
8966
+ earJwkEmpty: earJwkEmpty,
8951
8967
  emptyNavigateUri: emptyNavigateUri,
8952
8968
  emptyWindowError: emptyWindowError,
8953
8969
  failedToBuildHeaders: failedToBuildHeaders,
8970
+ failedToDecryptEarResponse: failedToDecryptEarResponse,
8954
8971
  failedToParseHeaders: failedToParseHeaders,
8955
8972
  failedToParseResponse: failedToParseResponse,
8956
8973
  getRequestFailed: getRequestFailed,
@@ -8968,7 +8985,6 @@ var BrowserAuthErrorCodes = /*#__PURE__*/Object.freeze({
8968
8985
  nativeHandshakeTimeout: nativeHandshakeTimeout,
8969
8986
  nativePromptNotSupported: nativePromptNotSupported,
8970
8987
  noAccountError: noAccountError,
8971
- noCachedAuthorityError: noCachedAuthorityError,
8972
8988
  noNetworkConnectivity: noNetworkConnectivity,
8973
8989
  noStateInHash: noStateInHash,
8974
8990
  noTokenRequestCacheError: noTokenRequestCacheError,
@@ -8999,6 +9015,8 @@ const ErrorLink = "For more visit: aka.ms/msaljs/browser-errors";
8999
9015
  */
9000
9016
  const BrowserAuthErrorMessages = {
9001
9017
  [pkceNotCreated]: "The PKCE code challenge and verifier could not be generated.",
9018
+ [earJwkEmpty]: "No EAR encryption key provided. This is unexpected.",
9019
+ [earJweEmpty]: "Server response does not contain ear_jwe property. This is unexpected.",
9002
9020
  [cryptoNonExistent]: "The crypto object or function is not available.",
9003
9021
  [emptyNavigateUri]: "Navigation URI is empty. Please check stack trace for more info.",
9004
9022
  [hashEmptyError]: `Hash value cannot be processed because it is empty. Please verify that your redirectUri is not clearing the hash. ${ErrorLink}`,
@@ -9021,7 +9039,6 @@ const BrowserAuthErrorMessages = {
9021
9039
  [silentPromptValueError]: "The value given for the prompt value is not valid for silent requests - must be set to 'none' or 'no_session'.",
9022
9040
  [noTokenRequestCacheError]: "No token request found in cache.",
9023
9041
  [unableToParseTokenRequestCacheError]: "The cached token request could not be parsed.",
9024
- [noCachedAuthorityError]: "No cached authority found.",
9025
9042
  [authRequestNotSetError]: "Auth Request not set. Please ensure initiateAuthRequest was called from the InteractionHandler",
9026
9043
  [invalidCacheType]: "Invalid cache type",
9027
9044
  [nonBrowserEnvironment]: "Login and token requests are not supported in non-browser environments.",
@@ -9046,6 +9063,7 @@ const BrowserAuthErrorMessages = {
9046
9063
  [invalidPopTokenRequest]: "Invalid PoP token request. The request should not have both a popKid value and signPopToken set to true.",
9047
9064
  [failedToBuildHeaders]: "Failed to build request headers object.",
9048
9065
  [failedToParseHeaders]: "Failed to parse response headers",
9066
+ [failedToDecryptEarResponse]: "Failed to decrypt ear response",
9049
9067
  };
9050
9068
  /**
9051
9069
  * BrowserAuthErrorMessage class containing string constants used by error codes and messages.
@@ -9148,10 +9166,6 @@ const BrowserAuthErrorMessage = {
9148
9166
  code: unableToParseTokenRequestCacheError,
9149
9167
  desc: BrowserAuthErrorMessages[unableToParseTokenRequestCacheError],
9150
9168
  },
9151
- noCachedAuthorityError: {
9152
- code: noCachedAuthorityError,
9153
- desc: BrowserAuthErrorMessages[noCachedAuthorityError],
9154
- },
9155
9169
  authRequestNotSet: {
9156
9170
  code: authRequestNotSetError,
9157
9171
  desc: BrowserAuthErrorMessages[authRequestNotSetError],
@@ -9263,10 +9277,6 @@ function createBrowserAuthError(errorCode, subError) {
9263
9277
  * Constants
9264
9278
  */
9265
9279
  const BrowserConstants = {
9266
- /**
9267
- * Interaction in progress cache value
9268
- */
9269
- INTERACTION_IN_PROGRESS_VALUE: "interaction_in_progress",
9270
9280
  /**
9271
9281
  * Invalid grant error code
9272
9282
  */
@@ -9319,21 +9329,12 @@ const HTTP_REQUEST_TYPE = {
9319
9329
  * Temporary cache keys for MSAL, deleted after any request.
9320
9330
  */
9321
9331
  const TemporaryCacheKeys = {
9322
- AUTHORITY: "authority",
9323
- ACQUIRE_TOKEN_ACCOUNT: "acquireToken.account",
9324
- SESSION_STATE: "session.state",
9325
- REQUEST_STATE: "request.state",
9326
- NONCE_IDTOKEN: "nonce.id_token",
9327
9332
  ORIGIN_URI: "request.origin",
9328
- RENEW_STATUS: "token.renew.status",
9329
9333
  URL_HASH: "urlHash",
9330
9334
  REQUEST_PARAMS: "request.params",
9331
- SCOPES: "scopes",
9335
+ VERIFIER: "code.verifier",
9332
9336
  INTERACTION_STATUS_KEY: "interaction.status",
9333
- CCS_CREDENTIAL: "ccs.credential",
9334
- CORRELATION_ID: "request.correlationId",
9335
9337
  NATIVE_REQUEST: "request.native",
9336
- REDIRECT_CONTEXT: "request.redirect.context",
9337
9338
  };
9338
9339
  const StaticCacheKeys = {
9339
9340
  ACCOUNT_KEYS: "msal.account.keys",
@@ -9703,6 +9704,69 @@ async function importJwk(key, extractable, usages) {
9703
9704
  async function sign(key, data) {
9704
9705
  return window.crypto.subtle.sign(keygenAlgorithmOptions, key, data);
9705
9706
  }
9707
+ /**
9708
+ * Generates Base64 encoded jwk used in the Encrypted Authorize Response (EAR) flow
9709
+ */
9710
+ async function generateEarKey() {
9711
+ const key = await generateBaseKey();
9712
+ const keyStr = urlEncodeArr(new Uint8Array(key));
9713
+ const jwk = {
9714
+ alg: "dir",
9715
+ kty: "oct",
9716
+ k: keyStr,
9717
+ };
9718
+ return base64Encode(JSON.stringify(jwk));
9719
+ }
9720
+ /**
9721
+ * Parses earJwk for encryption key and returns CryptoKey object
9722
+ * @param earJwk
9723
+ * @returns
9724
+ */
9725
+ async function importEarKey(earJwk) {
9726
+ const b64DecodedJwk = base64Decode(earJwk);
9727
+ const jwkJson = JSON.parse(b64DecodedJwk);
9728
+ const rawKey = jwkJson.k;
9729
+ const keyBuffer = base64DecToArr(rawKey);
9730
+ return window.crypto.subtle.importKey(RAW, keyBuffer, AES_GCM, false, [
9731
+ DECRYPT,
9732
+ ]);
9733
+ }
9734
+ /**
9735
+ * Decrypt ear_jwe response returned in the Encrypted Authorize Response (EAR) flow
9736
+ * @param earJwk
9737
+ * @param earJwe
9738
+ * @returns
9739
+ */
9740
+ async function decryptEarResponse(earJwk, earJwe) {
9741
+ const earJweParts = earJwe.split(".");
9742
+ if (earJweParts.length !== 5) {
9743
+ throw createBrowserAuthError(failedToDecryptEarResponse, "jwe_length");
9744
+ }
9745
+ const key = await importEarKey(earJwk).catch(() => {
9746
+ throw createBrowserAuthError(failedToDecryptEarResponse, "import_key");
9747
+ });
9748
+ try {
9749
+ const header = new TextEncoder().encode(earJweParts[0]);
9750
+ const iv = base64DecToArr(earJweParts[2]);
9751
+ const ciphertext = base64DecToArr(earJweParts[3]);
9752
+ const tag = base64DecToArr(earJweParts[4]);
9753
+ const tagLengthBits = tag.byteLength * 8;
9754
+ // Concat ciphertext and tag
9755
+ const encryptedData = new Uint8Array(ciphertext.length + tag.length);
9756
+ encryptedData.set(ciphertext);
9757
+ encryptedData.set(tag, ciphertext.length);
9758
+ const decryptedData = await window.crypto.subtle.decrypt({
9759
+ name: AES_GCM,
9760
+ iv: iv,
9761
+ tagLength: tagLengthBits,
9762
+ additionalData: header,
9763
+ }, key, encryptedData);
9764
+ return new TextDecoder().decode(decryptedData);
9765
+ }
9766
+ catch (e) {
9767
+ throw createBrowserAuthError(failedToDecryptEarResponse, "decrypt");
9768
+ }
9769
+ }
9706
9770
  /**
9707
9771
  * Generates symmetric base encryption key. This may be stored as all encryption/decryption keys will be derived from this one.
9708
9772
  */
@@ -10288,9 +10352,9 @@ function buildConfiguration({ auth: userInputAuth, cache: userInputCache, system
10288
10352
  const logger = new Logger(providedSystemOptions.loggerOptions);
10289
10353
  logger.warning(JSON.stringify(createClientConfigurationError(cannotSetOIDCOptions)));
10290
10354
  }
10291
- // Throw an error if user has set allowPlatformBroker to true without being in AAD protocol mode
10355
+ // Throw an error if user has set allowPlatformBroker to true with OIDC protocol mode
10292
10356
  if (userInputAuth?.protocolMode &&
10293
- userInputAuth.protocolMode !== ProtocolMode.AAD &&
10357
+ userInputAuth.protocolMode === ProtocolMode.OIDC &&
10294
10358
  providedSystemOptions?.allowPlatformBroker) {
10295
10359
  throw createClientConfigurationError(cannotAllowPlatformBroker);
10296
10360
  }
@@ -10312,7 +10376,7 @@ function buildConfiguration({ auth: userInputAuth, cache: userInputCache, system
10312
10376
 
10313
10377
  /* eslint-disable header/header */
10314
10378
  const name = "@azure/msal-browser";
10315
- const version = "4.8.0";
10379
+ const version = "4.9.1";
10316
10380
 
10317
10381
  /*
10318
10382
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -11633,28 +11697,6 @@ class SessionStorage {
11633
11697
  }
11634
11698
  }
11635
11699
 
11636
- /*
11637
- * Copyright (c) Microsoft Corporation. All rights reserved.
11638
- * Licensed under the MIT License.
11639
- */
11640
- /**
11641
- * Extracts the BrowserStateObject from the state string.
11642
- * @param browserCrypto
11643
- * @param state
11644
- */
11645
- function extractBrowserRequestState(browserCrypto, state) {
11646
- if (!state) {
11647
- return null;
11648
- }
11649
- try {
11650
- const requestStateObj = ProtocolUtils.parseRequestState(browserCrypto, state);
11651
- return requestStateObj.libraryState.meta;
11652
- }
11653
- catch (e) {
11654
- throw createClientAuthError(invalidState);
11655
- }
11656
- }
11657
-
11658
11700
  /*
11659
11701
  * Copyright (c) Microsoft Corporation. All rights reserved.
11660
11702
  * Licensed under the MIT License.
@@ -12354,177 +12396,53 @@ class BrowserCacheManager extends CacheManager {
12354
12396
  }
12355
12397
  return JSON.stringify(key);
12356
12398
  }
12357
- /**
12358
- * Create authorityKey to cache authority
12359
- * @param state
12360
- */
12361
- generateAuthorityKey(stateString) {
12362
- const { libraryState: { id: stateId }, } = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString);
12363
- return this.generateCacheKey(`${TemporaryCacheKeys.AUTHORITY}.${stateId}`);
12364
- }
12365
- /**
12366
- * Create Nonce key to cache nonce
12367
- * @param state
12368
- */
12369
- generateNonceKey(stateString) {
12370
- const { libraryState: { id: stateId }, } = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString);
12371
- return this.generateCacheKey(`${TemporaryCacheKeys.NONCE_IDTOKEN}.${stateId}`);
12372
- }
12373
- /**
12374
- * Creates full cache key for the request state
12375
- * @param stateString State string for the request
12376
- */
12377
- generateStateKey(stateString) {
12378
- // Use the library state id to key temp storage for uniqueness for multiple concurrent requests
12379
- const { libraryState: { id: stateId }, } = ProtocolUtils.parseRequestState(this.cryptoImpl, stateString);
12380
- return this.generateCacheKey(`${TemporaryCacheKeys.REQUEST_STATE}.${stateId}`);
12381
- }
12382
- /**
12383
- * Gets the cached authority based on the cached state. Returns empty if no cached state found.
12384
- */
12385
- getCachedAuthority(cachedState) {
12386
- const stateCacheKey = this.generateStateKey(cachedState);
12387
- const state = this.getTemporaryCache(stateCacheKey);
12388
- if (!state) {
12389
- return null;
12390
- }
12391
- const authorityCacheKey = this.generateAuthorityKey(state);
12392
- return this.getTemporaryCache(authorityCacheKey);
12393
- }
12394
- /**
12395
- * Updates account, authority, and state in cache
12396
- * @param serverAuthenticationRequest
12397
- * @param account
12398
- */
12399
- updateCacheEntries(state, nonce, authorityInstance, loginHint, account) {
12400
- this.logger.trace("BrowserCacheManager.updateCacheEntries called");
12401
- // Cache the request state
12402
- const stateCacheKey = this.generateStateKey(state);
12403
- this.setTemporaryCache(stateCacheKey, state, false);
12404
- // Cache the nonce
12405
- const nonceCacheKey = this.generateNonceKey(state);
12406
- this.setTemporaryCache(nonceCacheKey, nonce, false);
12407
- // Cache authorityKey
12408
- const authorityCacheKey = this.generateAuthorityKey(state);
12409
- this.setTemporaryCache(authorityCacheKey, authorityInstance, false);
12410
- if (account) {
12411
- const ccsCredential = {
12412
- credential: account.homeAccountId,
12413
- type: CcsCredentialType.HOME_ACCOUNT_ID,
12414
- };
12415
- this.setTemporaryCache(TemporaryCacheKeys.CCS_CREDENTIAL, JSON.stringify(ccsCredential), true);
12416
- }
12417
- else if (loginHint) {
12418
- const ccsCredential = {
12419
- credential: loginHint,
12420
- type: CcsCredentialType.UPN,
12421
- };
12422
- this.setTemporaryCache(TemporaryCacheKeys.CCS_CREDENTIAL, JSON.stringify(ccsCredential), true);
12423
- }
12424
- }
12425
12399
  /**
12426
12400
  * Reset all temporary cache items
12427
12401
  * @param state
12428
12402
  */
12429
- resetRequestCache(state) {
12403
+ resetRequestCache() {
12430
12404
  this.logger.trace("BrowserCacheManager.resetRequestCache called");
12431
- // check state and remove associated cache items
12432
- if (state) {
12433
- this.temporaryCacheStorage.getKeys().forEach((key) => {
12434
- if (key.indexOf(state) !== -1) {
12435
- this.removeTemporaryItem(key);
12436
- }
12437
- });
12438
- // delete generic interactive request parameters
12439
- this.removeTemporaryItem(this.generateStateKey(state));
12440
- this.removeTemporaryItem(this.generateNonceKey(state));
12441
- this.removeTemporaryItem(this.generateAuthorityKey(state));
12442
- }
12443
12405
  this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.REQUEST_PARAMS));
12406
+ this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.VERIFIER));
12444
12407
  this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.ORIGIN_URI));
12445
12408
  this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.URL_HASH));
12446
- this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.CORRELATION_ID));
12447
- this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.CCS_CREDENTIAL));
12448
12409
  this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.NATIVE_REQUEST));
12449
12410
  this.setInteractionInProgress(false);
12450
12411
  }
12451
- /**
12452
- * Removes temporary cache for the provided state
12453
- * @param stateString
12454
- */
12455
- cleanRequestByState(stateString) {
12456
- this.logger.trace("BrowserCacheManager.cleanRequestByState called");
12457
- // Interaction is completed - remove interaction status.
12458
- if (stateString) {
12459
- const stateKey = this.generateStateKey(stateString);
12460
- const cachedState = this.temporaryCacheStorage.getItem(stateKey);
12461
- this.logger.infoPii(`BrowserCacheManager.cleanRequestByState: Removing temporary cache items for state: ${cachedState}`);
12462
- this.resetRequestCache(cachedState || Constants.EMPTY_STRING);
12463
- }
12464
- }
12465
- /**
12466
- * Looks in temporary cache for any state values with the provided interactionType and removes all temporary cache items for that state
12467
- * Used in scenarios where temp cache needs to be cleaned but state is not known, such as clicking browser back button.
12468
- * @param interactionType
12469
- */
12470
- cleanRequestByInteractionType(interactionType) {
12471
- this.logger.trace("BrowserCacheManager.cleanRequestByInteractionType called");
12472
- // Loop through all keys to find state key
12473
- this.temporaryCacheStorage.getKeys().forEach((key) => {
12474
- // If this key is not the state key, move on
12475
- if (key.indexOf(TemporaryCacheKeys.REQUEST_STATE) === -1) {
12476
- return;
12477
- }
12478
- // Retrieve state value, return if not a valid value
12479
- const stateValue = this.temporaryCacheStorage.getItem(key);
12480
- if (!stateValue) {
12481
- return;
12482
- }
12483
- // Extract state and ensure it matches given InteractionType, then clean request cache
12484
- const parsedState = extractBrowserRequestState(this.cryptoImpl, stateValue);
12485
- if (parsedState &&
12486
- parsedState.interactionType === interactionType) {
12487
- this.logger.infoPii(`BrowserCacheManager.cleanRequestByInteractionType: Removing temporary cache items for state: ${stateValue}`);
12488
- this.resetRequestCache(stateValue);
12489
- }
12490
- });
12491
- this.setInteractionInProgress(false);
12492
- }
12493
- cacheCodeRequest(authCodeRequest) {
12494
- this.logger.trace("BrowserCacheManager.cacheCodeRequest called");
12412
+ cacheAuthorizeRequest(authCodeRequest, codeVerifier) {
12413
+ this.logger.trace("BrowserCacheManager.cacheAuthorizeRequest called");
12495
12414
  const encodedValue = base64Encode(JSON.stringify(authCodeRequest));
12496
12415
  this.setTemporaryCache(TemporaryCacheKeys.REQUEST_PARAMS, encodedValue, true);
12416
+ if (codeVerifier) {
12417
+ const encodedVerifier = base64Encode(codeVerifier);
12418
+ this.setTemporaryCache(TemporaryCacheKeys.VERIFIER, encodedVerifier, true);
12419
+ }
12497
12420
  }
12498
12421
  /**
12499
12422
  * Gets the token exchange parameters from the cache. Throws an error if nothing is found.
12500
12423
  */
12501
- getCachedRequest(state) {
12424
+ getCachedRequest() {
12502
12425
  this.logger.trace("BrowserCacheManager.getCachedRequest called");
12503
12426
  // Get token request from cache and parse as TokenExchangeParameters.
12504
12427
  const encodedTokenRequest = this.getTemporaryCache(TemporaryCacheKeys.REQUEST_PARAMS, true);
12505
12428
  if (!encodedTokenRequest) {
12506
12429
  throw createBrowserAuthError(noTokenRequestCacheError);
12507
12430
  }
12431
+ const encodedVerifier = this.getTemporaryCache(TemporaryCacheKeys.VERIFIER, true);
12508
12432
  let parsedRequest;
12433
+ let verifier = "";
12509
12434
  try {
12510
12435
  parsedRequest = JSON.parse(base64Decode(encodedTokenRequest));
12436
+ if (encodedVerifier) {
12437
+ verifier = base64Decode(encodedVerifier);
12438
+ }
12511
12439
  }
12512
12440
  catch (e) {
12513
12441
  this.logger.errorPii(`Attempted to parse: ${encodedTokenRequest}`);
12514
12442
  this.logger.error(`Parsing cached token request threw with error: ${e}`);
12515
12443
  throw createBrowserAuthError(unableToParseTokenRequestCacheError);
12516
12444
  }
12517
- this.removeTemporaryItem(this.generateCacheKey(TemporaryCacheKeys.REQUEST_PARAMS));
12518
- // Get cached authority and use if no authority is cached with request.
12519
- if (!parsedRequest.authority) {
12520
- const authorityCacheKey = this.generateAuthorityKey(state);
12521
- const cachedAuthority = this.getTemporaryCache(authorityCacheKey);
12522
- if (!cachedAuthority) {
12523
- throw createBrowserAuthError(noCachedAuthorityError);
12524
- }
12525
- parsedRequest.authority = cachedAuthority;
12526
- }
12527
- return parsedRequest;
12445
+ return [parsedRequest, verifier];
12528
12446
  }
12529
12447
  /**
12530
12448
  * Gets cached native request for redirect flows
@@ -13350,1083 +13268,1103 @@ function createNativeAuthError(code, description, ext) {
13350
13268
  * Copyright (c) Microsoft Corporation. All rights reserved.
13351
13269
  * Licensed under the MIT License.
13352
13270
  */
13353
- class SilentCacheClient extends StandardInteractionClient {
13271
+ class NativeMessageHandler {
13272
+ constructor(logger, handshakeTimeoutMs, performanceClient, extensionId) {
13273
+ this.logger = logger;
13274
+ this.handshakeTimeoutMs = handshakeTimeoutMs;
13275
+ this.extensionId = extensionId;
13276
+ this.resolvers = new Map(); // Used for non-handshake messages
13277
+ this.handshakeResolvers = new Map(); // Used for handshake messages
13278
+ this.messageChannel = new MessageChannel();
13279
+ this.windowListener = this.onWindowMessage.bind(this); // Window event callback doesn't have access to 'this' unless it's bound
13280
+ this.performanceClient = performanceClient;
13281
+ this.handshakeEvent = performanceClient.startMeasurement(PerformanceEvents.NativeMessageHandlerHandshake);
13282
+ }
13354
13283
  /**
13355
- * Returns unexpired tokens from the cache, if available
13356
- * @param silentRequest
13284
+ * Sends a given message to the extension and resolves with the extension response
13285
+ * @param body
13357
13286
  */
13358
- async acquireToken(silentRequest) {
13359
- this.performanceClient.addQueueMeasurement(PerformanceEvents.SilentCacheClientAcquireToken, silentRequest.correlationId);
13360
- // Telemetry manager only used to increment cacheHits here
13361
- const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenSilent_silentFlow);
13362
- const clientConfig = await invokeAsync(this.getClientConfiguration.bind(this), PerformanceEvents.StandardInteractionClientGetClientConfiguration, this.logger, this.performanceClient, this.correlationId)({
13363
- serverTelemetryManager,
13364
- requestAuthority: silentRequest.authority,
13365
- requestAzureCloudOptions: silentRequest.azureCloudOptions,
13366
- account: silentRequest.account,
13287
+ async sendMessage(body) {
13288
+ this.logger.trace("NativeMessageHandler - sendMessage called.");
13289
+ const req = {
13290
+ channel: NativeConstants.CHANNEL_ID,
13291
+ extensionId: this.extensionId,
13292
+ responseId: createNewGuid(),
13293
+ body: body,
13294
+ };
13295
+ this.logger.trace("NativeMessageHandler - Sending request to browser extension");
13296
+ this.logger.tracePii(`NativeMessageHandler - Sending request to browser extension: ${JSON.stringify(req)}`);
13297
+ this.messageChannel.port1.postMessage(req);
13298
+ return new Promise((resolve, reject) => {
13299
+ this.resolvers.set(req.responseId, { resolve, reject });
13367
13300
  });
13368
- const silentAuthClient = new SilentFlowClient(clientConfig, this.performanceClient);
13369
- this.logger.verbose("Silent auth client created");
13301
+ }
13302
+ /**
13303
+ * Returns an instance of the MessageHandler that has successfully established a connection with an extension
13304
+ * @param {Logger} logger
13305
+ * @param {number} handshakeTimeoutMs
13306
+ * @param {IPerformanceClient} performanceClient
13307
+ * @param {ICrypto} crypto
13308
+ */
13309
+ static async createProvider(logger, handshakeTimeoutMs, performanceClient) {
13310
+ logger.trace("NativeMessageHandler - createProvider called.");
13370
13311
  try {
13371
- const response = await invokeAsync(silentAuthClient.acquireCachedToken.bind(silentAuthClient), PerformanceEvents.SilentFlowClientAcquireCachedToken, this.logger, this.performanceClient, silentRequest.correlationId)(silentRequest);
13372
- const authResponse = response[0];
13373
- this.performanceClient.addFields({
13374
- fromCache: true,
13375
- }, silentRequest.correlationId);
13376
- return authResponse;
13312
+ const preferredProvider = new NativeMessageHandler(logger, handshakeTimeoutMs, performanceClient, NativeConstants.PREFERRED_EXTENSION_ID);
13313
+ await preferredProvider.sendHandshakeRequest();
13314
+ return preferredProvider;
13377
13315
  }
13378
- catch (error) {
13379
- if (error instanceof BrowserAuthError &&
13380
- error.errorCode === cryptoKeyNotFound) {
13381
- this.logger.verbose("Signing keypair for bound access token not found. Refreshing bound access token and generating a new crypto keypair.");
13382
- }
13383
- throw error;
13316
+ catch (e) {
13317
+ // If preferred extension fails for whatever reason, fallback to using any installed extension
13318
+ const backupProvider = new NativeMessageHandler(logger, handshakeTimeoutMs, performanceClient);
13319
+ await backupProvider.sendHandshakeRequest();
13320
+ return backupProvider;
13384
13321
  }
13385
13322
  }
13386
13323
  /**
13387
- * API to silenty clear the browser cache.
13388
- * @param logoutRequest
13324
+ * Send handshake request helper.
13389
13325
  */
13390
- logout(logoutRequest) {
13391
- this.logger.verbose("logoutRedirect called");
13392
- const validLogoutRequest = this.initializeLogoutRequest(logoutRequest);
13393
- return this.clearCacheOnLogout(validLogoutRequest?.account);
13394
- }
13395
- }
13396
-
13397
- /*
13398
- * Copyright (c) Microsoft Corporation. All rights reserved.
13399
- * Licensed under the MIT License.
13400
- */
13401
- class NativeInteractionClient extends BaseInteractionClient {
13402
- constructor(config, browserStorage, browserCrypto, logger, eventHandler, navigationClient, apiId, performanceClient, provider, accountId, nativeStorageImpl, correlationId) {
13403
- super(config, browserStorage, browserCrypto, logger, eventHandler, navigationClient, performanceClient, provider, correlationId);
13404
- this.apiId = apiId;
13405
- this.accountId = accountId;
13406
- this.nativeMessageHandler = provider;
13407
- this.nativeStorageManager = nativeStorageImpl;
13408
- this.silentCacheClient = new SilentCacheClient(config, this.nativeStorageManager, browserCrypto, logger, eventHandler, navigationClient, performanceClient, provider, correlationId);
13409
- const extensionName = this.nativeMessageHandler.getExtensionId() ===
13410
- NativeConstants.PREFERRED_EXTENSION_ID
13411
- ? "chrome"
13412
- : this.nativeMessageHandler.getExtensionId()?.length
13413
- ? "unknown"
13414
- : undefined;
13415
- this.skus = ServerTelemetryManager.makeExtraSkuString({
13416
- libraryName: BrowserConstants.MSAL_SKU,
13417
- libraryVersion: version,
13418
- extensionName: extensionName,
13419
- extensionVersion: this.nativeMessageHandler.getExtensionVersion(),
13326
+ async sendHandshakeRequest() {
13327
+ this.logger.trace("NativeMessageHandler - sendHandshakeRequest called.");
13328
+ // Register this event listener before sending handshake
13329
+ window.addEventListener("message", this.windowListener, false); // false is important, because content script message processing should work first
13330
+ const req = {
13331
+ channel: NativeConstants.CHANNEL_ID,
13332
+ extensionId: this.extensionId,
13333
+ responseId: createNewGuid(),
13334
+ body: {
13335
+ method: NativeExtensionMethod.HandshakeRequest,
13336
+ },
13337
+ };
13338
+ this.handshakeEvent.add({
13339
+ extensionId: this.extensionId,
13340
+ extensionHandshakeTimeoutMs: this.handshakeTimeoutMs,
13420
13341
  });
13421
- }
13422
- /**
13423
- * Adds SKUs to request extra query parameters
13424
- * @param request {NativeTokenRequest}
13425
- * @private
13426
- */
13427
- addRequestSKUs(request) {
13428
- request.extraParameters = {
13429
- ...request.extraParameters,
13430
- [X_CLIENT_EXTRA_SKU]: this.skus,
13342
+ this.messageChannel.port1.onmessage = (event) => {
13343
+ this.onChannelMessage(event);
13431
13344
  };
13432
- }
13433
- /**
13434
- * Acquire token from native platform via browser extension
13435
- * @param request
13436
- */
13437
- async acquireToken(request, cacheLookupPolicy) {
13438
- this.performanceClient.addQueueMeasurement(PerformanceEvents.NativeInteractionClientAcquireToken, request.correlationId);
13439
- this.logger.trace("NativeInteractionClient - acquireToken called.");
13440
- // start the perf measurement
13441
- const nativeATMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.NativeInteractionClientAcquireToken, request.correlationId);
13442
- const reqTimestamp = nowSeconds();
13443
- const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
13444
- try {
13445
- // initialize native request
13446
- const nativeRequest = await this.initializeNativeRequest(request);
13447
- // check if the tokens can be retrieved from internal cache
13448
- try {
13449
- const result = await this.acquireTokensFromCache(this.accountId, nativeRequest);
13450
- nativeATMeasurement.end({
13451
- success: true,
13452
- isNativeBroker: false,
13453
- fromCache: true,
13454
- });
13455
- return result;
13456
- }
13457
- catch (e) {
13458
- if (cacheLookupPolicy === CacheLookupPolicy.AccessToken) {
13459
- this.logger.info("MSAL internal Cache does not contain tokens, return error as per cache policy");
13460
- throw e;
13461
- }
13462
- // continue with a native call for any and all errors
13463
- this.logger.info("MSAL internal Cache does not contain tokens, proceed to make a native call");
13464
- }
13465
- const { ...nativeTokenRequest } = nativeRequest;
13466
- // fall back to native calls
13467
- const messageBody = {
13468
- method: NativeExtensionMethod.GetToken,
13469
- request: nativeTokenRequest,
13470
- };
13471
- const response = await this.nativeMessageHandler.sendMessage(messageBody);
13472
- const validatedResponse = this.validateNativeResponse(response);
13473
- return await this.handleNativeResponse(validatedResponse, nativeRequest, reqTimestamp)
13474
- .then((result) => {
13475
- nativeATMeasurement.end({
13476
- success: true,
13477
- isNativeBroker: true,
13478
- requestId: result.requestId,
13479
- });
13480
- serverTelemetryManager.clearNativeBrokerErrorCode();
13481
- return result;
13482
- })
13483
- .catch((error) => {
13484
- nativeATMeasurement.end({
13345
+ window.postMessage(req, window.origin, [this.messageChannel.port2]);
13346
+ return new Promise((resolve, reject) => {
13347
+ this.handshakeResolvers.set(req.responseId, { resolve, reject });
13348
+ this.timeoutId = window.setTimeout(() => {
13349
+ /*
13350
+ * Throw an error if neither HandshakeResponse nor original Handshake request are received in a reasonable timeframe.
13351
+ * This typically suggests an event handler stopped propagation of the Handshake request but did not respond to it on the MessageChannel port
13352
+ */
13353
+ window.removeEventListener("message", this.windowListener, false);
13354
+ this.messageChannel.port1.close();
13355
+ this.messageChannel.port2.close();
13356
+ this.handshakeEvent.end({
13357
+ extensionHandshakeTimedOut: true,
13485
13358
  success: false,
13486
- errorCode: error.errorCode,
13487
- subErrorCode: error.subError,
13488
- isNativeBroker: true,
13489
13359
  });
13490
- throw error;
13491
- });
13492
- }
13493
- catch (e) {
13494
- if (e instanceof NativeAuthError) {
13495
- serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode);
13496
- }
13497
- throw e;
13498
- }
13499
- }
13500
- /**
13501
- * Creates silent flow request
13502
- * @param request
13503
- * @param cachedAccount
13504
- * @returns CommonSilentFlowRequest
13505
- */
13506
- createSilentCacheRequest(request, cachedAccount) {
13507
- return {
13508
- authority: request.authority,
13509
- correlationId: this.correlationId,
13510
- scopes: ScopeSet.fromString(request.scope).asArray(),
13511
- account: cachedAccount,
13512
- forceRefresh: false,
13513
- };
13360
+ reject(createBrowserAuthError(nativeHandshakeTimeout));
13361
+ this.handshakeResolvers.delete(req.responseId);
13362
+ }, this.handshakeTimeoutMs); // Use a reasonable timeout in milliseconds here
13363
+ });
13514
13364
  }
13515
13365
  /**
13516
- * Fetches the tokens from the cache if un-expired
13517
- * @param nativeAccountId
13518
- * @param request
13519
- * @returns authenticationResult
13366
+ * Invoked when a message is posted to the window. If a handshake request is received it means the extension is not installed.
13367
+ * @param event
13520
13368
  */
13521
- async acquireTokensFromCache(nativeAccountId, request) {
13522
- if (!nativeAccountId) {
13523
- this.logger.warning("NativeInteractionClient:acquireTokensFromCache - No nativeAccountId provided");
13524
- throw createClientAuthError(noAccountFound);
13369
+ onWindowMessage(event) {
13370
+ this.logger.trace("NativeMessageHandler - onWindowMessage called");
13371
+ // We only accept messages from ourselves
13372
+ if (event.source !== window) {
13373
+ return;
13525
13374
  }
13526
- // fetch the account from browser cache
13527
- const account = this.browserStorage.getBaseAccountInfo({
13528
- nativeAccountId,
13529
- });
13530
- if (!account) {
13531
- throw createClientAuthError(noAccountFound);
13375
+ const request = event.data;
13376
+ if (!request.channel ||
13377
+ request.channel !== NativeConstants.CHANNEL_ID) {
13378
+ return;
13532
13379
  }
13533
- // leverage silent flow for cached tokens retrieval
13534
- try {
13535
- const silentRequest = this.createSilentCacheRequest(request, account);
13536
- const result = await this.silentCacheClient.acquireToken(silentRequest);
13537
- const fullAccount = {
13538
- ...account,
13539
- idTokenClaims: result?.idTokenClaims,
13540
- idToken: result?.idToken,
13541
- };
13542
- return {
13543
- ...result,
13544
- account: fullAccount,
13545
- };
13380
+ if (request.extensionId && request.extensionId !== this.extensionId) {
13381
+ return;
13546
13382
  }
13547
- catch (e) {
13548
- throw e;
13383
+ if (request.body.method === NativeExtensionMethod.HandshakeRequest) {
13384
+ const handshakeResolver = this.handshakeResolvers.get(request.responseId);
13385
+ /*
13386
+ * Filter out responses with no matched resolvers sooner to keep channel ports open while waiting for
13387
+ * the proper response.
13388
+ */
13389
+ if (!handshakeResolver) {
13390
+ this.logger.trace(`NativeMessageHandler.onWindowMessage - resolver can't be found for request ${request.responseId}`);
13391
+ return;
13392
+ }
13393
+ // If we receive this message back it means no extension intercepted the request, meaning no extension supporting handshake protocol is installed
13394
+ this.logger.verbose(request.extensionId
13395
+ ? `Extension with id: ${request.extensionId} not installed`
13396
+ : "No extension installed");
13397
+ clearTimeout(this.timeoutId);
13398
+ this.messageChannel.port1.close();
13399
+ this.messageChannel.port2.close();
13400
+ window.removeEventListener("message", this.windowListener, false);
13401
+ this.handshakeEvent.end({
13402
+ success: false,
13403
+ extensionInstalled: false,
13404
+ });
13405
+ handshakeResolver.reject(createBrowserAuthError(nativeExtensionNotInstalled));
13549
13406
  }
13550
13407
  }
13551
13408
  /**
13552
- * Acquires a token from native platform then redirects to the redirectUri instead of returning the response
13553
- * @param {RedirectRequest} request
13554
- * @param {InProgressPerformanceEvent} rootMeasurement
13409
+ * Invoked when a message is received from the extension on the MessageChannel port
13410
+ * @param event
13555
13411
  */
13556
- async acquireTokenRedirect(request, rootMeasurement) {
13557
- this.logger.trace("NativeInteractionClient - acquireTokenRedirect called.");
13558
- const { ...remainingParameters } = request;
13559
- delete remainingParameters.onRedirectNavigate;
13560
- const nativeRequest = await this.initializeNativeRequest(remainingParameters);
13561
- const messageBody = {
13562
- method: NativeExtensionMethod.GetToken,
13563
- request: nativeRequest,
13564
- };
13412
+ onChannelMessage(event) {
13413
+ this.logger.trace("NativeMessageHandler - onChannelMessage called.");
13414
+ const request = event.data;
13415
+ const resolver = this.resolvers.get(request.responseId);
13416
+ const handshakeResolver = this.handshakeResolvers.get(request.responseId);
13565
13417
  try {
13566
- const response = await this.nativeMessageHandler.sendMessage(messageBody);
13567
- this.validateNativeResponse(response);
13568
- }
13569
- catch (e) {
13570
- // Only throw fatal errors here to allow application to fallback to regular redirect. Otherwise proceed and the error will be thrown in handleRedirectPromise
13571
- if (e instanceof NativeAuthError) {
13572
- const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
13573
- serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode);
13574
- if (isFatalNativeAuthError(e)) {
13575
- throw e;
13418
+ const method = request.body.method;
13419
+ if (method === NativeExtensionMethod.Response) {
13420
+ if (!resolver) {
13421
+ return;
13422
+ }
13423
+ const response = request.body.response;
13424
+ this.logger.trace("NativeMessageHandler - Received response from browser extension");
13425
+ this.logger.tracePii(`NativeMessageHandler - Received response from browser extension: ${JSON.stringify(response)}`);
13426
+ if (response.status !== "Success") {
13427
+ resolver.reject(createNativeAuthError(response.code, response.description, response.ext));
13428
+ }
13429
+ else if (response.result) {
13430
+ if (response.result["code"] &&
13431
+ response.result["description"]) {
13432
+ resolver.reject(createNativeAuthError(response.result["code"], response.result["description"], response.result["ext"]));
13433
+ }
13434
+ else {
13435
+ resolver.resolve(response.result);
13436
+ }
13437
+ }
13438
+ else {
13439
+ throw createAuthError(unexpectedError, "Event does not contain result.");
13576
13440
  }
13441
+ this.resolvers.delete(request.responseId);
13442
+ }
13443
+ else if (method === NativeExtensionMethod.HandshakeResponse) {
13444
+ if (!handshakeResolver) {
13445
+ this.logger.trace(`NativeMessageHandler.onChannelMessage - resolver can't be found for request ${request.responseId}`);
13446
+ return;
13447
+ }
13448
+ clearTimeout(this.timeoutId); // Clear setTimeout
13449
+ window.removeEventListener("message", this.windowListener, false); // Remove 'No extension' listener
13450
+ this.extensionId = request.extensionId;
13451
+ this.extensionVersion = request.body.version;
13452
+ this.logger.verbose(`NativeMessageHandler - Received HandshakeResponse from extension: ${this.extensionId}`);
13453
+ this.handshakeEvent.end({
13454
+ extensionInstalled: true,
13455
+ success: true,
13456
+ });
13457
+ handshakeResolver.resolve();
13458
+ this.handshakeResolvers.delete(request.responseId);
13459
+ }
13460
+ // Do nothing if method is not Response or HandshakeResponse
13461
+ }
13462
+ catch (err) {
13463
+ this.logger.error("Error parsing response from WAM Extension");
13464
+ this.logger.errorPii(`Error parsing response from WAM Extension: ${err}`);
13465
+ this.logger.errorPii(`Unable to parse ${event}`);
13466
+ if (resolver) {
13467
+ resolver.reject(err);
13468
+ }
13469
+ else if (handshakeResolver) {
13470
+ handshakeResolver.reject(err);
13577
13471
  }
13578
13472
  }
13579
- this.browserStorage.setTemporaryCache(TemporaryCacheKeys.NATIVE_REQUEST, JSON.stringify(nativeRequest), true);
13580
- const navigationOptions = {
13581
- apiId: ApiId.acquireTokenRedirect,
13582
- timeout: this.config.system.redirectNavigationTimeout,
13583
- noHistory: false,
13584
- };
13585
- const redirectUri = this.config.auth.navigateToLoginRequestUrl
13586
- ? window.location.href
13587
- : this.getRedirectUri(request.redirectUri);
13588
- rootMeasurement.end({ success: true });
13589
- await this.navigationClient.navigateExternal(redirectUri, navigationOptions); // Need to treat this as external to ensure handleRedirectPromise is run again
13590
13473
  }
13591
13474
  /**
13592
- * If the previous page called native platform for a token using redirect APIs, send the same request again and return the response
13593
- * @param performanceClient {IPerformanceClient?}
13594
- * @param correlationId {string?} correlation identifier
13475
+ * Returns the Id for the browser extension this handler is communicating with
13476
+ * @returns
13595
13477
  */
13596
- async handleRedirectPromise(performanceClient, correlationId) {
13597
- this.logger.trace("NativeInteractionClient - handleRedirectPromise called.");
13598
- if (!this.browserStorage.isInteractionInProgress(true)) {
13599
- this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
13600
- return null;
13601
- }
13602
- // remove prompt from the request to prevent WAM from prompting twice
13603
- const cachedRequest = this.browserStorage.getCachedNativeRequest();
13604
- if (!cachedRequest) {
13605
- this.logger.verbose("NativeInteractionClient - handleRedirectPromise called but there is no cached request, returning null.");
13606
- if (performanceClient && correlationId) {
13607
- performanceClient?.addFields({ errorCode: "no_cached_request" }, correlationId);
13608
- }
13609
- return null;
13610
- }
13611
- const { prompt, ...request } = cachedRequest;
13612
- if (prompt) {
13613
- this.logger.verbose("NativeInteractionClient - handleRedirectPromise called and prompt was included in the original request, removing prompt from cached request to prevent second interaction with native broker window.");
13614
- }
13615
- this.browserStorage.removeItem(this.browserStorage.generateCacheKey(TemporaryCacheKeys.NATIVE_REQUEST));
13616
- const messageBody = {
13617
- method: NativeExtensionMethod.GetToken,
13618
- request: request,
13619
- };
13620
- const reqTimestamp = nowSeconds();
13621
- try {
13622
- this.logger.verbose("NativeInteractionClient - handleRedirectPromise sending message to native broker.");
13623
- const response = await this.nativeMessageHandler.sendMessage(messageBody);
13624
- this.validateNativeResponse(response);
13625
- const result = this.handleNativeResponse(response, request, reqTimestamp);
13626
- this.browserStorage.setInteractionInProgress(false);
13627
- const res = await result;
13628
- const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
13629
- serverTelemetryManager.clearNativeBrokerErrorCode();
13630
- return res;
13631
- }
13632
- catch (e) {
13633
- this.browserStorage.setInteractionInProgress(false);
13634
- throw e;
13635
- }
13478
+ getExtensionId() {
13479
+ return this.extensionId;
13636
13480
  }
13637
13481
  /**
13638
- * Logout from native platform via browser extension
13639
- * @param request
13482
+ * Returns the version for the browser extension this handler is communicating with
13483
+ * @returns
13640
13484
  */
13641
- logout() {
13642
- this.logger.trace("NativeInteractionClient - logout called.");
13643
- return Promise.reject("Logout not implemented yet");
13485
+ getExtensionVersion() {
13486
+ return this.extensionVersion;
13644
13487
  }
13645
13488
  /**
13646
- * Transform response from native platform into AuthenticationResult object which will be returned to the end user
13647
- * @param response
13648
- * @param request
13649
- * @param reqTimestamp
13489
+ * Returns boolean indicating whether or not the request should attempt to use native broker
13490
+ * @param logger
13491
+ * @param config
13492
+ * @param nativeExtensionProvider
13493
+ * @param authenticationScheme
13650
13494
  */
13651
- async handleNativeResponse(response, request, reqTimestamp) {
13652
- this.logger.trace("NativeInteractionClient - handleNativeResponse called.");
13653
- // generate identifiers
13654
- const idTokenClaims = extractTokenClaims(response.id_token, base64Decode);
13655
- const homeAccountIdentifier = this.createHomeAccountIdentifier(response, idTokenClaims);
13656
- const cachedhomeAccountId = this.browserStorage.getAccountInfoFilteredBy({
13657
- nativeAccountId: request.accountId,
13658
- })?.homeAccountId;
13659
- // add exception for double brokering, please note this is temporary and will be fortified in future
13660
- if (request.extraParameters?.child_client_id &&
13661
- response.account.id !== request.accountId) {
13662
- this.logger.info("handleNativeServerResponse: Double broker flow detected, ignoring accountId mismatch");
13495
+ static isPlatformBrokerAvailable(config, logger, nativeExtensionProvider, authenticationScheme) {
13496
+ logger.trace("isPlatformBrokerAvailable called");
13497
+ if (!config.system.allowPlatformBroker) {
13498
+ logger.trace("isPlatformBrokerAvailable: allowPlatformBroker is not enabled, returning false");
13499
+ // Developer disabled WAM
13500
+ return false;
13663
13501
  }
13664
- else if (homeAccountIdentifier !== cachedhomeAccountId &&
13665
- response.account.id !== request.accountId) {
13666
- // User switch in native broker prompt is not supported. All users must first sign in through web flow to ensure server state is in sync
13667
- throw createNativeAuthError(userSwitch);
13502
+ if (!nativeExtensionProvider) {
13503
+ logger.trace("isPlatformBrokerAvailable: Platform extension provider is not initialized, returning false");
13504
+ // Extension is not available
13505
+ return false;
13668
13506
  }
13669
- // Get the preferred_cache domain for the given authority
13670
- const authority = await this.getDiscoveredAuthority({
13671
- requestAuthority: request.authority,
13672
- });
13673
- const baseAccount = buildAccountToCache(this.browserStorage, authority, homeAccountIdentifier, base64Decode, idTokenClaims, response.client_info, undefined, // environment
13674
- idTokenClaims.tid, undefined, // auth code payload
13675
- response.account.id, this.logger);
13676
- // Ensure expires_in is in number format
13677
- response.expires_in = Number(response.expires_in);
13678
- // generate authenticationResult
13679
- const result = await this.generateAuthenticationResult(response, request, idTokenClaims, baseAccount, authority.canonicalAuthority, reqTimestamp);
13680
- // cache accounts and tokens in the appropriate storage
13681
- await this.cacheAccount(baseAccount);
13682
- await this.cacheNativeTokens(response, request, homeAccountIdentifier, idTokenClaims, response.access_token, result.tenantId, reqTimestamp);
13683
- return result;
13507
+ if (authenticationScheme) {
13508
+ switch (authenticationScheme) {
13509
+ case AuthenticationScheme.BEARER:
13510
+ case AuthenticationScheme.POP:
13511
+ logger.trace("isPlatformBrokerAvailable: authenticationScheme is supported, returning true");
13512
+ return true;
13513
+ default:
13514
+ logger.trace("isPlatformBrokerAvailable: authenticationScheme is not supported, returning false");
13515
+ return false;
13516
+ }
13517
+ }
13518
+ return true;
13684
13519
  }
13685
- /**
13686
- * creates an homeAccountIdentifier for the account
13687
- * @param response
13688
- * @param idTokenObj
13689
- * @returns
13690
- */
13691
- createHomeAccountIdentifier(response, idTokenClaims) {
13692
- // Save account in browser storage
13693
- const homeAccountIdentifier = AccountEntity.generateHomeAccountId(response.client_info || Constants.EMPTY_STRING, AuthorityType.Default, this.logger, this.browserCrypto, idTokenClaims);
13694
- return homeAccountIdentifier;
13520
+ }
13521
+
13522
+ /*
13523
+ * Copyright (c) Microsoft Corporation. All rights reserved.
13524
+ * Licensed under the MIT License.
13525
+ */
13526
+ /**
13527
+ * Extracts the BrowserStateObject from the state string.
13528
+ * @param browserCrypto
13529
+ * @param state
13530
+ */
13531
+ function extractBrowserRequestState(browserCrypto, state) {
13532
+ if (!state) {
13533
+ return null;
13695
13534
  }
13696
- /**
13697
- * Helper to generate scopes
13698
- * @param response
13699
- * @param request
13700
- * @returns
13701
- */
13702
- generateScopes(response, request) {
13703
- return response.scope
13704
- ? ScopeSet.fromString(response.scope)
13705
- : ScopeSet.fromString(request.scope);
13535
+ try {
13536
+ const requestStateObj = ProtocolUtils.parseRequestState(browserCrypto, state);
13537
+ return requestStateObj.libraryState.meta;
13538
+ }
13539
+ catch (e) {
13540
+ throw createClientAuthError(invalidState);
13541
+ }
13542
+ }
13543
+
13544
+ /*
13545
+ * Copyright (c) Microsoft Corporation. All rights reserved.
13546
+ * Licensed under the MIT License.
13547
+ */
13548
+ function deserializeResponse(responseString, responseLocation, logger) {
13549
+ // Deserialize hash fragment response parameters.
13550
+ const serverParams = getDeserializedResponse(responseString);
13551
+ if (!serverParams) {
13552
+ if (!stripLeadingHashOrQuery(responseString)) {
13553
+ // Hash or Query string is empty
13554
+ logger.error(`The request has returned to the redirectUri but a ${responseLocation} is not present. It's likely that the ${responseLocation} has been removed or the page has been redirected by code running on the redirectUri page.`);
13555
+ throw createBrowserAuthError(hashEmptyError);
13556
+ }
13557
+ else {
13558
+ logger.error(`A ${responseLocation} is present in the iframe but it does not contain known properties. It's likely that the ${responseLocation} has been replaced by code running on the redirectUri page.`);
13559
+ logger.errorPii(`The ${responseLocation} detected is: ${responseString}`);
13560
+ throw createBrowserAuthError(hashDoesNotContainKnownProperties);
13561
+ }
13562
+ }
13563
+ return serverParams;
13564
+ }
13565
+ /**
13566
+ * Returns the interaction type that the response object belongs to
13567
+ */
13568
+ function validateInteractionType(response, browserCrypto, interactionType) {
13569
+ if (!response.state) {
13570
+ throw createBrowserAuthError(noStateInHash);
13571
+ }
13572
+ const platformStateObj = extractBrowserRequestState(browserCrypto, response.state);
13573
+ if (!platformStateObj) {
13574
+ throw createBrowserAuthError(unableToParseState);
13575
+ }
13576
+ if (platformStateObj.interactionType !== interactionType) {
13577
+ throw createBrowserAuthError(stateInteractionTypeMismatch);
13578
+ }
13579
+ }
13580
+
13581
+ /*
13582
+ * Copyright (c) Microsoft Corporation. All rights reserved.
13583
+ * Licensed under the MIT License.
13584
+ */
13585
+ /**
13586
+ * Abstract class which defines operations for a browser interaction handling class.
13587
+ */
13588
+ class InteractionHandler {
13589
+ constructor(authCodeModule, storageImpl, authCodeRequest, logger, performanceClient) {
13590
+ this.authModule = authCodeModule;
13591
+ this.browserStorage = storageImpl;
13592
+ this.authCodeRequest = authCodeRequest;
13593
+ this.logger = logger;
13594
+ this.performanceClient = performanceClient;
13706
13595
  }
13707
13596
  /**
13708
- * If PoP token is requesred, records the PoP token if returned from the WAM, else generates one in the browser
13709
- * @param request
13710
- * @param response
13597
+ * Function to handle response parameters from hash.
13598
+ * @param locationHash
13711
13599
  */
13712
- async generatePopAccessToken(response, request) {
13713
- if (request.tokenType === AuthenticationScheme.POP &&
13714
- request.signPopToken) {
13715
- /**
13716
- * This code prioritizes SHR returned from the native layer. In case of error/SHR not calculated from WAM and the AT
13717
- * is still received, SHR is calculated locally
13718
- */
13719
- // Check if native layer returned an SHR token
13720
- if (response.shr) {
13721
- this.logger.trace("handleNativeServerResponse: SHR is enabled in native layer");
13722
- return response.shr;
13600
+ async handleCodeResponse(response, request) {
13601
+ this.performanceClient.addQueueMeasurement(PerformanceEvents.HandleCodeResponse, request.correlationId);
13602
+ let authCodeResponse;
13603
+ try {
13604
+ authCodeResponse = getAuthorizationCodePayload(response, request.state);
13605
+ }
13606
+ catch (e) {
13607
+ if (e instanceof ServerError &&
13608
+ e.subError === userCancelled) {
13609
+ // Translate server error caused by user closing native prompt to corresponding first class MSAL error
13610
+ throw createBrowserAuthError(userCancelled);
13723
13611
  }
13724
- // Generate SHR in msal js if WAM does not compute it when POP is enabled
13725
- const popTokenGenerator = new PopTokenGenerator(this.browserCrypto);
13726
- const shrParameters = {
13727
- resourceRequestMethod: request.resourceRequestMethod,
13728
- resourceRequestUri: request.resourceRequestUri,
13729
- shrClaims: request.shrClaims,
13730
- shrNonce: request.shrNonce,
13731
- };
13732
- /**
13733
- * KeyID must be present in the native request from when the PoP key was generated in order for
13734
- * PopTokenGenerator to query the full key for signing
13735
- */
13736
- if (!request.keyId) {
13737
- throw createClientAuthError(keyIdMissing);
13612
+ else {
13613
+ throw e;
13738
13614
  }
13739
- return popTokenGenerator.signPopToken(response.access_token, request.keyId, shrParameters);
13615
+ }
13616
+ return invokeAsync(this.handleCodeResponseFromServer.bind(this), PerformanceEvents.HandleCodeResponseFromServer, this.logger, this.performanceClient, request.correlationId)(authCodeResponse, request);
13617
+ }
13618
+ /**
13619
+ * Process auth code response from AAD
13620
+ * @param authCodeResponse
13621
+ * @param state
13622
+ * @param authority
13623
+ * @param networkModule
13624
+ * @returns
13625
+ */
13626
+ async handleCodeResponseFromServer(authCodeResponse, request, validateNonce = true) {
13627
+ this.performanceClient.addQueueMeasurement(PerformanceEvents.HandleCodeResponseFromServer, request.correlationId);
13628
+ this.logger.trace("InteractionHandler.handleCodeResponseFromServer called");
13629
+ // Assign code to request
13630
+ this.authCodeRequest.code = authCodeResponse.code;
13631
+ // Check for new cloud instance
13632
+ if (authCodeResponse.cloud_instance_host_name) {
13633
+ await invokeAsync(this.authModule.updateAuthority.bind(this.authModule), PerformanceEvents.UpdateTokenEndpointAuthority, this.logger, this.performanceClient, request.correlationId)(authCodeResponse.cloud_instance_host_name, request.correlationId);
13634
+ }
13635
+ // Nonce validation not needed when redirect not involved (e.g. hybrid spa, renewing token via rt)
13636
+ if (validateNonce) {
13637
+ // TODO: Assigning "response nonce" to "request nonce" is confusing. Refactor the function doing validation to accept request nonce directly
13638
+ authCodeResponse.nonce = request.nonce || undefined;
13639
+ }
13640
+ authCodeResponse.state = request.state;
13641
+ // Add CCS parameters if available
13642
+ if (authCodeResponse.client_info) {
13643
+ this.authCodeRequest.clientInfo = authCodeResponse.client_info;
13740
13644
  }
13741
13645
  else {
13742
- return response.access_token;
13646
+ const ccsCred = this.createCcsCredentials(request);
13647
+ if (ccsCred) {
13648
+ this.authCodeRequest.ccsCredential = ccsCred;
13649
+ }
13743
13650
  }
13651
+ // Acquire token with retrieved code.
13652
+ const tokenResponse = (await invokeAsync(this.authModule.acquireToken.bind(this.authModule), PerformanceEvents.AuthClientAcquireToken, this.logger, this.performanceClient, request.correlationId)(this.authCodeRequest, authCodeResponse));
13653
+ return tokenResponse;
13744
13654
  }
13745
13655
  /**
13746
- * Generates authentication result
13747
- * @param response
13748
- * @param request
13749
- * @param idTokenObj
13750
- * @param accountEntity
13751
- * @param authority
13752
- * @param reqTimestamp
13753
- * @returns
13656
+ * Build ccs creds if available
13754
13657
  */
13755
- async generateAuthenticationResult(response, request, idTokenClaims, accountEntity, authority, reqTimestamp) {
13756
- // Add Native Broker fields to Telemetry
13757
- const mats = this.addTelemetryFromNativeResponse(response);
13758
- // If scopes not returned in server response, use request scopes
13759
- const responseScopes = response.scope
13760
- ? ScopeSet.fromString(response.scope)
13761
- : ScopeSet.fromString(request.scope);
13762
- const accountProperties = response.account.properties || {};
13763
- const uid = accountProperties["UID"] ||
13764
- idTokenClaims.oid ||
13765
- idTokenClaims.sub ||
13766
- Constants.EMPTY_STRING;
13767
- const tid = accountProperties["TenantId"] ||
13768
- idTokenClaims.tid ||
13769
- Constants.EMPTY_STRING;
13770
- const accountInfo = updateAccountTenantProfileData(accountEntity.getAccountInfo(), undefined, // tenantProfile optional
13771
- idTokenClaims, response.id_token);
13772
- /**
13773
- * In pairwise broker flows, this check prevents the broker's native account id
13774
- * from being returned over the embedded app's account id.
13775
- */
13776
- if (accountInfo.nativeAccountId !== response.account.id) {
13777
- accountInfo.nativeAccountId = response.account.id;
13658
+ createCcsCredentials(request) {
13659
+ if (request.account) {
13660
+ return {
13661
+ credential: request.account.homeAccountId,
13662
+ type: CcsCredentialType.HOME_ACCOUNT_ID,
13663
+ };
13778
13664
  }
13779
- // generate PoP token as needed
13780
- const responseAccessToken = await this.generatePopAccessToken(response, request);
13781
- const tokenType = request.tokenType === AuthenticationScheme.POP
13782
- ? AuthenticationScheme.POP
13783
- : AuthenticationScheme.BEARER;
13784
- const result = {
13785
- authority: authority,
13786
- uniqueId: uid,
13787
- tenantId: tid,
13788
- scopes: responseScopes.asArray(),
13789
- account: accountInfo,
13790
- idToken: response.id_token,
13791
- idTokenClaims: idTokenClaims,
13792
- accessToken: responseAccessToken,
13793
- fromCache: mats ? this.isResponseFromCache(mats) : false,
13794
- // Request timestamp and NativeResponse expires_in are in seconds, converting to Date for AuthenticationResult
13795
- expiresOn: toDateFromSeconds(reqTimestamp + response.expires_in),
13796
- tokenType: tokenType,
13797
- correlationId: this.correlationId,
13798
- state: response.state,
13799
- fromNativeBroker: true,
13800
- };
13801
- return result;
13665
+ else if (request.loginHint) {
13666
+ return {
13667
+ credential: request.loginHint,
13668
+ type: CcsCredentialType.UPN,
13669
+ };
13670
+ }
13671
+ return null;
13802
13672
  }
13673
+ }
13674
+
13675
+ /*
13676
+ * Copyright (c) Microsoft Corporation. All rights reserved.
13677
+ * Licensed under the MIT License.
13678
+ */
13679
+ class SilentCacheClient extends StandardInteractionClient {
13803
13680
  /**
13804
- * cache the account entity in browser storage
13805
- * @param accountEntity
13681
+ * Returns unexpired tokens from the cache, if available
13682
+ * @param silentRequest
13806
13683
  */
13807
- async cacheAccount(accountEntity) {
13808
- // Store the account info and hence `nativeAccountId` in browser cache
13809
- await this.browserStorage.setAccount(accountEntity, this.correlationId);
13810
- // Remove any existing cached tokens for this account in browser storage
13811
- this.browserStorage.removeAccountContext(accountEntity).catch((e) => {
13812
- this.logger.error(`Error occurred while removing account context from browser storage. ${e}`);
13684
+ async acquireToken(silentRequest) {
13685
+ this.performanceClient.addQueueMeasurement(PerformanceEvents.SilentCacheClientAcquireToken, silentRequest.correlationId);
13686
+ // Telemetry manager only used to increment cacheHits here
13687
+ const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenSilent_silentFlow);
13688
+ const clientConfig = await invokeAsync(this.getClientConfiguration.bind(this), PerformanceEvents.StandardInteractionClientGetClientConfiguration, this.logger, this.performanceClient, this.correlationId)({
13689
+ serverTelemetryManager,
13690
+ requestAuthority: silentRequest.authority,
13691
+ requestAzureCloudOptions: silentRequest.azureCloudOptions,
13692
+ account: silentRequest.account,
13813
13693
  });
13694
+ const silentAuthClient = new SilentFlowClient(clientConfig, this.performanceClient);
13695
+ this.logger.verbose("Silent auth client created");
13696
+ try {
13697
+ const response = await invokeAsync(silentAuthClient.acquireCachedToken.bind(silentAuthClient), PerformanceEvents.SilentFlowClientAcquireCachedToken, this.logger, this.performanceClient, silentRequest.correlationId)(silentRequest);
13698
+ const authResponse = response[0];
13699
+ this.performanceClient.addFields({
13700
+ fromCache: true,
13701
+ }, silentRequest.correlationId);
13702
+ return authResponse;
13703
+ }
13704
+ catch (error) {
13705
+ if (error instanceof BrowserAuthError &&
13706
+ error.errorCode === cryptoKeyNotFound) {
13707
+ this.logger.verbose("Signing keypair for bound access token not found. Refreshing bound access token and generating a new crypto keypair.");
13708
+ }
13709
+ throw error;
13710
+ }
13814
13711
  }
13815
13712
  /**
13816
- * Stores the access_token and id_token in inmemory storage
13817
- * @param response
13818
- * @param request
13819
- * @param homeAccountIdentifier
13820
- * @param idTokenObj
13821
- * @param responseAccessToken
13822
- * @param tenantId
13823
- * @param reqTimestamp
13713
+ * API to silenty clear the browser cache.
13714
+ * @param logoutRequest
13824
13715
  */
13825
- cacheNativeTokens(response, request, homeAccountIdentifier, idTokenClaims, responseAccessToken, tenantId, reqTimestamp) {
13826
- const cachedIdToken = createIdTokenEntity(homeAccountIdentifier, request.authority, response.id_token || "", request.clientId, idTokenClaims.tid || "");
13827
- // cache accessToken in inmemory storage
13828
- const expiresIn = request.tokenType === AuthenticationScheme.POP
13829
- ? Constants.SHR_NONCE_VALIDITY
13830
- : (typeof response.expires_in === "string"
13831
- ? parseInt(response.expires_in, 10)
13832
- : response.expires_in) || 0;
13833
- const tokenExpirationSeconds = reqTimestamp + expiresIn;
13834
- const responseScopes = this.generateScopes(response, request);
13835
- const cachedAccessToken = createAccessTokenEntity(homeAccountIdentifier, request.authority, responseAccessToken, request.clientId, idTokenClaims.tid || tenantId, responseScopes.printScopes(), tokenExpirationSeconds, 0, base64Decode, undefined, request.tokenType, undefined, request.keyId);
13836
- const nativeCacheRecord = {
13837
- idToken: cachedIdToken,
13838
- accessToken: cachedAccessToken,
13839
- };
13840
- return this.nativeStorageManager.saveCacheRecord(nativeCacheRecord, this.correlationId, request.storeInCache);
13716
+ logout(logoutRequest) {
13717
+ this.logger.verbose("logoutRedirect called");
13718
+ const validLogoutRequest = this.initializeLogoutRequest(logoutRequest);
13719
+ return this.clearCacheOnLogout(validLogoutRequest?.account);
13841
13720
  }
13842
- addTelemetryFromNativeResponse(response) {
13843
- const mats = this.getMATSFromResponse(response);
13844
- if (!mats) {
13845
- return null;
13846
- }
13847
- this.performanceClient.addFields({
13848
- extensionId: this.nativeMessageHandler.getExtensionId(),
13721
+ }
13722
+
13723
+ /*
13724
+ * Copyright (c) Microsoft Corporation. All rights reserved.
13725
+ * Licensed under the MIT License.
13726
+ */
13727
+ class NativeInteractionClient extends BaseInteractionClient {
13728
+ constructor(config, browserStorage, browserCrypto, logger, eventHandler, navigationClient, apiId, performanceClient, provider, accountId, nativeStorageImpl, correlationId) {
13729
+ super(config, browserStorage, browserCrypto, logger, eventHandler, navigationClient, performanceClient, provider, correlationId);
13730
+ this.apiId = apiId;
13731
+ this.accountId = accountId;
13732
+ this.nativeMessageHandler = provider;
13733
+ this.nativeStorageManager = nativeStorageImpl;
13734
+ this.silentCacheClient = new SilentCacheClient(config, this.nativeStorageManager, browserCrypto, logger, eventHandler, navigationClient, performanceClient, provider, correlationId);
13735
+ const extensionName = this.nativeMessageHandler.getExtensionId() ===
13736
+ NativeConstants.PREFERRED_EXTENSION_ID
13737
+ ? "chrome"
13738
+ : this.nativeMessageHandler.getExtensionId()?.length
13739
+ ? "unknown"
13740
+ : undefined;
13741
+ this.skus = ServerTelemetryManager.makeExtraSkuString({
13742
+ libraryName: BrowserConstants.MSAL_SKU,
13743
+ libraryVersion: version,
13744
+ extensionName: extensionName,
13849
13745
  extensionVersion: this.nativeMessageHandler.getExtensionVersion(),
13850
- matsBrokerVersion: mats.broker_version,
13851
- matsAccountJoinOnStart: mats.account_join_on_start,
13852
- matsAccountJoinOnEnd: mats.account_join_on_end,
13853
- matsDeviceJoin: mats.device_join,
13854
- matsPromptBehavior: mats.prompt_behavior,
13855
- matsApiErrorCode: mats.api_error_code,
13856
- matsUiVisible: mats.ui_visible,
13857
- matsSilentCode: mats.silent_code,
13858
- matsSilentBiSubCode: mats.silent_bi_sub_code,
13859
- matsSilentMessage: mats.silent_message,
13860
- matsSilentStatus: mats.silent_status,
13861
- matsHttpStatus: mats.http_status,
13862
- matsHttpEventCount: mats.http_event_count,
13863
- }, this.correlationId);
13864
- return mats;
13746
+ });
13865
13747
  }
13866
13748
  /**
13867
- * Validates native platform response before processing
13868
- * @param response
13749
+ * Adds SKUs to request extra query parameters
13750
+ * @param request {NativeTokenRequest}
13751
+ * @private
13869
13752
  */
13870
- validateNativeResponse(response) {
13871
- if (response.hasOwnProperty("access_token") &&
13872
- response.hasOwnProperty("id_token") &&
13873
- response.hasOwnProperty("client_info") &&
13874
- response.hasOwnProperty("account") &&
13875
- response.hasOwnProperty("scope") &&
13876
- response.hasOwnProperty("expires_in")) {
13877
- return response;
13878
- }
13879
- else {
13880
- throw createAuthError(unexpectedError, "Response missing expected properties.");
13881
- }
13753
+ addRequestSKUs(request) {
13754
+ request.extraParameters = {
13755
+ ...request.extraParameters,
13756
+ [X_CLIENT_EXTRA_SKU]: this.skus,
13757
+ };
13882
13758
  }
13883
13759
  /**
13884
- * Gets MATS telemetry from native response
13885
- * @param response
13886
- * @returns
13760
+ * Acquire token from native platform via browser extension
13761
+ * @param request
13887
13762
  */
13888
- getMATSFromResponse(response) {
13889
- if (response.properties.MATS) {
13763
+ async acquireToken(request, cacheLookupPolicy) {
13764
+ this.performanceClient.addQueueMeasurement(PerformanceEvents.NativeInteractionClientAcquireToken, request.correlationId);
13765
+ this.logger.trace("NativeInteractionClient - acquireToken called.");
13766
+ // start the perf measurement
13767
+ const nativeATMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.NativeInteractionClientAcquireToken, request.correlationId);
13768
+ const reqTimestamp = nowSeconds();
13769
+ const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
13770
+ try {
13771
+ // initialize native request
13772
+ const nativeRequest = await this.initializeNativeRequest(request);
13773
+ // check if the tokens can be retrieved from internal cache
13890
13774
  try {
13891
- return JSON.parse(response.properties.MATS);
13775
+ const result = await this.acquireTokensFromCache(this.accountId, nativeRequest);
13776
+ nativeATMeasurement.end({
13777
+ success: true,
13778
+ isNativeBroker: false,
13779
+ fromCache: true,
13780
+ });
13781
+ return result;
13892
13782
  }
13893
13783
  catch (e) {
13894
- this.logger.error("NativeInteractionClient - Error parsing MATS telemetry, returning null instead");
13784
+ if (cacheLookupPolicy === CacheLookupPolicy.AccessToken) {
13785
+ this.logger.info("MSAL internal Cache does not contain tokens, return error as per cache policy");
13786
+ throw e;
13787
+ }
13788
+ // continue with a native call for any and all errors
13789
+ this.logger.info("MSAL internal Cache does not contain tokens, proceed to make a native call");
13895
13790
  }
13791
+ const { ...nativeTokenRequest } = nativeRequest;
13792
+ // fall back to native calls
13793
+ const messageBody = {
13794
+ method: NativeExtensionMethod.GetToken,
13795
+ request: nativeTokenRequest,
13796
+ };
13797
+ const response = await this.nativeMessageHandler.sendMessage(messageBody);
13798
+ const validatedResponse = this.validateNativeResponse(response);
13799
+ return await this.handleNativeResponse(validatedResponse, nativeRequest, reqTimestamp)
13800
+ .then((result) => {
13801
+ nativeATMeasurement.end({
13802
+ success: true,
13803
+ isNativeBroker: true,
13804
+ requestId: result.requestId,
13805
+ });
13806
+ serverTelemetryManager.clearNativeBrokerErrorCode();
13807
+ return result;
13808
+ })
13809
+ .catch((error) => {
13810
+ nativeATMeasurement.end({
13811
+ success: false,
13812
+ errorCode: error.errorCode,
13813
+ subErrorCode: error.subError,
13814
+ isNativeBroker: true,
13815
+ });
13816
+ throw error;
13817
+ });
13896
13818
  }
13897
- return null;
13898
- }
13899
- /**
13900
- * Returns whether or not response came from native cache
13901
- * @param response
13902
- * @returns
13903
- */
13904
- isResponseFromCache(mats) {
13905
- if (typeof mats.is_cached === "undefined") {
13906
- this.logger.verbose("NativeInteractionClient - MATS telemetry does not contain field indicating if response was served from cache. Returning false.");
13907
- return false;
13819
+ catch (e) {
13820
+ if (e instanceof NativeAuthError) {
13821
+ serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode);
13822
+ }
13823
+ throw e;
13908
13824
  }
13909
- return !!mats.is_cached;
13910
13825
  }
13911
13826
  /**
13912
- * Translates developer provided request object into NativeRequest object
13827
+ * Creates silent flow request
13913
13828
  * @param request
13829
+ * @param cachedAccount
13830
+ * @returns CommonSilentFlowRequest
13914
13831
  */
13915
- async initializeNativeRequest(request) {
13916
- this.logger.trace("NativeInteractionClient - initializeNativeRequest called");
13917
- const requestAuthority = request.authority || this.config.auth.authority;
13918
- if (request.account) {
13919
- // validate authority
13920
- await this.getDiscoveredAuthority({
13921
- requestAuthority,
13922
- requestAzureCloudOptions: request.azureCloudOptions,
13923
- account: request.account,
13924
- });
13925
- }
13926
- const canonicalAuthority = new UrlString(requestAuthority);
13927
- canonicalAuthority.validateAsUri();
13928
- // scopes are expected to be received by the native broker as "scope" and will be added to the request below. Other properties that should be dropped from the request to the native broker can be included in the object destructuring here.
13929
- const { scopes, ...remainingProperties } = request;
13930
- const scopeSet = new ScopeSet(scopes || []);
13931
- scopeSet.appendScopes(OIDC_DEFAULT_SCOPES);
13932
- const getPrompt = () => {
13933
- // If request is silent, prompt is always none
13934
- switch (this.apiId) {
13935
- case ApiId.ssoSilent:
13936
- case ApiId.acquireTokenSilent_silentFlow:
13937
- this.logger.trace("initializeNativeRequest: silent request sets prompt to none");
13938
- return PromptValue.NONE;
13939
- }
13940
- // Prompt not provided, request may proceed and native broker decides if it needs to prompt
13941
- if (!request.prompt) {
13942
- this.logger.trace("initializeNativeRequest: prompt was not provided");
13943
- return undefined;
13944
- }
13945
- // If request is interactive, check if prompt provided is allowed to go directly to native broker
13946
- switch (request.prompt) {
13947
- case PromptValue.NONE:
13948
- case PromptValue.CONSENT:
13949
- case PromptValue.LOGIN:
13950
- this.logger.trace("initializeNativeRequest: prompt is compatible with native flow");
13951
- return request.prompt;
13952
- default:
13953
- this.logger.trace(`initializeNativeRequest: prompt = ${request.prompt} is not compatible with native flow`);
13954
- throw createBrowserAuthError(nativePromptNotSupported);
13955
- }
13956
- };
13957
- const validatedRequest = {
13958
- ...remainingProperties,
13959
- accountId: this.accountId,
13960
- clientId: this.config.auth.clientId,
13961
- authority: canonicalAuthority.urlString,
13962
- scope: scopeSet.printScopes(),
13963
- redirectUri: this.getRedirectUri(request.redirectUri),
13964
- prompt: getPrompt(),
13832
+ createSilentCacheRequest(request, cachedAccount) {
13833
+ return {
13834
+ authority: request.authority,
13965
13835
  correlationId: this.correlationId,
13966
- tokenType: request.authenticationScheme,
13967
- windowTitleSubstring: document.title,
13968
- extraParameters: {
13969
- ...request.extraQueryParameters,
13970
- ...request.tokenQueryParameters,
13971
- },
13972
- extendedExpiryToken: false,
13973
- keyId: request.popKid,
13836
+ scopes: ScopeSet.fromString(request.scope).asArray(),
13837
+ account: cachedAccount,
13838
+ forceRefresh: false,
13974
13839
  };
13975
- // Check for PoP token requests: signPopToken should only be set to true if popKid is not set
13976
- if (validatedRequest.signPopToken && !!request.popKid) {
13977
- throw createBrowserAuthError(invalidPopTokenRequest);
13978
- }
13979
- this.handleExtraBrokerParams(validatedRequest);
13980
- validatedRequest.extraParameters =
13981
- validatedRequest.extraParameters || {};
13982
- validatedRequest.extraParameters.telemetry =
13983
- NativeConstants.MATS_TELEMETRY;
13984
- if (request.authenticationScheme === AuthenticationScheme.POP) {
13985
- // add POP request type
13986
- const shrParameters = {
13987
- resourceRequestUri: request.resourceRequestUri,
13988
- resourceRequestMethod: request.resourceRequestMethod,
13989
- shrClaims: request.shrClaims,
13990
- shrNonce: request.shrNonce,
13991
- };
13992
- const popTokenGenerator = new PopTokenGenerator(this.browserCrypto);
13993
- // generate reqCnf if not provided in the request
13994
- let reqCnfData;
13995
- if (!validatedRequest.keyId) {
13996
- const generatedReqCnfData = await invokeAsync(popTokenGenerator.generateCnf.bind(popTokenGenerator), PerformanceEvents.PopTokenGenerateCnf, this.logger, this.performanceClient, request.correlationId)(shrParameters, this.logger);
13997
- reqCnfData = generatedReqCnfData.reqCnfString;
13998
- validatedRequest.keyId = generatedReqCnfData.kid;
13999
- validatedRequest.signPopToken = true;
14000
- }
14001
- else {
14002
- reqCnfData = this.browserCrypto.base64UrlEncode(JSON.stringify({ kid: validatedRequest.keyId }));
14003
- validatedRequest.signPopToken = false;
14004
- }
14005
- // SPAs require whole string to be passed to broker
14006
- validatedRequest.reqCnf = reqCnfData;
14007
- }
14008
- this.addRequestSKUs(validatedRequest);
14009
- return validatedRequest;
14010
13840
  }
14011
13841
  /**
14012
- * Handles extra broker request parameters
14013
- * @param request {NativeTokenRequest}
14014
- * @private
13842
+ * Fetches the tokens from the cache if un-expired
13843
+ * @param nativeAccountId
13844
+ * @param request
13845
+ * @returns authenticationResult
14015
13846
  */
14016
- handleExtraBrokerParams(request) {
14017
- const hasExtraBrokerParams = request.extraParameters &&
14018
- request.extraParameters.hasOwnProperty(BROKER_CLIENT_ID) &&
14019
- request.extraParameters.hasOwnProperty(BROKER_REDIRECT_URI) &&
14020
- request.extraParameters.hasOwnProperty(CLIENT_ID);
14021
- if (!request.embeddedClientId && !hasExtraBrokerParams) {
14022
- return;
13847
+ async acquireTokensFromCache(nativeAccountId, request) {
13848
+ if (!nativeAccountId) {
13849
+ this.logger.warning("NativeInteractionClient:acquireTokensFromCache - No nativeAccountId provided");
13850
+ throw createClientAuthError(noAccountFound);
14023
13851
  }
14024
- let child_client_id = "";
14025
- const child_redirect_uri = request.redirectUri;
14026
- if (request.embeddedClientId) {
14027
- request.redirectUri = this.config.auth.redirectUri;
14028
- child_client_id = request.embeddedClientId;
13852
+ // fetch the account from browser cache
13853
+ const account = this.browserStorage.getBaseAccountInfo({
13854
+ nativeAccountId,
13855
+ });
13856
+ if (!account) {
13857
+ throw createClientAuthError(noAccountFound);
14029
13858
  }
14030
- else if (request.extraParameters) {
14031
- request.redirectUri =
14032
- request.extraParameters[BROKER_REDIRECT_URI];
14033
- child_client_id =
14034
- request.extraParameters[CLIENT_ID];
13859
+ // leverage silent flow for cached tokens retrieval
13860
+ try {
13861
+ const silentRequest = this.createSilentCacheRequest(request, account);
13862
+ const result = await this.silentCacheClient.acquireToken(silentRequest);
13863
+ const fullAccount = {
13864
+ ...account,
13865
+ idTokenClaims: result?.idTokenClaims,
13866
+ idToken: result?.idToken,
13867
+ };
13868
+ return {
13869
+ ...result,
13870
+ account: fullAccount,
13871
+ };
13872
+ }
13873
+ catch (e) {
13874
+ throw e;
14035
13875
  }
14036
- request.extraParameters = {
14037
- child_client_id,
14038
- child_redirect_uri,
14039
- };
14040
- this.performanceClient?.addFields({
14041
- embeddedClientId: child_client_id,
14042
- embeddedRedirectUri: child_redirect_uri,
14043
- }, request.correlationId);
14044
- }
14045
- }
14046
-
14047
- /*
14048
- * Copyright (c) Microsoft Corporation. All rights reserved.
14049
- * Licensed under the MIT License.
14050
- */
14051
- class NativeMessageHandler {
14052
- constructor(logger, handshakeTimeoutMs, performanceClient, extensionId) {
14053
- this.logger = logger;
14054
- this.handshakeTimeoutMs = handshakeTimeoutMs;
14055
- this.extensionId = extensionId;
14056
- this.resolvers = new Map(); // Used for non-handshake messages
14057
- this.handshakeResolvers = new Map(); // Used for handshake messages
14058
- this.messageChannel = new MessageChannel();
14059
- this.windowListener = this.onWindowMessage.bind(this); // Window event callback doesn't have access to 'this' unless it's bound
14060
- this.performanceClient = performanceClient;
14061
- this.handshakeEvent = performanceClient.startMeasurement(PerformanceEvents.NativeMessageHandlerHandshake);
14062
13876
  }
14063
13877
  /**
14064
- * Sends a given message to the extension and resolves with the extension response
14065
- * @param body
13878
+ * Acquires a token from native platform then redirects to the redirectUri instead of returning the response
13879
+ * @param {RedirectRequest} request
13880
+ * @param {InProgressPerformanceEvent} rootMeasurement
14066
13881
  */
14067
- async sendMessage(body) {
14068
- this.logger.trace("NativeMessageHandler - sendMessage called.");
14069
- const req = {
14070
- channel: NativeConstants.CHANNEL_ID,
14071
- extensionId: this.extensionId,
14072
- responseId: createNewGuid(),
14073
- body: body,
13882
+ async acquireTokenRedirect(request, rootMeasurement) {
13883
+ this.logger.trace("NativeInteractionClient - acquireTokenRedirect called.");
13884
+ const { ...remainingParameters } = request;
13885
+ delete remainingParameters.onRedirectNavigate;
13886
+ const nativeRequest = await this.initializeNativeRequest(remainingParameters);
13887
+ const messageBody = {
13888
+ method: NativeExtensionMethod.GetToken,
13889
+ request: nativeRequest,
14074
13890
  };
14075
- this.logger.trace("NativeMessageHandler - Sending request to browser extension");
14076
- this.logger.tracePii(`NativeMessageHandler - Sending request to browser extension: ${JSON.stringify(req)}`);
14077
- this.messageChannel.port1.postMessage(req);
14078
- return new Promise((resolve, reject) => {
14079
- this.resolvers.set(req.responseId, { resolve, reject });
14080
- });
13891
+ try {
13892
+ const response = await this.nativeMessageHandler.sendMessage(messageBody);
13893
+ this.validateNativeResponse(response);
13894
+ }
13895
+ catch (e) {
13896
+ // Only throw fatal errors here to allow application to fallback to regular redirect. Otherwise proceed and the error will be thrown in handleRedirectPromise
13897
+ if (e instanceof NativeAuthError) {
13898
+ const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
13899
+ serverTelemetryManager.setNativeBrokerErrorCode(e.errorCode);
13900
+ if (isFatalNativeAuthError(e)) {
13901
+ throw e;
13902
+ }
13903
+ }
13904
+ }
13905
+ this.browserStorage.setTemporaryCache(TemporaryCacheKeys.NATIVE_REQUEST, JSON.stringify(nativeRequest), true);
13906
+ const navigationOptions = {
13907
+ apiId: ApiId.acquireTokenRedirect,
13908
+ timeout: this.config.system.redirectNavigationTimeout,
13909
+ noHistory: false,
13910
+ };
13911
+ const redirectUri = this.config.auth.navigateToLoginRequestUrl
13912
+ ? window.location.href
13913
+ : this.getRedirectUri(request.redirectUri);
13914
+ rootMeasurement.end({ success: true });
13915
+ await this.navigationClient.navigateExternal(redirectUri, navigationOptions); // Need to treat this as external to ensure handleRedirectPromise is run again
14081
13916
  }
14082
13917
  /**
14083
- * Returns an instance of the MessageHandler that has successfully established a connection with an extension
14084
- * @param {Logger} logger
14085
- * @param {number} handshakeTimeoutMs
14086
- * @param {IPerformanceClient} performanceClient
14087
- * @param {ICrypto} crypto
13918
+ * If the previous page called native platform for a token using redirect APIs, send the same request again and return the response
13919
+ * @param performanceClient {IPerformanceClient?}
13920
+ * @param correlationId {string?} correlation identifier
14088
13921
  */
14089
- static async createProvider(logger, handshakeTimeoutMs, performanceClient) {
14090
- logger.trace("NativeMessageHandler - createProvider called.");
13922
+ async handleRedirectPromise(performanceClient, correlationId) {
13923
+ this.logger.trace("NativeInteractionClient - handleRedirectPromise called.");
13924
+ if (!this.browserStorage.isInteractionInProgress(true)) {
13925
+ this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
13926
+ return null;
13927
+ }
13928
+ // remove prompt from the request to prevent WAM from prompting twice
13929
+ const cachedRequest = this.browserStorage.getCachedNativeRequest();
13930
+ if (!cachedRequest) {
13931
+ this.logger.verbose("NativeInteractionClient - handleRedirectPromise called but there is no cached request, returning null.");
13932
+ if (performanceClient && correlationId) {
13933
+ performanceClient?.addFields({ errorCode: "no_cached_request" }, correlationId);
13934
+ }
13935
+ return null;
13936
+ }
13937
+ const { prompt, ...request } = cachedRequest;
13938
+ if (prompt) {
13939
+ this.logger.verbose("NativeInteractionClient - handleRedirectPromise called and prompt was included in the original request, removing prompt from cached request to prevent second interaction with native broker window.");
13940
+ }
13941
+ this.browserStorage.removeItem(this.browserStorage.generateCacheKey(TemporaryCacheKeys.NATIVE_REQUEST));
13942
+ const messageBody = {
13943
+ method: NativeExtensionMethod.GetToken,
13944
+ request: request,
13945
+ };
13946
+ const reqTimestamp = nowSeconds();
14091
13947
  try {
14092
- const preferredProvider = new NativeMessageHandler(logger, handshakeTimeoutMs, performanceClient, NativeConstants.PREFERRED_EXTENSION_ID);
14093
- await preferredProvider.sendHandshakeRequest();
14094
- return preferredProvider;
13948
+ this.logger.verbose("NativeInteractionClient - handleRedirectPromise sending message to native broker.");
13949
+ const response = await this.nativeMessageHandler.sendMessage(messageBody);
13950
+ this.validateNativeResponse(response);
13951
+ const result = this.handleNativeResponse(response, request, reqTimestamp);
13952
+ const res = await result;
13953
+ const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
13954
+ serverTelemetryManager.clearNativeBrokerErrorCode();
13955
+ return res;
14095
13956
  }
14096
13957
  catch (e) {
14097
- // If preferred extension fails for whatever reason, fallback to using any installed extension
14098
- const backupProvider = new NativeMessageHandler(logger, handshakeTimeoutMs, performanceClient);
14099
- await backupProvider.sendHandshakeRequest();
14100
- return backupProvider;
13958
+ throw e;
14101
13959
  }
14102
13960
  }
14103
13961
  /**
14104
- * Send handshake request helper.
13962
+ * Logout from native platform via browser extension
13963
+ * @param request
14105
13964
  */
14106
- async sendHandshakeRequest() {
14107
- this.logger.trace("NativeMessageHandler - sendHandshakeRequest called.");
14108
- // Register this event listener before sending handshake
14109
- window.addEventListener("message", this.windowListener, false); // false is important, because content script message processing should work first
14110
- const req = {
14111
- channel: NativeConstants.CHANNEL_ID,
14112
- extensionId: this.extensionId,
14113
- responseId: createNewGuid(),
14114
- body: {
14115
- method: NativeExtensionMethod.HandshakeRequest,
14116
- },
14117
- };
14118
- this.handshakeEvent.add({
14119
- extensionId: this.extensionId,
14120
- extensionHandshakeTimeoutMs: this.handshakeTimeoutMs,
14121
- });
14122
- this.messageChannel.port1.onmessage = (event) => {
14123
- this.onChannelMessage(event);
14124
- };
14125
- window.postMessage(req, window.origin, [this.messageChannel.port2]);
14126
- return new Promise((resolve, reject) => {
14127
- this.handshakeResolvers.set(req.responseId, { resolve, reject });
14128
- this.timeoutId = window.setTimeout(() => {
14129
- /*
14130
- * Throw an error if neither HandshakeResponse nor original Handshake request are received in a reasonable timeframe.
14131
- * This typically suggests an event handler stopped propagation of the Handshake request but did not respond to it on the MessageChannel port
14132
- */
14133
- window.removeEventListener("message", this.windowListener, false);
14134
- this.messageChannel.port1.close();
14135
- this.messageChannel.port2.close();
14136
- this.handshakeEvent.end({
14137
- extensionHandshakeTimedOut: true,
14138
- success: false,
14139
- });
14140
- reject(createBrowserAuthError(nativeHandshakeTimeout));
14141
- this.handshakeResolvers.delete(req.responseId);
14142
- }, this.handshakeTimeoutMs); // Use a reasonable timeout in milliseconds here
14143
- });
13965
+ logout() {
13966
+ this.logger.trace("NativeInteractionClient - logout called.");
13967
+ return Promise.reject("Logout not implemented yet");
14144
13968
  }
14145
13969
  /**
14146
- * Invoked when a message is posted to the window. If a handshake request is received it means the extension is not installed.
14147
- * @param event
13970
+ * Transform response from native platform into AuthenticationResult object which will be returned to the end user
13971
+ * @param response
13972
+ * @param request
13973
+ * @param reqTimestamp
14148
13974
  */
14149
- onWindowMessage(event) {
14150
- this.logger.trace("NativeMessageHandler - onWindowMessage called");
14151
- // We only accept messages from ourselves
14152
- if (event.source !== window) {
14153
- return;
14154
- }
14155
- const request = event.data;
14156
- if (!request.channel ||
14157
- request.channel !== NativeConstants.CHANNEL_ID) {
14158
- return;
14159
- }
14160
- if (request.extensionId && request.extensionId !== this.extensionId) {
14161
- return;
13975
+ async handleNativeResponse(response, request, reqTimestamp) {
13976
+ this.logger.trace("NativeInteractionClient - handleNativeResponse called.");
13977
+ // generate identifiers
13978
+ const idTokenClaims = extractTokenClaims(response.id_token, base64Decode);
13979
+ const homeAccountIdentifier = this.createHomeAccountIdentifier(response, idTokenClaims);
13980
+ const cachedhomeAccountId = this.browserStorage.getAccountInfoFilteredBy({
13981
+ nativeAccountId: request.accountId,
13982
+ })?.homeAccountId;
13983
+ // add exception for double brokering, please note this is temporary and will be fortified in future
13984
+ if (request.extraParameters?.child_client_id &&
13985
+ response.account.id !== request.accountId) {
13986
+ this.logger.info("handleNativeServerResponse: Double broker flow detected, ignoring accountId mismatch");
14162
13987
  }
14163
- if (request.body.method === NativeExtensionMethod.HandshakeRequest) {
14164
- const handshakeResolver = this.handshakeResolvers.get(request.responseId);
14165
- /*
14166
- * Filter out responses with no matched resolvers sooner to keep channel ports open while waiting for
14167
- * the proper response.
14168
- */
14169
- if (!handshakeResolver) {
14170
- this.logger.trace(`NativeMessageHandler.onWindowMessage - resolver can't be found for request ${request.responseId}`);
14171
- return;
14172
- }
14173
- // If we receive this message back it means no extension intercepted the request, meaning no extension supporting handshake protocol is installed
14174
- this.logger.verbose(request.extensionId
14175
- ? `Extension with id: ${request.extensionId} not installed`
14176
- : "No extension installed");
14177
- clearTimeout(this.timeoutId);
14178
- this.messageChannel.port1.close();
14179
- this.messageChannel.port2.close();
14180
- window.removeEventListener("message", this.windowListener, false);
14181
- this.handshakeEvent.end({
14182
- success: false,
14183
- extensionInstalled: false,
14184
- });
14185
- handshakeResolver.reject(createBrowserAuthError(nativeExtensionNotInstalled));
13988
+ else if (homeAccountIdentifier !== cachedhomeAccountId &&
13989
+ response.account.id !== request.accountId) {
13990
+ // User switch in native broker prompt is not supported. All users must first sign in through web flow to ensure server state is in sync
13991
+ throw createNativeAuthError(userSwitch);
14186
13992
  }
13993
+ // Get the preferred_cache domain for the given authority
13994
+ const authority = await this.getDiscoveredAuthority({
13995
+ requestAuthority: request.authority,
13996
+ });
13997
+ const baseAccount = buildAccountToCache(this.browserStorage, authority, homeAccountIdentifier, base64Decode, idTokenClaims, response.client_info, undefined, // environment
13998
+ idTokenClaims.tid, undefined, // auth code payload
13999
+ response.account.id, this.logger);
14000
+ // Ensure expires_in is in number format
14001
+ response.expires_in = Number(response.expires_in);
14002
+ // generate authenticationResult
14003
+ const result = await this.generateAuthenticationResult(response, request, idTokenClaims, baseAccount, authority.canonicalAuthority, reqTimestamp);
14004
+ // cache accounts and tokens in the appropriate storage
14005
+ await this.cacheAccount(baseAccount);
14006
+ await this.cacheNativeTokens(response, request, homeAccountIdentifier, idTokenClaims, response.access_token, result.tenantId, reqTimestamp);
14007
+ return result;
14187
14008
  }
14188
14009
  /**
14189
- * Invoked when a message is received from the extension on the MessageChannel port
14190
- * @param event
14010
+ * creates an homeAccountIdentifier for the account
14011
+ * @param response
14012
+ * @param idTokenObj
14013
+ * @returns
14191
14014
  */
14192
- onChannelMessage(event) {
14193
- this.logger.trace("NativeMessageHandler - onChannelMessage called.");
14194
- const request = event.data;
14195
- const resolver = this.resolvers.get(request.responseId);
14196
- const handshakeResolver = this.handshakeResolvers.get(request.responseId);
14197
- try {
14198
- const method = request.body.method;
14199
- if (method === NativeExtensionMethod.Response) {
14200
- if (!resolver) {
14201
- return;
14202
- }
14203
- const response = request.body.response;
14204
- this.logger.trace("NativeMessageHandler - Received response from browser extension");
14205
- this.logger.tracePii(`NativeMessageHandler - Received response from browser extension: ${JSON.stringify(response)}`);
14206
- if (response.status !== "Success") {
14207
- resolver.reject(createNativeAuthError(response.code, response.description, response.ext));
14208
- }
14209
- else if (response.result) {
14210
- if (response.result["code"] &&
14211
- response.result["description"]) {
14212
- resolver.reject(createNativeAuthError(response.result["code"], response.result["description"], response.result["ext"]));
14213
- }
14214
- else {
14215
- resolver.resolve(response.result);
14216
- }
14217
- }
14218
- else {
14219
- throw createAuthError(unexpectedError, "Event does not contain result.");
14220
- }
14221
- this.resolvers.delete(request.responseId);
14015
+ createHomeAccountIdentifier(response, idTokenClaims) {
14016
+ // Save account in browser storage
14017
+ const homeAccountIdentifier = AccountEntity.generateHomeAccountId(response.client_info || Constants.EMPTY_STRING, AuthorityType.Default, this.logger, this.browserCrypto, idTokenClaims);
14018
+ return homeAccountIdentifier;
14019
+ }
14020
+ /**
14021
+ * Helper to generate scopes
14022
+ * @param response
14023
+ * @param request
14024
+ * @returns
14025
+ */
14026
+ generateScopes(response, request) {
14027
+ return response.scope
14028
+ ? ScopeSet.fromString(response.scope)
14029
+ : ScopeSet.fromString(request.scope);
14030
+ }
14031
+ /**
14032
+ * If PoP token is requesred, records the PoP token if returned from the WAM, else generates one in the browser
14033
+ * @param request
14034
+ * @param response
14035
+ */
14036
+ async generatePopAccessToken(response, request) {
14037
+ if (request.tokenType === AuthenticationScheme.POP &&
14038
+ request.signPopToken) {
14039
+ /**
14040
+ * This code prioritizes SHR returned from the native layer. In case of error/SHR not calculated from WAM and the AT
14041
+ * is still received, SHR is calculated locally
14042
+ */
14043
+ // Check if native layer returned an SHR token
14044
+ if (response.shr) {
14045
+ this.logger.trace("handleNativeServerResponse: SHR is enabled in native layer");
14046
+ return response.shr;
14222
14047
  }
14223
- else if (method === NativeExtensionMethod.HandshakeResponse) {
14224
- if (!handshakeResolver) {
14225
- this.logger.trace(`NativeMessageHandler.onChannelMessage - resolver can't be found for request ${request.responseId}`);
14226
- return;
14227
- }
14228
- clearTimeout(this.timeoutId); // Clear setTimeout
14229
- window.removeEventListener("message", this.windowListener, false); // Remove 'No extension' listener
14230
- this.extensionId = request.extensionId;
14231
- this.extensionVersion = request.body.version;
14232
- this.logger.verbose(`NativeMessageHandler - Received HandshakeResponse from extension: ${this.extensionId}`);
14233
- this.handshakeEvent.end({
14234
- extensionInstalled: true,
14235
- success: true,
14236
- });
14237
- handshakeResolver.resolve();
14238
- this.handshakeResolvers.delete(request.responseId);
14048
+ // Generate SHR in msal js if WAM does not compute it when POP is enabled
14049
+ const popTokenGenerator = new PopTokenGenerator(this.browserCrypto);
14050
+ const shrParameters = {
14051
+ resourceRequestMethod: request.resourceRequestMethod,
14052
+ resourceRequestUri: request.resourceRequestUri,
14053
+ shrClaims: request.shrClaims,
14054
+ shrNonce: request.shrNonce,
14055
+ };
14056
+ /**
14057
+ * KeyID must be present in the native request from when the PoP key was generated in order for
14058
+ * PopTokenGenerator to query the full key for signing
14059
+ */
14060
+ if (!request.keyId) {
14061
+ throw createClientAuthError(keyIdMissing);
14239
14062
  }
14240
- // Do nothing if method is not Response or HandshakeResponse
14063
+ return popTokenGenerator.signPopToken(response.access_token, request.keyId, shrParameters);
14241
14064
  }
14242
- catch (err) {
14243
- this.logger.error("Error parsing response from WAM Extension");
14244
- this.logger.errorPii(`Error parsing response from WAM Extension: ${err}`);
14245
- this.logger.errorPii(`Unable to parse ${event}`);
14246
- if (resolver) {
14247
- resolver.reject(err);
14248
- }
14249
- else if (handshakeResolver) {
14250
- handshakeResolver.reject(err);
14251
- }
14065
+ else {
14066
+ return response.access_token;
14252
14067
  }
14253
14068
  }
14254
14069
  /**
14255
- * Returns the Id for the browser extension this handler is communicating with
14070
+ * Generates authentication result
14071
+ * @param response
14072
+ * @param request
14073
+ * @param idTokenObj
14074
+ * @param accountEntity
14075
+ * @param authority
14076
+ * @param reqTimestamp
14256
14077
  * @returns
14257
14078
  */
14258
- getExtensionId() {
14259
- return this.extensionId;
14079
+ async generateAuthenticationResult(response, request, idTokenClaims, accountEntity, authority, reqTimestamp) {
14080
+ // Add Native Broker fields to Telemetry
14081
+ const mats = this.addTelemetryFromNativeResponse(response);
14082
+ // If scopes not returned in server response, use request scopes
14083
+ const responseScopes = response.scope
14084
+ ? ScopeSet.fromString(response.scope)
14085
+ : ScopeSet.fromString(request.scope);
14086
+ const accountProperties = response.account.properties || {};
14087
+ const uid = accountProperties["UID"] ||
14088
+ idTokenClaims.oid ||
14089
+ idTokenClaims.sub ||
14090
+ Constants.EMPTY_STRING;
14091
+ const tid = accountProperties["TenantId"] ||
14092
+ idTokenClaims.tid ||
14093
+ Constants.EMPTY_STRING;
14094
+ const accountInfo = updateAccountTenantProfileData(accountEntity.getAccountInfo(), undefined, // tenantProfile optional
14095
+ idTokenClaims, response.id_token);
14096
+ /**
14097
+ * In pairwise broker flows, this check prevents the broker's native account id
14098
+ * from being returned over the embedded app's account id.
14099
+ */
14100
+ if (accountInfo.nativeAccountId !== response.account.id) {
14101
+ accountInfo.nativeAccountId = response.account.id;
14102
+ }
14103
+ // generate PoP token as needed
14104
+ const responseAccessToken = await this.generatePopAccessToken(response, request);
14105
+ const tokenType = request.tokenType === AuthenticationScheme.POP
14106
+ ? AuthenticationScheme.POP
14107
+ : AuthenticationScheme.BEARER;
14108
+ const result = {
14109
+ authority: authority,
14110
+ uniqueId: uid,
14111
+ tenantId: tid,
14112
+ scopes: responseScopes.asArray(),
14113
+ account: accountInfo,
14114
+ idToken: response.id_token,
14115
+ idTokenClaims: idTokenClaims,
14116
+ accessToken: responseAccessToken,
14117
+ fromCache: mats ? this.isResponseFromCache(mats) : false,
14118
+ // Request timestamp and NativeResponse expires_in are in seconds, converting to Date for AuthenticationResult
14119
+ expiresOn: toDateFromSeconds(reqTimestamp + response.expires_in),
14120
+ tokenType: tokenType,
14121
+ correlationId: this.correlationId,
14122
+ state: response.state,
14123
+ fromNativeBroker: true,
14124
+ };
14125
+ return result;
14260
14126
  }
14261
14127
  /**
14262
- * Returns the version for the browser extension this handler is communicating with
14263
- * @returns
14128
+ * cache the account entity in browser storage
14129
+ * @param accountEntity
14264
14130
  */
14265
- getExtensionVersion() {
14266
- return this.extensionVersion;
14131
+ async cacheAccount(accountEntity) {
14132
+ // Store the account info and hence `nativeAccountId` in browser cache
14133
+ await this.browserStorage.setAccount(accountEntity, this.correlationId);
14134
+ // Remove any existing cached tokens for this account in browser storage
14135
+ this.browserStorage.removeAccountContext(accountEntity).catch((e) => {
14136
+ this.logger.error(`Error occurred while removing account context from browser storage. ${e}`);
14137
+ });
14267
14138
  }
14268
14139
  /**
14269
- * Returns boolean indicating whether or not the request should attempt to use native broker
14270
- * @param logger
14271
- * @param config
14272
- * @param nativeExtensionProvider
14273
- * @param authenticationScheme
14140
+ * Stores the access_token and id_token in inmemory storage
14141
+ * @param response
14142
+ * @param request
14143
+ * @param homeAccountIdentifier
14144
+ * @param idTokenObj
14145
+ * @param responseAccessToken
14146
+ * @param tenantId
14147
+ * @param reqTimestamp
14274
14148
  */
14275
- static isPlatformBrokerAvailable(config, logger, nativeExtensionProvider, authenticationScheme) {
14276
- logger.trace("isPlatformBrokerAvailable called");
14277
- if (!config.system.allowPlatformBroker) {
14278
- logger.trace("isPlatformBrokerAvailable: allowPlatformBroker is not enabled, returning false");
14279
- // Developer disabled WAM
14280
- return false;
14149
+ cacheNativeTokens(response, request, homeAccountIdentifier, idTokenClaims, responseAccessToken, tenantId, reqTimestamp) {
14150
+ const cachedIdToken = createIdTokenEntity(homeAccountIdentifier, request.authority, response.id_token || "", request.clientId, idTokenClaims.tid || "");
14151
+ // cache accessToken in inmemory storage
14152
+ const expiresIn = request.tokenType === AuthenticationScheme.POP
14153
+ ? Constants.SHR_NONCE_VALIDITY
14154
+ : (typeof response.expires_in === "string"
14155
+ ? parseInt(response.expires_in, 10)
14156
+ : response.expires_in) || 0;
14157
+ const tokenExpirationSeconds = reqTimestamp + expiresIn;
14158
+ const responseScopes = this.generateScopes(response, request);
14159
+ const cachedAccessToken = createAccessTokenEntity(homeAccountIdentifier, request.authority, responseAccessToken, request.clientId, idTokenClaims.tid || tenantId, responseScopes.printScopes(), tokenExpirationSeconds, 0, base64Decode, undefined, request.tokenType, undefined, request.keyId);
14160
+ const nativeCacheRecord = {
14161
+ idToken: cachedIdToken,
14162
+ accessToken: cachedAccessToken,
14163
+ };
14164
+ return this.nativeStorageManager.saveCacheRecord(nativeCacheRecord, this.correlationId, request.storeInCache);
14165
+ }
14166
+ addTelemetryFromNativeResponse(response) {
14167
+ const mats = this.getMATSFromResponse(response);
14168
+ if (!mats) {
14169
+ return null;
14281
14170
  }
14282
- if (!nativeExtensionProvider) {
14283
- logger.trace("isPlatformBrokerAvailable: Platform extension provider is not initialized, returning false");
14284
- // Extension is not available
14285
- return false;
14171
+ this.performanceClient.addFields({
14172
+ extensionId: this.nativeMessageHandler.getExtensionId(),
14173
+ extensionVersion: this.nativeMessageHandler.getExtensionVersion(),
14174
+ matsBrokerVersion: mats.broker_version,
14175
+ matsAccountJoinOnStart: mats.account_join_on_start,
14176
+ matsAccountJoinOnEnd: mats.account_join_on_end,
14177
+ matsDeviceJoin: mats.device_join,
14178
+ matsPromptBehavior: mats.prompt_behavior,
14179
+ matsApiErrorCode: mats.api_error_code,
14180
+ matsUiVisible: mats.ui_visible,
14181
+ matsSilentCode: mats.silent_code,
14182
+ matsSilentBiSubCode: mats.silent_bi_sub_code,
14183
+ matsSilentMessage: mats.silent_message,
14184
+ matsSilentStatus: mats.silent_status,
14185
+ matsHttpStatus: mats.http_status,
14186
+ matsHttpEventCount: mats.http_event_count,
14187
+ }, this.correlationId);
14188
+ return mats;
14189
+ }
14190
+ /**
14191
+ * Validates native platform response before processing
14192
+ * @param response
14193
+ */
14194
+ validateNativeResponse(response) {
14195
+ if (response.hasOwnProperty("access_token") &&
14196
+ response.hasOwnProperty("id_token") &&
14197
+ response.hasOwnProperty("client_info") &&
14198
+ response.hasOwnProperty("account") &&
14199
+ response.hasOwnProperty("scope") &&
14200
+ response.hasOwnProperty("expires_in")) {
14201
+ return response;
14286
14202
  }
14287
- if (authenticationScheme) {
14288
- switch (authenticationScheme) {
14289
- case AuthenticationScheme.BEARER:
14290
- case AuthenticationScheme.POP:
14291
- logger.trace("isPlatformBrokerAvailable: authenticationScheme is supported, returning true");
14292
- return true;
14293
- default:
14294
- logger.trace("isPlatformBrokerAvailable: authenticationScheme is not supported, returning false");
14295
- return false;
14296
- }
14203
+ else {
14204
+ throw createAuthError(unexpectedError, "Response missing expected properties.");
14297
14205
  }
14298
- return true;
14299
- }
14300
- }
14301
-
14302
- /*
14303
- * Copyright (c) Microsoft Corporation. All rights reserved.
14304
- * Licensed under the MIT License.
14305
- */
14306
- /**
14307
- * Abstract class which defines operations for a browser interaction handling class.
14308
- */
14309
- class InteractionHandler {
14310
- constructor(authCodeModule, storageImpl, authCodeRequest, logger, performanceClient) {
14311
- this.authModule = authCodeModule;
14312
- this.browserStorage = storageImpl;
14313
- this.authCodeRequest = authCodeRequest;
14314
- this.logger = logger;
14315
- this.performanceClient = performanceClient;
14316
14206
  }
14317
14207
  /**
14318
- * Function to handle response parameters from hash.
14319
- * @param locationHash
14208
+ * Gets MATS telemetry from native response
14209
+ * @param response
14210
+ * @returns
14320
14211
  */
14321
- async handleCodeResponse(response, request) {
14322
- this.performanceClient.addQueueMeasurement(PerformanceEvents.HandleCodeResponse, request.correlationId);
14323
- let authCodeResponse;
14324
- try {
14325
- authCodeResponse = getAuthorizationCodePayload(response, request.state);
14326
- }
14327
- catch (e) {
14328
- if (e instanceof ServerError &&
14329
- e.subError === userCancelled) {
14330
- // Translate server error caused by user closing native prompt to corresponding first class MSAL error
14331
- throw createBrowserAuthError(userCancelled);
14212
+ getMATSFromResponse(response) {
14213
+ if (response.properties.MATS) {
14214
+ try {
14215
+ return JSON.parse(response.properties.MATS);
14332
14216
  }
14333
- else {
14334
- throw e;
14217
+ catch (e) {
14218
+ this.logger.error("NativeInteractionClient - Error parsing MATS telemetry, returning null instead");
14335
14219
  }
14336
14220
  }
14337
- return invokeAsync(this.handleCodeResponseFromServer.bind(this), PerformanceEvents.HandleCodeResponseFromServer, this.logger, this.performanceClient, request.correlationId)(authCodeResponse, request);
14221
+ return null;
14338
14222
  }
14339
14223
  /**
14340
- * Process auth code response from AAD
14341
- * @param authCodeResponse
14342
- * @param state
14343
- * @param authority
14344
- * @param networkModule
14224
+ * Returns whether or not response came from native cache
14225
+ * @param response
14345
14226
  * @returns
14346
14227
  */
14347
- async handleCodeResponseFromServer(authCodeResponse, request, validateNonce = true) {
14348
- this.performanceClient.addQueueMeasurement(PerformanceEvents.HandleCodeResponseFromServer, request.correlationId);
14349
- this.logger.trace("InteractionHandler.handleCodeResponseFromServer called");
14350
- // Assign code to request
14351
- this.authCodeRequest.code = authCodeResponse.code;
14352
- // Check for new cloud instance
14353
- if (authCodeResponse.cloud_instance_host_name) {
14354
- await invokeAsync(this.authModule.updateAuthority.bind(this.authModule), PerformanceEvents.UpdateTokenEndpointAuthority, this.logger, this.performanceClient, request.correlationId)(authCodeResponse.cloud_instance_host_name, request.correlationId);
14355
- }
14356
- // Nonce validation not needed when redirect not involved (e.g. hybrid spa, renewing token via rt)
14357
- if (validateNonce) {
14358
- // TODO: Assigning "response nonce" to "request nonce" is confusing. Refactor the function doing validation to accept request nonce directly
14359
- authCodeResponse.nonce = request.nonce || undefined;
14360
- }
14361
- authCodeResponse.state = request.state;
14362
- // Add CCS parameters if available
14363
- if (authCodeResponse.client_info) {
14364
- this.authCodeRequest.clientInfo = authCodeResponse.client_info;
14365
- }
14366
- else {
14367
- const ccsCred = this.createCcsCredentials(request);
14368
- if (ccsCred) {
14369
- this.authCodeRequest.ccsCredential = ccsCred;
14370
- }
14228
+ isResponseFromCache(mats) {
14229
+ if (typeof mats.is_cached === "undefined") {
14230
+ this.logger.verbose("NativeInteractionClient - MATS telemetry does not contain field indicating if response was served from cache. Returning false.");
14231
+ return false;
14371
14232
  }
14372
- // Acquire token with retrieved code.
14373
- const tokenResponse = (await invokeAsync(this.authModule.acquireToken.bind(this.authModule), PerformanceEvents.AuthClientAcquireToken, this.logger, this.performanceClient, request.correlationId)(this.authCodeRequest, authCodeResponse));
14374
- return tokenResponse;
14233
+ return !!mats.is_cached;
14375
14234
  }
14376
14235
  /**
14377
- * Build ccs creds if available
14236
+ * Translates developer provided request object into NativeRequest object
14237
+ * @param request
14378
14238
  */
14379
- createCcsCredentials(request) {
14239
+ async initializeNativeRequest(request) {
14240
+ this.logger.trace("NativeInteractionClient - initializeNativeRequest called");
14241
+ const requestAuthority = request.authority || this.config.auth.authority;
14380
14242
  if (request.account) {
14381
- return {
14382
- credential: request.account.homeAccountId,
14383
- type: CcsCredentialType.HOME_ACCOUNT_ID,
14384
- };
14243
+ // validate authority
14244
+ await this.getDiscoveredAuthority({
14245
+ requestAuthority,
14246
+ requestAzureCloudOptions: request.azureCloudOptions,
14247
+ account: request.account,
14248
+ });
14385
14249
  }
14386
- else if (request.loginHint) {
14387
- return {
14388
- credential: request.loginHint,
14389
- type: CcsCredentialType.UPN,
14250
+ const canonicalAuthority = new UrlString(requestAuthority);
14251
+ canonicalAuthority.validateAsUri();
14252
+ // scopes are expected to be received by the native broker as "scope" and will be added to the request below. Other properties that should be dropped from the request to the native broker can be included in the object destructuring here.
14253
+ const { scopes, ...remainingProperties } = request;
14254
+ const scopeSet = new ScopeSet(scopes || []);
14255
+ scopeSet.appendScopes(OIDC_DEFAULT_SCOPES);
14256
+ const getPrompt = () => {
14257
+ // If request is silent, prompt is always none
14258
+ switch (this.apiId) {
14259
+ case ApiId.ssoSilent:
14260
+ case ApiId.acquireTokenSilent_silentFlow:
14261
+ this.logger.trace("initializeNativeRequest: silent request sets prompt to none");
14262
+ return PromptValue.NONE;
14263
+ }
14264
+ // Prompt not provided, request may proceed and native broker decides if it needs to prompt
14265
+ if (!request.prompt) {
14266
+ this.logger.trace("initializeNativeRequest: prompt was not provided");
14267
+ return undefined;
14268
+ }
14269
+ // If request is interactive, check if prompt provided is allowed to go directly to native broker
14270
+ switch (request.prompt) {
14271
+ case PromptValue.NONE:
14272
+ case PromptValue.CONSENT:
14273
+ case PromptValue.LOGIN:
14274
+ this.logger.trace("initializeNativeRequest: prompt is compatible with native flow");
14275
+ return request.prompt;
14276
+ default:
14277
+ this.logger.trace(`initializeNativeRequest: prompt = ${request.prompt} is not compatible with native flow`);
14278
+ throw createBrowserAuthError(nativePromptNotSupported);
14279
+ }
14280
+ };
14281
+ const validatedRequest = {
14282
+ ...remainingProperties,
14283
+ accountId: this.accountId,
14284
+ clientId: this.config.auth.clientId,
14285
+ authority: canonicalAuthority.urlString,
14286
+ scope: scopeSet.printScopes(),
14287
+ redirectUri: this.getRedirectUri(request.redirectUri),
14288
+ prompt: getPrompt(),
14289
+ correlationId: this.correlationId,
14290
+ tokenType: request.authenticationScheme,
14291
+ windowTitleSubstring: document.title,
14292
+ extraParameters: {
14293
+ ...request.extraQueryParameters,
14294
+ ...request.tokenQueryParameters,
14295
+ },
14296
+ extendedExpiryToken: false,
14297
+ keyId: request.popKid,
14298
+ };
14299
+ // Check for PoP token requests: signPopToken should only be set to true if popKid is not set
14300
+ if (validatedRequest.signPopToken && !!request.popKid) {
14301
+ throw createBrowserAuthError(invalidPopTokenRequest);
14302
+ }
14303
+ this.handleExtraBrokerParams(validatedRequest);
14304
+ validatedRequest.extraParameters =
14305
+ validatedRequest.extraParameters || {};
14306
+ validatedRequest.extraParameters.telemetry =
14307
+ NativeConstants.MATS_TELEMETRY;
14308
+ if (request.authenticationScheme === AuthenticationScheme.POP) {
14309
+ // add POP request type
14310
+ const shrParameters = {
14311
+ resourceRequestUri: request.resourceRequestUri,
14312
+ resourceRequestMethod: request.resourceRequestMethod,
14313
+ shrClaims: request.shrClaims,
14314
+ shrNonce: request.shrNonce,
14390
14315
  };
14316
+ const popTokenGenerator = new PopTokenGenerator(this.browserCrypto);
14317
+ // generate reqCnf if not provided in the request
14318
+ let reqCnfData;
14319
+ if (!validatedRequest.keyId) {
14320
+ const generatedReqCnfData = await invokeAsync(popTokenGenerator.generateCnf.bind(popTokenGenerator), PerformanceEvents.PopTokenGenerateCnf, this.logger, this.performanceClient, request.correlationId)(shrParameters, this.logger);
14321
+ reqCnfData = generatedReqCnfData.reqCnfString;
14322
+ validatedRequest.keyId = generatedReqCnfData.kid;
14323
+ validatedRequest.signPopToken = true;
14324
+ }
14325
+ else {
14326
+ reqCnfData = this.browserCrypto.base64UrlEncode(JSON.stringify({ kid: validatedRequest.keyId }));
14327
+ validatedRequest.signPopToken = false;
14328
+ }
14329
+ // SPAs require whole string to be passed to broker
14330
+ validatedRequest.reqCnf = reqCnfData;
14391
14331
  }
14392
- return null;
14332
+ this.addRequestSKUs(validatedRequest);
14333
+ return validatedRequest;
14393
14334
  }
14394
- }
14395
-
14396
- /*
14397
- * Copyright (c) Microsoft Corporation. All rights reserved.
14398
- * Licensed under the MIT License.
14399
- */
14400
- function deserializeResponse(responseString, responseLocation, logger) {
14401
- // Deserialize hash fragment response parameters.
14402
- const serverParams = getDeserializedResponse(responseString);
14403
- if (!serverParams) {
14404
- if (!stripLeadingHashOrQuery(responseString)) {
14405
- // Hash or Query string is empty
14406
- logger.error(`The request has returned to the redirectUri but a ${responseLocation} is not present. It's likely that the ${responseLocation} has been removed or the page has been redirected by code running on the redirectUri page.`);
14407
- throw createBrowserAuthError(hashEmptyError);
14335
+ /**
14336
+ * Handles extra broker request parameters
14337
+ * @param request {NativeTokenRequest}
14338
+ * @private
14339
+ */
14340
+ handleExtraBrokerParams(request) {
14341
+ const hasExtraBrokerParams = request.extraParameters &&
14342
+ request.extraParameters.hasOwnProperty(BROKER_CLIENT_ID) &&
14343
+ request.extraParameters.hasOwnProperty(BROKER_REDIRECT_URI) &&
14344
+ request.extraParameters.hasOwnProperty(CLIENT_ID);
14345
+ if (!request.embeddedClientId && !hasExtraBrokerParams) {
14346
+ return;
14408
14347
  }
14409
- else {
14410
- logger.error(`A ${responseLocation} is present in the iframe but it does not contain known properties. It's likely that the ${responseLocation} has been replaced by code running on the redirectUri page.`);
14411
- logger.errorPii(`The ${responseLocation} detected is: ${responseString}`);
14412
- throw createBrowserAuthError(hashDoesNotContainKnownProperties);
14348
+ let child_client_id = "";
14349
+ const child_redirect_uri = request.redirectUri;
14350
+ if (request.embeddedClientId) {
14351
+ request.redirectUri = this.config.auth.redirectUri;
14352
+ child_client_id = request.embeddedClientId;
14413
14353
  }
14414
- }
14415
- return serverParams;
14416
- }
14417
- /**
14418
- * Returns the interaction type that the response object belongs to
14419
- */
14420
- function validateInteractionType(response, browserCrypto, interactionType) {
14421
- if (!response.state) {
14422
- throw createBrowserAuthError(noStateInHash);
14423
- }
14424
- const platformStateObj = extractBrowserRequestState(browserCrypto, response.state);
14425
- if (!platformStateObj) {
14426
- throw createBrowserAuthError(unableToParseState);
14427
- }
14428
- if (platformStateObj.interactionType !== interactionType) {
14429
- throw createBrowserAuthError(stateInteractionTypeMismatch);
14354
+ else if (request.extraParameters) {
14355
+ request.redirectUri =
14356
+ request.extraParameters[BROKER_REDIRECT_URI];
14357
+ child_client_id =
14358
+ request.extraParameters[CLIENT_ID];
14359
+ }
14360
+ request.extraParameters = {
14361
+ child_client_id,
14362
+ child_redirect_uri,
14363
+ };
14364
+ this.performanceClient?.addFields({
14365
+ embeddedClientId: child_client_id,
14366
+ embeddedRedirectUri: child_redirect_uri,
14367
+ }, request.correlationId);
14430
14368
  }
14431
14369
  }
14432
14370
 
@@ -14490,9 +14428,147 @@ async function getAuthCodeRequestUrl(config, authority, request, logger, perform
14490
14428
  throw createClientConfigurationError(pkceParamsMissing);
14491
14429
  }
14492
14430
  const parameters = await invokeAsync(getStandardParameters, PerformanceEvents.GetStandardParams, logger, performanceClient, request.correlationId)(config, authority, request, logger, performanceClient);
14493
- addResponseTypeCode(parameters);
14431
+ addResponseType(parameters, OAuthResponseType.CODE);
14494
14432
  addCodeChallengeParams(parameters, request.codeChallenge, Constants.S256_CODE_CHALLENGE_METHOD);
14433
+ addExtraQueryParameters(parameters, request.extraQueryParameters || {});
14495
14434
  return getAuthorizeUrl(authority, parameters);
14435
+ }
14436
+ /**
14437
+ * Gets the form that will be posted to /authorize with request parameters when using EAR
14438
+ */
14439
+ async function getEARForm(frame, config, authority, request, logger, performanceClient) {
14440
+ if (!request.earJwk) {
14441
+ throw createBrowserAuthError(earJwkEmpty);
14442
+ }
14443
+ const parameters = await getStandardParameters(config, authority, request, logger, performanceClient);
14444
+ addResponseType(parameters, OAuthResponseType.IDTOKEN_TOKEN_REFRESHTOKEN);
14445
+ addEARParameters(parameters, request.earJwk);
14446
+ const queryParams = new Map();
14447
+ addExtraQueryParameters(queryParams, request.extraQueryParameters || {});
14448
+ const url = getAuthorizeUrl(authority, queryParams);
14449
+ return createForm(frame, url, parameters);
14450
+ }
14451
+ /**
14452
+ * Creates form element in the provided document with auth parameters in the post body
14453
+ * @param frame
14454
+ * @param authorizeUrl
14455
+ * @param parameters
14456
+ * @returns
14457
+ */
14458
+ function createForm(frame, authorizeUrl, parameters) {
14459
+ const form = frame.createElement("form");
14460
+ form.method = "post";
14461
+ form.action = authorizeUrl;
14462
+ parameters.forEach((value, key) => {
14463
+ const param = frame.createElement("input");
14464
+ param.hidden = true;
14465
+ param.name = key;
14466
+ param.value = value;
14467
+ form.appendChild(param);
14468
+ });
14469
+ frame.body.appendChild(form);
14470
+ return form;
14471
+ }
14472
+ /**
14473
+ * Response handler when server returns accountId on the /authorize request
14474
+ * @param request
14475
+ * @param accountId
14476
+ * @param apiId
14477
+ * @param config
14478
+ * @param browserStorage
14479
+ * @param nativeStorage
14480
+ * @param eventHandler
14481
+ * @param logger
14482
+ * @param performanceClient
14483
+ * @param nativeMessageHandler
14484
+ * @returns
14485
+ */
14486
+ async function handleResponsePlatformBroker(request, accountId, apiId, config, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler) {
14487
+ if (!nativeMessageHandler) {
14488
+ throw createBrowserAuthError(nativeConnectionNotEstablished);
14489
+ }
14490
+ const browserCrypto = new CryptoOps(logger, performanceClient);
14491
+ const nativeInteractionClient = new NativeInteractionClient(config, browserStorage, browserCrypto, logger, eventHandler, config.system.navigationClient, apiId, performanceClient, nativeMessageHandler, accountId, nativeStorage, request.correlationId);
14492
+ const { userRequestState } = ProtocolUtils.parseRequestState(browserCrypto, request.state);
14493
+ return invokeAsync(nativeInteractionClient.acquireToken.bind(nativeInteractionClient), PerformanceEvents.NativeInteractionClientAcquireToken, logger, performanceClient, request.correlationId)({
14494
+ ...request,
14495
+ state: userRequestState,
14496
+ prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
14497
+ });
14498
+ }
14499
+ /**
14500
+ * Response handler when server returns code on the /authorize request
14501
+ * @param request
14502
+ * @param response
14503
+ * @param codeVerifier
14504
+ * @param authClient
14505
+ * @param browserStorage
14506
+ * @param logger
14507
+ * @param performanceClient
14508
+ * @returns
14509
+ */
14510
+ async function handleResponseCode(request, response, codeVerifier, apiId, config, authClient, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler) {
14511
+ // Remove throttle if it exists
14512
+ ThrottlingUtils.removeThrottle(browserStorage, config.auth.clientId, request);
14513
+ if (response.accountId) {
14514
+ return invokeAsync(handleResponsePlatformBroker, PerformanceEvents.HandleResponsePlatformBroker, logger, performanceClient, request.correlationId)(request, response.accountId, apiId, config, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler);
14515
+ }
14516
+ const authCodeRequest = {
14517
+ ...request,
14518
+ code: response.code || "",
14519
+ codeVerifier: codeVerifier,
14520
+ };
14521
+ // Create popup interaction handler.
14522
+ const interactionHandler = new InteractionHandler(authClient, browserStorage, authCodeRequest, logger, performanceClient);
14523
+ // Handle response from hash string.
14524
+ const result = await invokeAsync(interactionHandler.handleCodeResponse.bind(interactionHandler), PerformanceEvents.HandleCodeResponse, logger, performanceClient, request.correlationId)(response, request);
14525
+ return result;
14526
+ }
14527
+ /**
14528
+ * Response handler when server returns ear_jwe on the /authorize request
14529
+ * @param request
14530
+ * @param response
14531
+ * @param apiId
14532
+ * @param config
14533
+ * @param authority
14534
+ * @param browserStorage
14535
+ * @param nativeStorage
14536
+ * @param eventHandler
14537
+ * @param logger
14538
+ * @param performanceClient
14539
+ * @param nativeMessageHandler
14540
+ * @returns
14541
+ */
14542
+ async function handleResponseEAR(request, response, apiId, config, authority, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler) {
14543
+ // Remove throttle if it exists
14544
+ ThrottlingUtils.removeThrottle(browserStorage, config.auth.clientId, request);
14545
+ // Validate state & check response for errors
14546
+ validateAuthorizationResponse(response, request.state);
14547
+ if (!response.ear_jwe) {
14548
+ throw createBrowserAuthError(earJweEmpty);
14549
+ }
14550
+ if (!request.earJwk) {
14551
+ throw createBrowserAuthError(earJwkEmpty);
14552
+ }
14553
+ const decryptedData = JSON.parse(await invokeAsync(decryptEarResponse, PerformanceEvents.DecryptEarResponse, logger, performanceClient, request.correlationId)(request.earJwk, response.ear_jwe));
14554
+ if (decryptedData.accountId) {
14555
+ return invokeAsync(handleResponsePlatformBroker, PerformanceEvents.HandleResponsePlatformBroker, logger, performanceClient, request.correlationId)(request, decryptedData.accountId, apiId, config, browserStorage, nativeStorage, eventHandler, logger, performanceClient, nativeMessageHandler);
14556
+ }
14557
+ const responseHandler = new ResponseHandler(config.auth.clientId, browserStorage, new CryptoOps(logger, performanceClient), logger, null, null, performanceClient);
14558
+ // Validate response. This function throws a server error if an error is returned by the server.
14559
+ responseHandler.validateTokenResponse(decryptedData);
14560
+ // Temporary until response handler is refactored to be more flow agnostic.
14561
+ const additionalData = {
14562
+ code: "",
14563
+ state: request.state,
14564
+ nonce: request.nonce,
14565
+ client_info: decryptedData.client_info,
14566
+ cloud_graph_host_name: decryptedData.cloud_graph_host_name,
14567
+ cloud_instance_host_name: decryptedData.cloud_instance_host_name,
14568
+ cloud_instance_name: decryptedData.cloud_instance_name,
14569
+ msgraph_host: decryptedData.msgraph_host,
14570
+ };
14571
+ return (await invokeAsync(responseHandler.handleServerTokenResponse.bind(responseHandler), PerformanceEvents.HandleServerTokenResponse, logger, performanceClient, request.correlationId)(decryptedData, authority, nowSeconds(), request, additionalData, undefined, undefined, undefined, undefined));
14496
14572
  }
14497
14573
 
14498
14574
  /*
@@ -14560,6 +14636,7 @@ class PopupClient extends StandardInteractionClient {
14560
14636
  // Properly sets this reference for the unload event.
14561
14637
  this.unloadWindow = this.unloadWindow.bind(this);
14562
14638
  this.nativeStorage = nativeStorageImpl;
14639
+ this.eventHandler = eventHandler;
14563
14640
  }
14564
14641
  /**
14565
14642
  * Acquires tokens by opening a popup window to the /authorize endpoint of the authority
@@ -14635,11 +14712,7 @@ class PopupClient extends StandardInteractionClient {
14635
14712
  */
14636
14713
  async acquireTokenPopupAsync(request, popupParams, pkceCodes) {
14637
14714
  this.logger.verbose("acquireTokenPopupAsync called");
14638
- const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenPopup);
14639
14715
  const validRequest = await invokeAsync(this.initializeAuthorizationRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, this.logger, this.performanceClient, this.correlationId)(request, exports.InteractionType.Popup);
14640
- const pkce = pkceCodes ||
14641
- (await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, this.correlationId)(this.performanceClient, this.logger, this.correlationId));
14642
- validRequest.codeChallenge = pkce.challenge;
14643
14716
  /*
14644
14717
  * Skip pre-connect for async popups to reduce time between user interaction and popup window creation to avoid
14645
14718
  * popup from being blocked by browsers with shorter popup timers
@@ -14647,65 +14720,49 @@ class PopupClient extends StandardInteractionClient {
14647
14720
  if (popupParams.popup) {
14648
14721
  preconnect(validRequest.authority);
14649
14722
  }
14723
+ const isPlatformBroker = NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme);
14724
+ validRequest.platformBroker = isPlatformBroker;
14725
+ if (this.config.auth.protocolMode === ProtocolMode.EAR) {
14726
+ return this.executeEarFlow(validRequest, popupParams);
14727
+ }
14728
+ else {
14729
+ return this.executeCodeFlow(validRequest, popupParams, pkceCodes);
14730
+ }
14731
+ }
14732
+ /**
14733
+ * Executes auth code + PKCE flow
14734
+ * @param request
14735
+ * @param popupParams
14736
+ * @param pkceCodes
14737
+ * @returns
14738
+ */
14739
+ async executeCodeFlow(request, popupParams, pkceCodes) {
14740
+ const correlationId = request.correlationId;
14741
+ const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenPopup);
14742
+ const pkce = pkceCodes ||
14743
+ (await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, correlationId)(this.performanceClient, this.logger, correlationId));
14744
+ const popupRequest = {
14745
+ ...request,
14746
+ codeChallenge: pkce.challenge,
14747
+ };
14650
14748
  try {
14651
14749
  // Initialize the client
14652
- const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)({
14750
+ const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, correlationId)({
14653
14751
  serverTelemetryManager,
14654
- requestAuthority: validRequest.authority,
14655
- requestAzureCloudOptions: validRequest.azureCloudOptions,
14656
- requestExtraQueryParameters: validRequest.extraQueryParameters,
14657
- account: validRequest.account,
14752
+ requestAuthority: popupRequest.authority,
14753
+ requestAzureCloudOptions: popupRequest.azureCloudOptions,
14754
+ requestExtraQueryParameters: popupRequest.extraQueryParameters,
14755
+ account: popupRequest.account,
14658
14756
  });
14659
- const isPlatformBroker = NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme);
14660
- // Start measurement for server calls with native brokering enabled
14661
- let fetchNativeAccountIdMeasurement;
14662
- if (isPlatformBroker) {
14663
- fetchNativeAccountIdMeasurement =
14664
- this.performanceClient.startMeasurement(PerformanceEvents.FetchAccountIdWithNativeBroker, request.correlationId);
14665
- }
14666
14757
  // Create acquire token url.
14667
- const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, validRequest.correlationId)(this.config, authClient.authority, {
14668
- ...validRequest,
14669
- platformBroker: isPlatformBroker,
14670
- }, this.logger, this.performanceClient);
14758
+ const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, correlationId)(this.config, authClient.authority, popupRequest, this.logger, this.performanceClient);
14671
14759
  // Show the UI once the url has been created. Get the window handle for the popup.
14672
14760
  const popupWindow = this.initiateAuthRequest(navigateUrl, popupParams);
14673
14761
  this.eventHandler.emitEvent(EventType.POPUP_OPENED, exports.InteractionType.Popup, { popupWindow }, null);
14674
14762
  // Monitor the window for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
14675
14763
  const responseString = await this.monitorPopupForHash(popupWindow, popupParams.popupWindowParent);
14676
14764
  const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, this.correlationId)(responseString, this.config.auth.OIDCOptions.serverResponseType, this.logger);
14677
- // Remove throttle if it exists
14678
- ThrottlingUtils.removeThrottle(this.browserStorage, this.config.auth.clientId, validRequest);
14679
- if (serverParams.accountId) {
14680
- this.logger.verbose("Account id found in hash, calling WAM for token");
14681
- // end measurement for server call with native brokering enabled
14682
- if (fetchNativeAccountIdMeasurement) {
14683
- fetchNativeAccountIdMeasurement.end({
14684
- success: true,
14685
- isNativeBroker: true,
14686
- });
14687
- }
14688
- if (!this.nativeMessageHandler) {
14689
- throw createBrowserAuthError(nativeConnectionNotEstablished);
14690
- }
14691
- const nativeInteractionClient = new NativeInteractionClient(this.config, this.browserStorage, this.browserCrypto, this.logger, this.eventHandler, this.navigationClient, ApiId.acquireTokenPopup, this.performanceClient, this.nativeMessageHandler, serverParams.accountId, this.nativeStorage, validRequest.correlationId);
14692
- const { userRequestState } = ProtocolUtils.parseRequestState(this.browserCrypto, validRequest.state);
14693
- return await nativeInteractionClient.acquireToken({
14694
- ...validRequest,
14695
- state: userRequestState,
14696
- prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
14697
- });
14698
- }
14699
- const authCodeRequest = {
14700
- ...validRequest,
14701
- code: serverParams.code || "",
14702
- codeVerifier: pkce.verifier,
14703
- };
14704
- // Create popup interaction handler.
14705
- const interactionHandler = new InteractionHandler(authClient, this.browserStorage, authCodeRequest, this.logger, this.performanceClient);
14706
- // Handle response from hash string.
14707
- const result = await interactionHandler.handleCodeResponse(serverParams, validRequest);
14708
- return result;
14765
+ return await invokeAsync(handleResponseCode, PerformanceEvents.HandleResponseCode, this.logger, this.performanceClient, correlationId)(request, serverParams, pkce.verifier, ApiId.acquireTokenPopup, this.config, authClient, this.browserStorage, this.nativeStorage, this.eventHandler, this.logger, this.performanceClient, this.nativeMessageHandler);
14709
14766
  }
14710
14767
  catch (e) {
14711
14768
  // Close the synchronous popup if an error is thrown before the window unload event is registered
@@ -14717,6 +14774,32 @@ class PopupClient extends StandardInteractionClient {
14717
14774
  throw e;
14718
14775
  }
14719
14776
  }
14777
+ /**
14778
+ * Executes EAR flow
14779
+ * @param request
14780
+ */
14781
+ async executeEarFlow(request, popupParams) {
14782
+ const correlationId = request.correlationId;
14783
+ // Get the frame handle for the silent request
14784
+ const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, correlationId)({
14785
+ requestAuthority: request.authority,
14786
+ requestAzureCloudOptions: request.azureCloudOptions,
14787
+ requestExtraQueryParameters: request.extraQueryParameters,
14788
+ account: request.account,
14789
+ });
14790
+ const earJwk = await invokeAsync(generateEarKey, PerformanceEvents.GenerateEarKey, this.logger, this.performanceClient, correlationId)();
14791
+ const popupRequest = {
14792
+ ...request,
14793
+ earJwk: earJwk,
14794
+ };
14795
+ const popupWindow = popupParams.popup || this.openPopup("about:blank", popupParams);
14796
+ const form = await getEARForm(popupWindow.document, this.config, discoveredAuthority, popupRequest, this.logger, this.performanceClient);
14797
+ form.submit();
14798
+ // Monitor the popup for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
14799
+ const responseString = await invokeAsync(this.monitorPopupForHash.bind(this), PerformanceEvents.SilentHandlerMonitorIframeForHash, this.logger, this.performanceClient, correlationId)(popupWindow, popupParams.popupWindowParent);
14800
+ const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, this.correlationId)(responseString, this.config.auth.OIDCOptions.serverResponseType, this.logger);
14801
+ return invokeAsync(handleResponseEAR, PerformanceEvents.HandleResponseEar, this.logger, this.performanceClient, correlationId)(popupRequest, serverParams, ApiId.acquireTokenPopup, this.config, discoveredAuthority, this.browserStorage, this.nativeStorage, this.eventHandler, this.logger, this.performanceClient, this.nativeMessageHandler);
14802
+ }
14720
14803
  /**
14721
14804
  *
14722
14805
  * @param validRequest
@@ -14792,7 +14875,6 @@ class PopupClient extends StandardInteractionClient {
14792
14875
  e.setCorrelationId(this.correlationId);
14793
14876
  serverTelemetryManager.cacheFailedRequest(e);
14794
14877
  }
14795
- this.browserStorage.setInteractionInProgress(false);
14796
14878
  this.eventHandler.emitEvent(EventType.LOGOUT_FAILURE, exports.InteractionType.Popup, null, e);
14797
14879
  this.eventHandler.emitEvent(EventType.LOGOUT_END, exports.InteractionType.Popup);
14798
14880
  throw e;
@@ -14904,7 +14986,6 @@ class PopupClient extends StandardInteractionClient {
14904
14986
  }
14905
14987
  catch (e) {
14906
14988
  this.logger.error("error opening popup " + e.message);
14907
- this.browserStorage.setInteractionInProgress(false);
14908
14989
  throw createBrowserAuthError(popupWindowError);
14909
14990
  }
14910
14991
  }
@@ -14962,7 +15043,6 @@ class PopupClient extends StandardInteractionClient {
14962
15043
  * Event callback to unload main window.
14963
15044
  */
14964
15045
  unloadWindow(e) {
14965
- this.browserStorage.cleanRequestByInteractionType(exports.InteractionType.Popup);
14966
15046
  if (this.currentWindow) {
14967
15047
  this.currentWindow.close();
14968
15048
  }
@@ -14978,8 +15058,6 @@ class PopupClient extends StandardInteractionClient {
14978
15058
  popupWindow.close();
14979
15059
  // Remove window unload function
14980
15060
  popupWindowParent.removeEventListener("beforeunload", this.unloadWindow);
14981
- // Interaction is completed - remove interaction status.
14982
- this.browserStorage.setInteractionInProgress(false);
14983
15061
  }
14984
15062
  /**
14985
15063
  * Generates the name for the popup based on the client id and request
@@ -15000,141 +15078,6 @@ class PopupClient extends StandardInteractionClient {
15000
15078
  }
15001
15079
  }
15002
15080
 
15003
- /*
15004
- * Copyright (c) Microsoft Corporation. All rights reserved.
15005
- * Licensed under the MIT License.
15006
- */
15007
- class RedirectHandler {
15008
- constructor(authCodeModule, storageImpl, authCodeRequest, logger, performanceClient) {
15009
- this.authModule = authCodeModule;
15010
- this.browserStorage = storageImpl;
15011
- this.authCodeRequest = authCodeRequest;
15012
- this.logger = logger;
15013
- this.performanceClient = performanceClient;
15014
- }
15015
- /**
15016
- * Redirects window to given URL.
15017
- * @param urlNavigate
15018
- */
15019
- async initiateAuthRequest(requestUrl, params) {
15020
- this.logger.verbose("RedirectHandler.initiateAuthRequest called");
15021
- // Navigate if valid URL
15022
- if (requestUrl) {
15023
- // Cache start page, returns to this page after redirectUri if navigateToLoginRequestUrl is true
15024
- if (params.redirectStartPage) {
15025
- this.logger.verbose("RedirectHandler.initiateAuthRequest: redirectStartPage set, caching start page");
15026
- this.browserStorage.setTemporaryCache(TemporaryCacheKeys.ORIGIN_URI, params.redirectStartPage, true);
15027
- }
15028
- // Set interaction status in the library.
15029
- this.browserStorage.setTemporaryCache(TemporaryCacheKeys.CORRELATION_ID, this.authCodeRequest.correlationId, true);
15030
- this.browserStorage.cacheCodeRequest(this.authCodeRequest);
15031
- this.logger.infoPii(`RedirectHandler.initiateAuthRequest: Navigate to: ${requestUrl}`);
15032
- const navigationOptions = {
15033
- apiId: ApiId.acquireTokenRedirect,
15034
- timeout: params.redirectTimeout,
15035
- noHistory: false,
15036
- };
15037
- // If onRedirectNavigate is implemented, invoke it and provide requestUrl
15038
- if (typeof params.onRedirectNavigate === "function") {
15039
- this.logger.verbose("RedirectHandler.initiateAuthRequest: Invoking onRedirectNavigate callback");
15040
- const navigate = params.onRedirectNavigate(requestUrl);
15041
- // Returning false from onRedirectNavigate will stop navigation
15042
- if (navigate !== false) {
15043
- this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate did not return false, navigating");
15044
- await params.navigationClient.navigateExternal(requestUrl, navigationOptions);
15045
- return;
15046
- }
15047
- else {
15048
- this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate returned false, stopping navigation");
15049
- return;
15050
- }
15051
- }
15052
- else {
15053
- // Navigate window to request URL
15054
- this.logger.verbose("RedirectHandler.initiateAuthRequest: Navigating window to navigate url");
15055
- await params.navigationClient.navigateExternal(requestUrl, navigationOptions);
15056
- return;
15057
- }
15058
- }
15059
- else {
15060
- // Throw error if request URL is empty.
15061
- this.logger.info("RedirectHandler.initiateAuthRequest: Navigate url is empty");
15062
- throw createBrowserAuthError(emptyNavigateUri);
15063
- }
15064
- }
15065
- /**
15066
- * Handle authorization code response in the window.
15067
- * @param hash
15068
- */
15069
- async handleCodeResponse(response, state) {
15070
- this.logger.verbose("RedirectHandler.handleCodeResponse called");
15071
- // Interaction is completed - remove interaction status.
15072
- this.browserStorage.setInteractionInProgress(false);
15073
- // Handle code response.
15074
- const stateKey = this.browserStorage.generateStateKey(state);
15075
- const requestState = this.browserStorage.getTemporaryCache(stateKey);
15076
- if (!requestState) {
15077
- throw createClientAuthError(stateNotFound, "Cached State");
15078
- }
15079
- let authCodeResponse;
15080
- try {
15081
- authCodeResponse = getAuthorizationCodePayload(response, requestState);
15082
- }
15083
- catch (e) {
15084
- if (e instanceof ServerError &&
15085
- e.subError === userCancelled) {
15086
- // Translate server error caused by user closing native prompt to corresponding first class MSAL error
15087
- throw createBrowserAuthError(userCancelled);
15088
- }
15089
- else {
15090
- throw e;
15091
- }
15092
- }
15093
- // Get cached items
15094
- const nonceKey = this.browserStorage.generateNonceKey(requestState);
15095
- const cachedNonce = this.browserStorage.getTemporaryCache(nonceKey);
15096
- // Assign code to request
15097
- this.authCodeRequest.code = authCodeResponse.code;
15098
- // Check for new cloud instance
15099
- if (authCodeResponse.cloud_instance_host_name) {
15100
- await invokeAsync(this.authModule.updateAuthority.bind(this.authModule), PerformanceEvents.UpdateTokenEndpointAuthority, this.logger, this.performanceClient, this.authCodeRequest.correlationId)(authCodeResponse.cloud_instance_host_name, this.authCodeRequest.correlationId);
15101
- }
15102
- authCodeResponse.nonce = cachedNonce || undefined;
15103
- authCodeResponse.state = requestState;
15104
- // Add CCS parameters if available
15105
- if (authCodeResponse.client_info) {
15106
- this.authCodeRequest.clientInfo = authCodeResponse.client_info;
15107
- }
15108
- else {
15109
- const cachedCcsCred = this.checkCcsCredentials();
15110
- if (cachedCcsCred) {
15111
- this.authCodeRequest.ccsCredential = cachedCcsCred;
15112
- }
15113
- }
15114
- // Acquire token with retrieved code.
15115
- const tokenResponse = (await this.authModule.acquireToken(this.authCodeRequest, authCodeResponse));
15116
- this.browserStorage.cleanRequestByState(state);
15117
- return tokenResponse;
15118
- }
15119
- /**
15120
- * Looks up ccs creds in the cache
15121
- */
15122
- checkCcsCredentials() {
15123
- // Look up ccs credential in temp cache
15124
- const cachedCcsCred = this.browserStorage.getTemporaryCache(TemporaryCacheKeys.CCS_CREDENTIAL, true);
15125
- if (cachedCcsCred) {
15126
- try {
15127
- return JSON.parse(cachedCcsCred);
15128
- }
15129
- catch (e) {
15130
- this.authModule.logger.error("Cache credential could not be parsed");
15131
- this.authModule.logger.errorPii(`Cache credential could not be parsed: ${cachedCcsCred}`);
15132
- }
15133
- }
15134
- return null;
15135
- }
15136
- }
15137
-
15138
15081
  /*
15139
15082
  * Copyright (c) Microsoft Corporation. All rights reserved.
15140
15083
  * Licensed under the MIT License.
@@ -15162,62 +15105,96 @@ class RedirectClient extends StandardInteractionClient {
15162
15105
  */
15163
15106
  async acquireToken(request) {
15164
15107
  const validRequest = await invokeAsync(this.initializeAuthorizationRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, this.logger, this.performanceClient, this.correlationId)(request, exports.InteractionType.Redirect);
15165
- const pkceCodes = await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, this.correlationId)(this.performanceClient, this.logger, this.correlationId);
15166
- validRequest.codeChallenge = pkceCodes.challenge;
15167
- this.browserStorage.updateCacheEntries(validRequest.state, validRequest.nonce, validRequest.authority, validRequest.loginHint || "", validRequest.account || null);
15168
- const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenRedirect);
15108
+ validRequest.platformBroker =
15109
+ NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme);
15169
15110
  const handleBackButton = (event) => {
15170
15111
  // Clear temporary cache if the back button is clicked during the redirect flow.
15171
15112
  if (event.persisted) {
15172
15113
  this.logger.verbose("Page was restored from back/forward cache. Clearing temporary cache.");
15173
- this.browserStorage.cleanRequestByState(validRequest.state);
15114
+ this.browserStorage.resetRequestCache();
15174
15115
  this.eventHandler.emitEvent(EventType.RESTORE_FROM_BFCACHE, exports.InteractionType.Redirect);
15175
15116
  }
15176
15117
  };
15118
+ const redirectStartPage = this.getRedirectStartPage(request.redirectStartPage);
15119
+ this.logger.verbosePii(`Redirect start page: ${redirectStartPage}`);
15120
+ // Cache start page, returns to this page after redirectUri if navigateToLoginRequestUrl is true
15121
+ this.browserStorage.setTemporaryCache(TemporaryCacheKeys.ORIGIN_URI, redirectStartPage, true);
15122
+ // Clear temporary cache if the back button is clicked during the redirect flow.
15123
+ window.addEventListener("pageshow", handleBackButton);
15124
+ try {
15125
+ if (this.config.auth.protocolMode === ProtocolMode.EAR) {
15126
+ await this.executeEarFlow(validRequest);
15127
+ }
15128
+ else {
15129
+ await this.executeCodeFlow(validRequest, request.onRedirectNavigate);
15130
+ }
15131
+ }
15132
+ catch (e) {
15133
+ if (e instanceof AuthError) {
15134
+ e.setCorrelationId(this.correlationId);
15135
+ }
15136
+ window.removeEventListener("pageshow", handleBackButton);
15137
+ throw e;
15138
+ }
15139
+ }
15140
+ /**
15141
+ * Executes auth code + PKCE flow
15142
+ * @param request
15143
+ * @returns
15144
+ */
15145
+ async executeCodeFlow(request, onRedirectNavigate) {
15146
+ const correlationId = request.correlationId;
15147
+ const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenRedirect);
15148
+ const pkceCodes = await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, correlationId)(this.performanceClient, this.logger, correlationId);
15149
+ const redirectRequest = {
15150
+ ...request,
15151
+ codeChallenge: pkceCodes.challenge,
15152
+ };
15153
+ this.browserStorage.cacheAuthorizeRequest(redirectRequest, pkceCodes.verifier);
15177
15154
  try {
15178
15155
  // Initialize the client
15179
15156
  const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)({
15180
15157
  serverTelemetryManager,
15181
- requestAuthority: validRequest.authority,
15182
- requestAzureCloudOptions: validRequest.azureCloudOptions,
15183
- requestExtraQueryParameters: validRequest.extraQueryParameters,
15184
- account: validRequest.account,
15158
+ requestAuthority: redirectRequest.authority,
15159
+ requestAzureCloudOptions: redirectRequest.azureCloudOptions,
15160
+ requestExtraQueryParameters: redirectRequest.extraQueryParameters,
15161
+ account: redirectRequest.account,
15185
15162
  });
15186
- const authCodeRequest = {
15187
- ...validRequest,
15188
- code: "",
15189
- codeVerifier: pkceCodes.verifier,
15190
- };
15191
- // Create redirect interaction handler.
15192
- const interactionHandler = new RedirectHandler(authClient, this.browserStorage, authCodeRequest, this.logger, this.performanceClient);
15193
15163
  // Create acquire token url.
15194
- const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, validRequest.correlationId)(this.config, authClient.authority, {
15195
- ...validRequest,
15196
- platformBroker: NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme),
15197
- }, this.logger, this.performanceClient);
15198
- const redirectStartPage = this.getRedirectStartPage(request.redirectStartPage);
15199
- this.logger.verbosePii(`Redirect start page: ${redirectStartPage}`);
15200
- // Clear temporary cache if the back button is clicked during the redirect flow.
15201
- window.addEventListener("pageshow", handleBackButton);
15164
+ const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, request.correlationId)(this.config, authClient.authority, redirectRequest, this.logger, this.performanceClient);
15202
15165
  // Show the UI once the url has been created. Response will come back in the hash, which will be handled in the handleRedirectCallback function.
15203
- return await interactionHandler.initiateAuthRequest(navigateUrl, {
15204
- navigationClient: this.navigationClient,
15205
- redirectTimeout: this.config.system.redirectNavigationTimeout,
15206
- redirectStartPage: redirectStartPage,
15207
- onRedirectNavigate: request.onRedirectNavigate ||
15208
- this.config.auth.onRedirectNavigate,
15209
- });
15166
+ return await this.initiateAuthRequest(navigateUrl, onRedirectNavigate);
15210
15167
  }
15211
15168
  catch (e) {
15212
15169
  if (e instanceof AuthError) {
15213
15170
  e.setCorrelationId(this.correlationId);
15214
15171
  serverTelemetryManager.cacheFailedRequest(e);
15215
15172
  }
15216
- window.removeEventListener("pageshow", handleBackButton);
15217
- this.browserStorage.cleanRequestByState(validRequest.state);
15218
15173
  throw e;
15219
15174
  }
15220
15175
  }
15176
+ /**
15177
+ * Executes EAR flow
15178
+ * @param request
15179
+ */
15180
+ async executeEarFlow(request) {
15181
+ const correlationId = request.correlationId;
15182
+ // Get the frame handle for the silent request
15183
+ const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, correlationId)({
15184
+ requestAuthority: request.authority,
15185
+ requestAzureCloudOptions: request.azureCloudOptions,
15186
+ requestExtraQueryParameters: request.extraQueryParameters,
15187
+ account: request.account,
15188
+ });
15189
+ const earJwk = await invokeAsync(generateEarKey, PerformanceEvents.GenerateEarKey, this.logger, this.performanceClient, correlationId)();
15190
+ const redirectRequest = {
15191
+ ...request,
15192
+ earJwk: earJwk,
15193
+ };
15194
+ this.browserStorage.cacheAuthorizeRequest(redirectRequest);
15195
+ const form = await getEARForm(document, this.config, discoveredAuthority, redirectRequest, this.logger, this.performanceClient);
15196
+ form.submit();
15197
+ }
15221
15198
  /**
15222
15199
  * Checks if navigateToLoginRequestUrl is set, and:
15223
15200
  * - if true, performs logic to cache and navigate
@@ -15225,18 +15202,14 @@ class RedirectClient extends StandardInteractionClient {
15225
15202
  * @param hash {string} url hash
15226
15203
  * @param parentMeasurement {InProgressPerformanceEvent} parent measurement
15227
15204
  */
15228
- async handleRedirectPromise(hash = "", parentMeasurement) {
15205
+ async handleRedirectPromise(hash = "", request, pkceVerifier, parentMeasurement) {
15229
15206
  const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.handleRedirectPromise);
15230
15207
  try {
15231
- if (!this.browserStorage.isInteractionInProgress(true)) {
15232
- this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
15233
- return null;
15234
- }
15235
15208
  const [serverParams, responseString] = this.getRedirectResponse(hash || "");
15236
15209
  if (!serverParams) {
15237
15210
  // Not a recognized server response hash or hash not associated with a redirect request
15238
15211
  this.logger.info("handleRedirectPromise did not detect a response as a result of a redirect. Cleaning temporary cache.");
15239
- this.browserStorage.cleanRequestByInteractionType(exports.InteractionType.Redirect);
15212
+ this.browserStorage.resetRequestCache();
15240
15213
  // Do not instrument "no_server_response" if user clicked back button
15241
15214
  if (getNavigationType() !== "back_forward") {
15242
15215
  parentMeasurement.event.errorCode = "no_server_response";
@@ -15258,12 +15231,12 @@ class RedirectClient extends StandardInteractionClient {
15258
15231
  // Replace current hash with non-msal hash, if present
15259
15232
  replaceHash(loginRequestUrl);
15260
15233
  }
15261
- const handleHashResult = await this.handleResponse(serverParams, serverTelemetryManager);
15234
+ const handleHashResult = await this.handleResponse(serverParams, request, pkceVerifier, serverTelemetryManager);
15262
15235
  return handleHashResult;
15263
15236
  }
15264
15237
  else if (!this.config.auth.navigateToLoginRequestUrl) {
15265
15238
  this.logger.verbose("NavigateToLoginRequestUrl set to false, handling response");
15266
- return await this.handleResponse(serverParams, serverTelemetryManager);
15239
+ return await this.handleResponse(serverParams, request, pkceVerifier, serverTelemetryManager);
15267
15240
  }
15268
15241
  else if (!isInIframe() ||
15269
15242
  this.config.system.allowRedirectInIframe) {
@@ -15299,7 +15272,7 @@ class RedirectClient extends StandardInteractionClient {
15299
15272
  }
15300
15273
  // If navigateInternal implementation returns false, handle the hash now
15301
15274
  if (!processHashOnRedirect) {
15302
- return await this.handleResponse(serverParams, serverTelemetryManager);
15275
+ return await this.handleResponse(serverParams, request, pkceVerifier, serverTelemetryManager);
15303
15276
  }
15304
15277
  }
15305
15278
  return null;
@@ -15309,7 +15282,6 @@ class RedirectClient extends StandardInteractionClient {
15309
15282
  e.setCorrelationId(this.correlationId);
15310
15283
  serverTelemetryManager.cacheFailedRequest(e);
15311
15284
  }
15312
- this.browserStorage.cleanRequestByInteractionType(exports.InteractionType.Redirect);
15313
15285
  throw e;
15314
15286
  }
15315
15287
  }
@@ -15362,39 +15334,67 @@ class RedirectClient extends StandardInteractionClient {
15362
15334
  * @param hash
15363
15335
  * @param state
15364
15336
  */
15365
- async handleResponse(serverParams, serverTelemetryManager) {
15337
+ async handleResponse(serverParams, request, codeVerifier, serverTelemetryManager) {
15366
15338
  const state = serverParams.state;
15367
15339
  if (!state) {
15368
15340
  throw createBrowserAuthError(noStateInHash);
15369
15341
  }
15370
- const cachedRequest = this.browserStorage.getCachedRequest(state);
15371
- this.logger.verbose("handleResponse called, retrieved cached request");
15372
- if (serverParams.accountId) {
15373
- this.logger.verbose("Account id found in hash, calling WAM for token");
15374
- if (!this.nativeMessageHandler) {
15375
- throw createBrowserAuthError(nativeConnectionNotEstablished);
15376
- }
15377
- const nativeInteractionClient = new NativeInteractionClient(this.config, this.browserStorage, this.browserCrypto, this.logger, this.eventHandler, this.navigationClient, ApiId.acquireTokenPopup, this.performanceClient, this.nativeMessageHandler, serverParams.accountId, this.nativeStorage, cachedRequest.correlationId);
15378
- const { userRequestState } = ProtocolUtils.parseRequestState(this.browserCrypto, state);
15379
- return nativeInteractionClient
15380
- .acquireToken({
15381
- ...cachedRequest,
15382
- state: userRequestState,
15383
- prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
15384
- })
15385
- .finally(() => {
15386
- this.browserStorage.cleanRequestByState(state);
15342
+ if (serverParams.ear_jwe) {
15343
+ const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, request.correlationId)({
15344
+ requestAuthority: request.authority,
15345
+ requestAzureCloudOptions: request.azureCloudOptions,
15346
+ requestExtraQueryParameters: request.extraQueryParameters,
15347
+ account: request.account,
15387
15348
  });
15349
+ return invokeAsync(handleResponseEAR, PerformanceEvents.HandleResponseEar, this.logger, this.performanceClient, request.correlationId)(request, serverParams, ApiId.acquireTokenRedirect, this.config, discoveredAuthority, this.browserStorage, this.nativeStorage, this.eventHandler, this.logger, this.performanceClient, this.nativeMessageHandler);
15350
+ }
15351
+ const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)({ serverTelemetryManager, requestAuthority: request.authority });
15352
+ return invokeAsync(handleResponseCode, PerformanceEvents.HandleResponseCode, this.logger, this.performanceClient, request.correlationId)(request, serverParams, codeVerifier, ApiId.acquireTokenRedirect, this.config, authClient, this.browserStorage, this.nativeStorage, this.eventHandler, this.logger, this.performanceClient, this.nativeMessageHandler);
15353
+ }
15354
+ /**
15355
+ * Redirects window to given URL.
15356
+ * @param urlNavigate
15357
+ * @param onRedirectNavigateRequest - onRedirectNavigate callback provided on the request
15358
+ */
15359
+ async initiateAuthRequest(requestUrl, onRedirectNavigateRequest) {
15360
+ this.logger.verbose("RedirectHandler.initiateAuthRequest called");
15361
+ // Navigate if valid URL
15362
+ if (requestUrl) {
15363
+ this.logger.infoPii(`RedirectHandler.initiateAuthRequest: Navigate to: ${requestUrl}`);
15364
+ const navigationOptions = {
15365
+ apiId: ApiId.acquireTokenRedirect,
15366
+ timeout: this.config.system.redirectNavigationTimeout,
15367
+ noHistory: false,
15368
+ };
15369
+ const onRedirectNavigate = onRedirectNavigateRequest ||
15370
+ this.config.auth.onRedirectNavigate;
15371
+ // If onRedirectNavigate is implemented, invoke it and provide requestUrl
15372
+ if (typeof onRedirectNavigate === "function") {
15373
+ this.logger.verbose("RedirectHandler.initiateAuthRequest: Invoking onRedirectNavigate callback");
15374
+ const navigate = onRedirectNavigate(requestUrl);
15375
+ // Returning false from onRedirectNavigate will stop navigation
15376
+ if (navigate !== false) {
15377
+ this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate did not return false, navigating");
15378
+ await this.navigationClient.navigateExternal(requestUrl, navigationOptions);
15379
+ return;
15380
+ }
15381
+ else {
15382
+ this.logger.verbose("RedirectHandler.initiateAuthRequest: onRedirectNavigate returned false, stopping navigation");
15383
+ return;
15384
+ }
15385
+ }
15386
+ else {
15387
+ // Navigate window to request URL
15388
+ this.logger.verbose("RedirectHandler.initiateAuthRequest: Navigating window to navigate url");
15389
+ await this.navigationClient.navigateExternal(requestUrl, navigationOptions);
15390
+ return;
15391
+ }
15388
15392
  }
15389
- // Hash contains known properties - handle and return in callback
15390
- const currentAuthority = this.browserStorage.getCachedAuthority(state);
15391
- if (!currentAuthority) {
15392
- throw createBrowserAuthError(noCachedAuthorityError);
15393
+ else {
15394
+ // Throw error if request URL is empty.
15395
+ this.logger.info("RedirectHandler.initiateAuthRequest: Navigate url is empty");
15396
+ throw createBrowserAuthError(emptyNavigateUri);
15393
15397
  }
15394
- const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)({ serverTelemetryManager, requestAuthority: currentAuthority });
15395
- ThrottlingUtils.removeThrottle(this.browserStorage, this.config.auth.clientId, cachedRequest);
15396
- const interactionHandler = new RedirectHandler(authClient, this.browserStorage, cachedRequest, this.logger, this.performanceClient);
15397
- return interactionHandler.handleCodeResponse(serverParams, state);
15398
15398
  }
15399
15399
  /**
15400
15400
  * Use to log out the current user, and redirect the user to the postLogoutRedirectUri.
@@ -15493,7 +15493,7 @@ class RedirectClient extends StandardInteractionClient {
15493
15493
  * @param urlNavigate
15494
15494
  * @param userRequestScopes
15495
15495
  */
15496
- async function initiateAuthRequest(requestUrl, performanceClient, logger, correlationId, navigateFrameWait) {
15496
+ async function initiateCodeRequest(requestUrl, performanceClient, logger, correlationId, navigateFrameWait) {
15497
15497
  performanceClient.addQueueMeasurement(PerformanceEvents.SilentHandlerInitiateAuthRequest, correlationId);
15498
15498
  if (!requestUrl) {
15499
15499
  // Throw error if request URL is empty.
@@ -15505,6 +15505,15 @@ async function initiateAuthRequest(requestUrl, performanceClient, logger, correl
15505
15505
  }
15506
15506
  return invoke(loadFrameSync, PerformanceEvents.SilentHandlerLoadFrameSync, logger, performanceClient, correlationId)(requestUrl);
15507
15507
  }
15508
+ async function initiateEarRequest(config, authority, request, logger, performanceClient) {
15509
+ const frame = createHiddenIframe();
15510
+ if (!frame.contentDocument) {
15511
+ throw "No document associated with iframe!";
15512
+ }
15513
+ const form = await getEARForm(frame.contentDocument, config, authority, request, logger, performanceClient);
15514
+ form.submit();
15515
+ return frame;
15516
+ }
15508
15517
  /**
15509
15518
  * Monitors an iframe content window until it loads a url with a known hash, or hits a specified timeout.
15510
15519
  * @param iframe
@@ -15655,19 +15664,34 @@ class SilentIframeClient extends StandardInteractionClient {
15655
15664
  }
15656
15665
  // Create silent request
15657
15666
  const silentRequest = await invokeAsync(this.initializeAuthorizationRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, this.logger, this.performanceClient, request.correlationId)(inputRequest, exports.InteractionType.Silent);
15667
+ silentRequest.platformBroker =
15668
+ NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, silentRequest.authenticationScheme);
15658
15669
  preconnect(silentRequest.authority);
15659
- const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
15670
+ if (this.config.auth.protocolMode === ProtocolMode.EAR) {
15671
+ return this.executeEarFlow(silentRequest);
15672
+ }
15673
+ else {
15674
+ return this.executeCodeFlow(silentRequest);
15675
+ }
15676
+ }
15677
+ /**
15678
+ * Executes auth code + PKCE flow
15679
+ * @param request
15680
+ * @returns
15681
+ */
15682
+ async executeCodeFlow(request) {
15660
15683
  let authClient;
15684
+ const serverTelemetryManager = this.initializeServerTelemetryManager(this.apiId);
15661
15685
  try {
15662
15686
  // Initialize the client
15663
15687
  authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, request.correlationId)({
15664
15688
  serverTelemetryManager,
15665
- requestAuthority: silentRequest.authority,
15666
- requestAzureCloudOptions: silentRequest.azureCloudOptions,
15667
- requestExtraQueryParameters: silentRequest.extraQueryParameters,
15668
- account: silentRequest.account,
15689
+ requestAuthority: request.authority,
15690
+ requestAzureCloudOptions: request.azureCloudOptions,
15691
+ requestExtraQueryParameters: request.extraQueryParameters,
15692
+ account: request.account,
15669
15693
  });
15670
- return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, request.correlationId)(authClient, silentRequest);
15694
+ return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, request.correlationId)(authClient, request);
15671
15695
  }
15672
15696
  catch (e) {
15673
15697
  if (e instanceof AuthError) {
@@ -15682,10 +15706,33 @@ class SilentIframeClient extends StandardInteractionClient {
15682
15706
  this.performanceClient.addFields({
15683
15707
  retryError: e.errorCode,
15684
15708
  }, this.correlationId);
15685
- const retrySilentRequest = await invokeAsync(this.initializeAuthorizationRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, this.logger, this.performanceClient, request.correlationId)(inputRequest, exports.InteractionType.Silent);
15686
- return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, this.correlationId)(authClient, retrySilentRequest);
15709
+ return await invokeAsync(this.silentTokenHelper.bind(this), PerformanceEvents.SilentIframeClientTokenHelper, this.logger, this.performanceClient, this.correlationId)(authClient, request);
15687
15710
  }
15688
15711
  }
15712
+ /**
15713
+ * Executes EAR flow
15714
+ * @param request
15715
+ */
15716
+ async executeEarFlow(request) {
15717
+ const correlationId = request.correlationId;
15718
+ const discoveredAuthority = await invokeAsync(this.getDiscoveredAuthority.bind(this), PerformanceEvents.StandardInteractionClientGetDiscoveredAuthority, this.logger, this.performanceClient, correlationId)({
15719
+ requestAuthority: request.authority,
15720
+ requestAzureCloudOptions: request.azureCloudOptions,
15721
+ requestExtraQueryParameters: request.extraQueryParameters,
15722
+ account: request.account,
15723
+ });
15724
+ const earJwk = await invokeAsync(generateEarKey, PerformanceEvents.GenerateEarKey, this.logger, this.performanceClient, correlationId)();
15725
+ const silentRequest = {
15726
+ ...request,
15727
+ earJwk: earJwk,
15728
+ };
15729
+ const msalFrame = await invokeAsync(initiateEarRequest, PerformanceEvents.SilentHandlerInitiateAuthRequest, this.logger, this.performanceClient, correlationId)(this.config, discoveredAuthority, silentRequest, this.logger, this.performanceClient);
15730
+ const responseType = this.config.auth.OIDCOptions.serverResponseType;
15731
+ // Monitor the window for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
15732
+ const responseString = await invokeAsync(monitorIframeForHash, PerformanceEvents.SilentHandlerMonitorIframeForHash, this.logger, this.performanceClient, correlationId)(msalFrame, this.config.system.iframeHashTimeout, this.config.system.pollIntervalMilliseconds, this.performanceClient, this.logger, correlationId, responseType);
15733
+ const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, correlationId)(responseString, responseType, this.logger);
15734
+ return invokeAsync(handleResponseEAR, PerformanceEvents.HandleResponseEar, this.logger, this.performanceClient, correlationId)(silentRequest, serverParams, this.apiId, this.config, discoveredAuthority, this.browserStorage, this.nativeStorage, this.eventHandler, this.logger, this.performanceClient, this.nativeMessageHandler);
15735
+ }
15689
15736
  /**
15690
15737
  * Currently Unsupported
15691
15738
  */
@@ -15702,44 +15749,20 @@ class SilentIframeClient extends StandardInteractionClient {
15702
15749
  async silentTokenHelper(authClient, request) {
15703
15750
  const correlationId = request.correlationId;
15704
15751
  this.performanceClient.addQueueMeasurement(PerformanceEvents.SilentIframeClientTokenHelper, correlationId);
15705
- const pkceCodes = await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, this.correlationId)(this.performanceClient, this.logger, this.correlationId);
15752
+ const pkceCodes = await invokeAsync(generatePkceCodes, PerformanceEvents.GeneratePkceCodes, this.logger, this.performanceClient, correlationId)(this.performanceClient, this.logger, correlationId);
15706
15753
  const silentRequest = {
15707
15754
  ...request,
15708
15755
  codeChallenge: pkceCodes.challenge,
15709
15756
  };
15710
15757
  // Create authorize request url
15711
- const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, correlationId)(this.config, authClient.authority, {
15712
- ...silentRequest,
15713
- platformBroker: NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeMessageHandler, silentRequest.authenticationScheme),
15714
- }, this.logger, this.performanceClient);
15758
+ const navigateUrl = await invokeAsync(getAuthCodeRequestUrl, PerformanceEvents.GetAuthCodeUrl, this.logger, this.performanceClient, correlationId)(this.config, authClient.authority, silentRequest, this.logger, this.performanceClient);
15715
15759
  // Get the frame handle for the silent request
15716
- const msalFrame = await invokeAsync(initiateAuthRequest, PerformanceEvents.SilentHandlerInitiateAuthRequest, this.logger, this.performanceClient, correlationId)(navigateUrl, this.performanceClient, this.logger, correlationId, this.config.system.navigateFrameWait);
15760
+ const msalFrame = await invokeAsync(initiateCodeRequest, PerformanceEvents.SilentHandlerInitiateAuthRequest, this.logger, this.performanceClient, correlationId)(navigateUrl, this.performanceClient, this.logger, correlationId, this.config.system.navigateFrameWait);
15717
15761
  const responseType = this.config.auth.OIDCOptions.serverResponseType;
15718
15762
  // Monitor the window for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
15719
15763
  const responseString = await invokeAsync(monitorIframeForHash, PerformanceEvents.SilentHandlerMonitorIframeForHash, this.logger, this.performanceClient, correlationId)(msalFrame, this.config.system.iframeHashTimeout, this.config.system.pollIntervalMilliseconds, this.performanceClient, this.logger, correlationId, responseType);
15720
- const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, this.correlationId)(responseString, responseType, this.logger);
15721
- if (serverParams.accountId) {
15722
- this.logger.verbose("Account id found in hash, calling WAM for token");
15723
- if (!this.nativeMessageHandler) {
15724
- throw createBrowserAuthError(nativeConnectionNotEstablished);
15725
- }
15726
- const nativeInteractionClient = new NativeInteractionClient(this.config, this.browserStorage, this.browserCrypto, this.logger, this.eventHandler, this.navigationClient, this.apiId, this.performanceClient, this.nativeMessageHandler, serverParams.accountId, this.browserStorage, correlationId);
15727
- const { userRequestState } = ProtocolUtils.parseRequestState(this.browserCrypto, silentRequest.state);
15728
- return invokeAsync(nativeInteractionClient.acquireToken.bind(nativeInteractionClient), PerformanceEvents.NativeInteractionClientAcquireToken, this.logger, this.performanceClient, correlationId)({
15729
- ...silentRequest,
15730
- state: userRequestState,
15731
- prompt: silentRequest.prompt || PromptValue.NONE,
15732
- });
15733
- }
15734
- const authCodeRequest = {
15735
- ...silentRequest,
15736
- code: serverParams.code || "",
15737
- codeVerifier: pkceCodes.verifier,
15738
- };
15739
- // Create silent handler
15740
- const interactionHandler = new InteractionHandler(authClient, this.browserStorage, authCodeRequest, this.logger, this.performanceClient);
15741
- // Handle response from hash string
15742
- return invokeAsync(interactionHandler.handleCodeResponse.bind(interactionHandler), PerformanceEvents.HandleCodeResponse, this.logger, this.performanceClient, correlationId)(serverParams, silentRequest);
15764
+ const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, correlationId)(responseString, responseType, this.logger);
15765
+ return invokeAsync(handleResponseCode, PerformanceEvents.HandleResponseCode, this.logger, this.performanceClient, correlationId)(request, serverParams, pkceCodes.verifier, this.apiId, this.config, authClient, this.browserStorage, this.nativeStorage, this.eventHandler, this.logger, this.performanceClient, this.nativeMessageHandler);
15743
15766
  }
15744
15767
  }
15745
15768
 
@@ -16268,31 +16291,38 @@ class StandardController {
16268
16291
  * @returns
16269
16292
  */
16270
16293
  async handleRedirectPromiseInternal(hash) {
16294
+ if (!this.browserStorage.isInteractionInProgress(true)) {
16295
+ this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
16296
+ return null;
16297
+ }
16271
16298
  const loggedInAccounts = this.getAllAccounts();
16272
- const request = this.browserStorage.getCachedNativeRequest();
16273
- const useNative = request &&
16299
+ const platformBrokerRequest = this.browserStorage.getCachedNativeRequest();
16300
+ const useNative = platformBrokerRequest &&
16274
16301
  NativeMessageHandler.isPlatformBrokerAvailable(this.config, this.logger, this.nativeExtensionProvider) &&
16275
16302
  this.nativeExtensionProvider &&
16276
16303
  !hash;
16277
- const correlationId = useNative
16278
- ? request?.correlationId
16279
- : this.browserStorage.getTemporaryCache(TemporaryCacheKeys.CORRELATION_ID, true) || "";
16280
- const rootMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenRedirect, correlationId);
16304
+ let rootMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenRedirect, platformBrokerRequest?.correlationId || "");
16281
16305
  this.eventHandler.emitEvent(EventType.HANDLE_REDIRECT_START, exports.InteractionType.Redirect);
16282
16306
  let redirectResponse;
16283
16307
  if (useNative && this.nativeExtensionProvider) {
16284
16308
  this.logger.trace("handleRedirectPromise - acquiring token from native platform");
16285
- const nativeClient = new NativeInteractionClient(this.config, this.browserStorage, this.browserCrypto, this.logger, this.eventHandler, this.navigationClient, ApiId.handleRedirectPromise, this.performanceClient, this.nativeExtensionProvider, request.accountId, this.nativeInternalStorage, request.correlationId);
16309
+ const nativeClient = new NativeInteractionClient(this.config, this.browserStorage, this.browserCrypto, this.logger, this.eventHandler, this.navigationClient, ApiId.handleRedirectPromise, this.performanceClient, this.nativeExtensionProvider, platformBrokerRequest.accountId, this.nativeInternalStorage, platformBrokerRequest.correlationId);
16286
16310
  redirectResponse = invokeAsync(nativeClient.handleRedirectPromise.bind(nativeClient), PerformanceEvents.HandleNativeRedirectPromiseMeasurement, this.logger, this.performanceClient, rootMeasurement.event.correlationId)(this.performanceClient, rootMeasurement.event.correlationId);
16287
16311
  }
16288
16312
  else {
16313
+ const [standardRequest, codeVerifier] = this.browserStorage.getCachedRequest();
16314
+ const correlationId = standardRequest.correlationId;
16315
+ // Reset rootMeasurement now that we have correlationId
16316
+ rootMeasurement.discard();
16317
+ rootMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenRedirect, correlationId);
16289
16318
  this.logger.trace("handleRedirectPromise - acquiring token from web flow");
16290
16319
  const redirectClient = this.createRedirectClient(correlationId);
16291
- redirectResponse = invokeAsync(redirectClient.handleRedirectPromise.bind(redirectClient), PerformanceEvents.HandleRedirectPromiseMeasurement, this.logger, this.performanceClient, rootMeasurement.event.correlationId)(hash, rootMeasurement);
16320
+ redirectResponse = invokeAsync(redirectClient.handleRedirectPromise.bind(redirectClient), PerformanceEvents.HandleRedirectPromiseMeasurement, this.logger, this.performanceClient, rootMeasurement.event.correlationId)(hash, standardRequest, codeVerifier, rootMeasurement);
16292
16321
  }
16293
16322
  return redirectResponse
16294
16323
  .then((result) => {
16295
16324
  if (result) {
16325
+ this.browserStorage.resetRequestCache();
16296
16326
  // Emit login event if number of accounts change
16297
16327
  const isLoggingIn = loggedInAccounts.length < this.getAllAccounts().length;
16298
16328
  if (isLoggingIn) {
@@ -16324,6 +16354,7 @@ class StandardController {
16324
16354
  return result;
16325
16355
  })
16326
16356
  .catch((e) => {
16357
+ this.browserStorage.resetRequestCache();
16327
16358
  const eventError = e;
16328
16359
  // Emit login event if there is an account
16329
16360
  if (loggedInAccounts.length > 0) {
@@ -16417,7 +16448,6 @@ class StandardController {
16417
16448
  const redirectClient = this.createRedirectClient(correlationId);
16418
16449
  return redirectClient.acquireToken(request);
16419
16450
  }
16420
- this.browserStorage.setInteractionInProgress(false);
16421
16451
  throw e;
16422
16452
  });
16423
16453
  }
@@ -16428,6 +16458,7 @@ class StandardController {
16428
16458
  return await result;
16429
16459
  }
16430
16460
  catch (e) {
16461
+ this.browserStorage.resetRequestCache();
16431
16462
  atrMeasurement.end({ success: false }, e);
16432
16463
  if (isLoggedIn) {
16433
16464
  this.eventHandler.emitEvent(EventType.ACQUIRE_TOKEN_FAILURE, exports.InteractionType.Redirect, null, e);
@@ -16479,7 +16510,6 @@ class StandardController {
16479
16510
  correlationId,
16480
16511
  }, ApiId.acquireTokenPopup)
16481
16512
  .then((response) => {
16482
- this.browserStorage.setInteractionInProgress(false);
16483
16513
  atPopupMeasurement.end({
16484
16514
  success: true,
16485
16515
  isNativeBroker: true,
@@ -16499,7 +16529,6 @@ class StandardController {
16499
16529
  const popupClient = this.createPopupClient(correlationId);
16500
16530
  return popupClient.acquireToken(request, pkce);
16501
16531
  }
16502
- this.browserStorage.setInteractionInProgress(false);
16503
16532
  throw e;
16504
16533
  });
16505
16534
  }
@@ -16540,8 +16569,12 @@ class StandardController {
16540
16569
  // Since this function is syncronous we need to reject
16541
16570
  return Promise.reject(e);
16542
16571
  })
16543
- .finally(() => this.config.system.asyncPopups &&
16544
- this.preGeneratePkceCodes(correlationId));
16572
+ .finally(async () => {
16573
+ this.browserStorage.setInteractionInProgress(false);
16574
+ if (this.config.system.asyncPopups) {
16575
+ await this.preGeneratePkceCodes(correlationId);
16576
+ }
16577
+ });
16545
16578
  }
16546
16579
  trackPageVisibilityWithMeasurement() {
16547
16580
  const measurement = this.ssoSilentMeasurement ||
@@ -16844,7 +16877,9 @@ class StandardController {
16844
16877
  preflightCheck$1(this.initialized);
16845
16878
  this.browserStorage.setInteractionInProgress(true);
16846
16879
  const popupClient = this.createPopupClient(correlationId);
16847
- return popupClient.logout(logoutRequest);
16880
+ return popupClient.logout(logoutRequest).finally(() => {
16881
+ this.browserStorage.setInteractionInProgress(false);
16882
+ });
16848
16883
  }
16849
16884
  catch (e) {
16850
16885
  // Since this function is syncronous we need to reject
@@ -17260,9 +17295,7 @@ class StandardController {
17260
17295
  async acquireTokenSilentDeduped(request, account, correlationId) {
17261
17296
  const thumbprint = getRequestThumbprint(this.config.auth.clientId, {
17262
17297
  ...request,
17263
- authority: request.authority || this.config.auth.authority,
17264
- correlationId: correlationId,
17265
- }, account.homeAccountId);
17298
+ authority: request.authority || this.config.auth.authority}, account.homeAccountId);
17266
17299
  const silentRequestKey = JSON.stringify(thumbprint);
17267
17300
  const inProgressRequest = this.activeSilentTokenRequests.get(silentRequestKey);
17268
17301
  if (typeof inProgressRequest === "undefined") {