@azure/msal-browser 3.0.0-alpha.1 → 3.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +213 -213
  3. package/dist/app/IPublicClientApplication.d.ts +45 -45
  4. package/dist/app/IPublicClientApplication.js +96 -96
  5. package/dist/app/PublicClientApplication.d.ts +244 -244
  6. package/dist/app/PublicClientApplication.js +307 -307
  7. package/dist/broker/nativeBroker/NativeMessageHandler.d.ts +63 -63
  8. package/dist/broker/nativeBroker/NativeMessageHandler.js +255 -255
  9. package/dist/broker/nativeBroker/NativeRequest.d.ts +43 -43
  10. package/dist/broker/nativeBroker/NativeResponse.d.ts +48 -48
  11. package/dist/cache/AsyncMemoryStorage.d.ts +51 -51
  12. package/dist/cache/AsyncMemoryStorage.js +132 -132
  13. package/dist/cache/BrowserCacheManager.d.ts +376 -377
  14. package/dist/cache/BrowserCacheManager.d.ts.map +1 -1
  15. package/dist/cache/BrowserCacheManager.js +1275 -1276
  16. package/dist/cache/BrowserCacheManager.js.map +1 -1
  17. package/dist/cache/BrowserStorage.d.ts +11 -11
  18. package/dist/cache/BrowserStorage.js +35 -35
  19. package/dist/cache/CryptoKeyStore.d.ts +18 -17
  20. package/dist/cache/CryptoKeyStore.d.ts.map +1 -1
  21. package/dist/cache/CryptoKeyStore.js +40 -41
  22. package/dist/cache/CryptoKeyStore.js.map +1 -1
  23. package/dist/cache/DatabaseStorage.d.ts +56 -56
  24. package/dist/cache/DatabaseStorage.js +190 -190
  25. package/dist/cache/IAsyncMemoryStorage.d.ts +27 -27
  26. package/dist/cache/ITokenCache.d.ts +10 -10
  27. package/dist/cache/IWindowStorage.d.ts +27 -27
  28. package/dist/cache/MemoryStorage.d.ts +11 -11
  29. package/dist/cache/MemoryStorage.js +31 -31
  30. package/dist/cache/TokenCache.d.ts +76 -76
  31. package/dist/cache/TokenCache.js +225 -225
  32. package/dist/config/Configuration.d.ts +187 -203
  33. package/dist/config/Configuration.d.ts.map +1 -1
  34. package/dist/config/Configuration.js +97 -101
  35. package/dist/config/Configuration.js.map +1 -1
  36. package/dist/controllers/ControllerFactory.d.ts +9 -9
  37. package/dist/controllers/ControllerFactory.js +37 -37
  38. package/dist/controllers/IController.d.ts +66 -66
  39. package/dist/controllers/IController.d.ts.map +1 -1
  40. package/dist/controllers/StandardController.d.ts +413 -413
  41. package/dist/controllers/StandardController.d.ts.map +1 -1
  42. package/dist/controllers/StandardController.js +1277 -1272
  43. package/dist/controllers/StandardController.js.map +1 -1
  44. package/dist/crypto/BrowserCrypto.d.ts +49 -61
  45. package/dist/crypto/BrowserCrypto.d.ts.map +1 -1
  46. package/dist/crypto/BrowserCrypto.js +93 -134
  47. package/dist/crypto/BrowserCrypto.js.map +1 -1
  48. package/dist/crypto/CryptoOps.d.ts +72 -73
  49. package/dist/crypto/CryptoOps.d.ts.map +1 -1
  50. package/dist/crypto/CryptoOps.js +150 -150
  51. package/dist/crypto/CryptoOps.js.map +1 -1
  52. package/dist/crypto/GuidGenerator.d.ts +12 -12
  53. package/dist/crypto/GuidGenerator.js +96 -96
  54. package/dist/crypto/ISubtleCrypto.d.ts +9 -9
  55. package/dist/crypto/ModernBrowserCrypto.d.ts +9 -9
  56. package/dist/crypto/ModernBrowserCrypto.js +24 -24
  57. package/dist/crypto/PkceGenerator.d.ts +24 -24
  58. package/dist/crypto/PkceGenerator.js +58 -58
  59. package/dist/crypto/SignedHttpRequest.d.ts +30 -30
  60. package/dist/crypto/SignedHttpRequest.js +39 -39
  61. package/dist/encode/Base64Decode.d.ts +22 -22
  62. package/dist/encode/Base64Decode.js +73 -73
  63. package/dist/encode/Base64Encode.d.ts +31 -31
  64. package/dist/encode/Base64Encode.js +79 -79
  65. package/dist/error/BrowserAuthError.d.ts +382 -382
  66. package/dist/error/BrowserAuthError.js +483 -483
  67. package/dist/error/BrowserConfigurationAuthError.d.ts +70 -70
  68. package/dist/error/BrowserConfigurationAuthError.js +96 -96
  69. package/dist/error/NativeAuthError.d.ts +57 -56
  70. package/dist/error/NativeAuthError.d.ts.map +1 -1
  71. package/dist/error/NativeAuthError.js +93 -88
  72. package/dist/error/NativeAuthError.js.map +1 -1
  73. package/dist/event/EventHandler.d.ts +41 -41
  74. package/dist/event/EventHandler.js +119 -119
  75. package/dist/event/EventMessage.d.ts +25 -25
  76. package/dist/event/EventMessage.d.ts.map +1 -1
  77. package/dist/event/EventMessage.js +68 -67
  78. package/dist/event/EventMessage.js.map +1 -1
  79. package/dist/event/EventType.d.ts +28 -26
  80. package/dist/event/EventType.d.ts.map +1 -1
  81. package/dist/event/EventType.js +32 -32
  82. package/dist/event/EventType.js.map +1 -1
  83. package/dist/index.d.ts +35 -35
  84. package/dist/index.js +1 -1
  85. package/dist/interaction_client/BaseInteractionClient.d.ts +53 -52
  86. package/dist/interaction_client/BaseInteractionClient.d.ts.map +1 -1
  87. package/dist/interaction_client/BaseInteractionClient.js +151 -138
  88. package/dist/interaction_client/BaseInteractionClient.js.map +1 -1
  89. package/dist/interaction_client/HybridSpaAuthorizationCodeClient.d.ts +4 -4
  90. package/dist/interaction_client/HybridSpaAuthorizationCodeClient.js +10 -10
  91. package/dist/interaction_client/NativeInteractionClient.d.ts +148 -148
  92. package/dist/interaction_client/NativeInteractionClient.d.ts.map +1 -1
  93. package/dist/interaction_client/NativeInteractionClient.js +521 -517
  94. package/dist/interaction_client/NativeInteractionClient.js.map +1 -1
  95. package/dist/interaction_client/PopupClient.d.ts +111 -111
  96. package/dist/interaction_client/PopupClient.js +476 -476
  97. package/dist/interaction_client/RedirectClient.d.ts +48 -48
  98. package/dist/interaction_client/RedirectClient.d.ts.map +1 -1
  99. package/dist/interaction_client/RedirectClient.js +291 -290
  100. package/dist/interaction_client/RedirectClient.js.map +1 -1
  101. package/dist/interaction_client/SilentAuthCodeClient.d.ts +22 -22
  102. package/dist/interaction_client/SilentAuthCodeClient.js +62 -62
  103. package/dist/interaction_client/SilentCacheClient.d.ts +21 -21
  104. package/dist/interaction_client/SilentCacheClient.js +67 -67
  105. package/dist/interaction_client/SilentCacheClient.js.map +1 -1
  106. package/dist/interaction_client/SilentIframeClient.d.ts +31 -31
  107. package/dist/interaction_client/SilentIframeClient.js +127 -127
  108. package/dist/interaction_client/SilentRefreshClient.d.ts +19 -19
  109. package/dist/interaction_client/SilentRefreshClient.js +62 -62
  110. package/dist/interaction_client/SilentRefreshClient.js.map +1 -1
  111. package/dist/interaction_client/StandardInteractionClient.d.ts +59 -59
  112. package/dist/interaction_client/StandardInteractionClient.js +259 -259
  113. package/dist/interaction_handler/InteractionHandler.d.ts +39 -39
  114. package/dist/interaction_handler/InteractionHandler.js +127 -127
  115. package/dist/interaction_handler/RedirectHandler.d.ts +24 -24
  116. package/dist/interaction_handler/RedirectHandler.js +118 -118
  117. package/dist/interaction_handler/SilentHandler.d.ts +47 -47
  118. package/dist/interaction_handler/SilentHandler.js +162 -162
  119. package/dist/internals.d.ts +23 -23
  120. package/dist/internals.js +4 -4
  121. package/dist/navigation/INavigationClient.d.ts +16 -16
  122. package/dist/navigation/NavigationClient.d.ts +22 -22
  123. package/dist/navigation/NavigationClient.js +40 -40
  124. package/dist/navigation/NavigationOptions.d.ts +12 -12
  125. package/dist/network/FetchClient.d.ts +26 -26
  126. package/dist/network/FetchClient.js +99 -99
  127. package/dist/network/XhrClient.d.ts +40 -40
  128. package/dist/network/XhrClient.js +117 -117
  129. package/dist/operatingcontext/BaseOperatingContext.d.ts +40 -40
  130. package/dist/operatingcontext/BaseOperatingContext.js +44 -44
  131. package/dist/operatingcontext/StandardOperatingContext.d.ts +25 -25
  132. package/dist/operatingcontext/StandardOperatingContext.js +43 -43
  133. package/dist/operatingcontext/TeamsAppOperatingContext.d.ts +25 -25
  134. package/dist/operatingcontext/TeamsAppOperatingContext.js +42 -42
  135. package/dist/packageMetadata.d.ts +2 -2
  136. package/dist/packageMetadata.d.ts.map +1 -1
  137. package/dist/packageMetadata.js +4 -4
  138. package/dist/request/AuthorizationCodeRequest.d.ts +8 -8
  139. package/dist/request/AuthorizationUrlRequest.d.ts +8 -8
  140. package/dist/request/EndSessionPopupRequest.d.ts +18 -18
  141. package/dist/request/EndSessionRequest.d.ts +15 -15
  142. package/dist/request/PopupRequest.d.ts +32 -32
  143. package/dist/request/PopupWindowAttributes.d.ts +15 -15
  144. package/dist/request/RedirectRequest.d.ts +33 -33
  145. package/dist/request/SilentRequest.d.ts +30 -30
  146. package/dist/request/SsoSilentRequest.d.ts +26 -26
  147. package/dist/telemetry/BrowserPerformanceClient.d.ts +37 -38
  148. package/dist/telemetry/BrowserPerformanceClient.d.ts.map +1 -1
  149. package/dist/telemetry/BrowserPerformanceClient.js +124 -124
  150. package/dist/telemetry/BrowserPerformanceClient.js.map +1 -1
  151. package/dist/telemetry/BrowserPerformanceMeasurement.d.ts +21 -21
  152. package/dist/telemetry/BrowserPerformanceMeasurement.js +92 -92
  153. package/dist/utils/BrowserConstants.d.ts +176 -166
  154. package/dist/utils/BrowserConstants.d.ts.map +1 -1
  155. package/dist/utils/BrowserConstants.js +205 -215
  156. package/dist/utils/BrowserConstants.js.map +1 -1
  157. package/dist/utils/BrowserProtocolUtils.d.ts +18 -18
  158. package/dist/utils/BrowserProtocolUtils.js +34 -34
  159. package/dist/utils/BrowserStringUtils.d.ts +26 -26
  160. package/dist/utils/BrowserStringUtils.js +149 -149
  161. package/dist/utils/BrowserUtils.d.ts +65 -65
  162. package/dist/utils/BrowserUtils.js +138 -138
  163. package/dist/utils/MathUtils.d.ts +11 -11
  164. package/dist/utils/MathUtils.js +21 -21
  165. package/lib/msal-browser.cjs.js +18227 -0
  166. package/lib/msal-browser.cjs.js.map +1 -0
  167. package/lib/msal-browser.js +18233 -0
  168. package/lib/msal-browser.js.map +1 -0
  169. package/lib/msal-browser.min.js +63 -0
  170. package/package.json +101 -95
  171. package/dist/crypto/MsBrowserCrypto.d.ts +0 -10
  172. package/dist/crypto/MsBrowserCrypto.d.ts.map +0 -1
  173. package/dist/crypto/MsBrowserCrypto.js +0 -88
  174. package/dist/crypto/MsBrowserCrypto.js.map +0 -1
  175. package/dist/crypto/MsrBrowserCrypto.d.ts +0 -18
  176. package/dist/crypto/MsrBrowserCrypto.d.ts.map +0 -1
  177. package/dist/crypto/MsrBrowserCrypto.js +0 -35
  178. package/dist/crypto/MsrBrowserCrypto.js.map +0 -1
@@ -1,4 +1,4 @@
1
- /*! @azure/msal-browser v3.0.0-alpha.1 2023-05-08 */
1
+ /*! @azure/msal-browser v3.0.0-beta.0 2023-06-19 */
2
2
  'use strict';
3
3
  import { PerformanceEvents, Constants, AuthError, UrlString, ProtocolUtils, ThrottlingUtils } from '@azure/msal-common';
4
4
  import { StandardInteractionClient } from './StandardInteractionClient.js';
@@ -10,295 +10,296 @@ import { BrowserAuthError } from '../error/BrowserAuthError.js';
10
10
  import { NativeInteractionClient } from './NativeInteractionClient.js';
11
11
  import { NativeMessageHandler } from '../broker/nativeBroker/NativeMessageHandler.js';
12
12
 
13
- /*
14
- * Copyright (c) Microsoft Corporation. All rights reserved.
15
- * Licensed under the MIT License.
16
- */
17
- class RedirectClient extends StandardInteractionClient {
18
- constructor(config, storageImpl, browserCrypto, logger, eventHandler, navigationClient, performanceClient, nativeStorageImpl, nativeMessageHandler, correlationId) {
19
- super(config, storageImpl, browserCrypto, logger, eventHandler, navigationClient, performanceClient, nativeMessageHandler, correlationId);
20
- this.nativeStorage = nativeStorageImpl;
21
- }
22
- /**
23
- * Redirects the page to the /authorize endpoint of the IDP
24
- * @param request
25
- */
26
- async acquireToken(request) {
27
- this.performanceClient.setPreQueueTime(PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, request.correlationId);
28
- const validRequest = await this.initializeAuthorizationRequest(request, InteractionType.Redirect);
29
- this.browserStorage.updateCacheEntries(validRequest.state, validRequest.nonce, validRequest.authority, validRequest.loginHint || Constants.EMPTY_STRING, validRequest.account || null);
30
- const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenRedirect);
31
- const handleBackButton = (event) => {
32
- // Clear temporary cache if the back button is clicked during the redirect flow.
33
- if (event.persisted) {
34
- this.logger.verbose("Page was restored from back/forward cache. Clearing temporary cache.");
35
- this.browserStorage.cleanRequestByState(validRequest.state);
36
- }
37
- };
38
- try {
39
- // Create auth code request and generate PKCE params
40
- this.performanceClient.setPreQueueTime(PerformanceEvents.StandardInteractionClientInitializeAuthorizationCodeRequest, request.correlationId);
41
- const authCodeRequest = await this.initializeAuthorizationCodeRequest(validRequest);
42
- // Initialize the client
43
- this.performanceClient.setPreQueueTime(PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, request.correlationId);
44
- const authClient = await this.createAuthCodeClient(serverTelemetryManager, validRequest.authority, validRequest.azureCloudOptions);
45
- this.logger.verbose("Auth code client created");
46
- // Create redirect interaction handler.
47
- const interactionHandler = new RedirectHandler(authClient, this.browserStorage, authCodeRequest, this.logger, this.browserCrypto, this.performanceClient);
48
- // Create acquire token url.
49
- const navigateUrl = await authClient.getAuthCodeUrl({
50
- ...validRequest,
51
- nativeBroker: NativeMessageHandler.isNativeAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme),
52
- });
53
- const redirectStartPage = this.getRedirectStartPage(request.redirectStartPage);
54
- this.logger.verbosePii(`Redirect start page: ${redirectStartPage}`);
55
- // Clear temporary cache if the back button is clicked during the redirect flow.
56
- window.addEventListener("pageshow", handleBackButton);
57
- // Show the UI once the url has been created. Response will come back in the hash, which will be handled in the handleRedirectCallback function.
58
- return await interactionHandler.initiateAuthRequest(navigateUrl, {
59
- navigationClient: this.navigationClient,
60
- redirectTimeout: this.config.system.redirectNavigationTimeout,
61
- redirectStartPage: redirectStartPage,
62
- onRedirectNavigate: request.onRedirectNavigate,
63
- });
64
- }
65
- catch (e) {
66
- if (e instanceof AuthError) {
67
- e.setCorrelationId(this.correlationId);
68
- serverTelemetryManager.cacheFailedRequest(e);
69
- }
70
- window.removeEventListener("pageshow", handleBackButton);
71
- this.browserStorage.cleanRequestByState(validRequest.state);
72
- throw e;
73
- }
74
- }
75
- /**
76
- * Checks if navigateToLoginRequestUrl is set, and:
77
- * - if true, performs logic to cache and navigate
78
- * - if false, handles hash string and parses response
79
- * @param hash
80
- */
81
- async handleRedirectPromise(hash) {
82
- const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.handleRedirectPromise);
83
- try {
84
- if (!this.browserStorage.isInteractionInProgress(true)) {
85
- this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
86
- return null;
87
- }
88
- const responseHash = this.getRedirectResponseHash(hash || window.location.hash);
89
- if (!responseHash) {
90
- // Not a recognized server response hash or hash not associated with a redirect request
91
- this.logger.info("handleRedirectPromise did not detect a response hash as a result of a redirect. Cleaning temporary cache.");
92
- this.browserStorage.cleanRequestByInteractionType(InteractionType.Redirect);
93
- return null;
94
- }
95
- let state;
96
- try {
97
- // Deserialize hash fragment response parameters.
98
- const serverParams = UrlString.getDeserializedHash(responseHash);
99
- state = this.validateAndExtractStateFromHash(serverParams, InteractionType.Redirect);
100
- this.logger.verbose("State extracted from hash");
101
- }
102
- catch (e) {
103
- this.logger.info(`handleRedirectPromise was unable to extract state due to: ${e}`);
104
- this.browserStorage.cleanRequestByInteractionType(InteractionType.Redirect);
105
- return null;
106
- }
107
- // If navigateToLoginRequestUrl is true, get the url where the redirect request was initiated
108
- const loginRequestUrl = this.browserStorage.getTemporaryCache(TemporaryCacheKeys.ORIGIN_URI, true) || Constants.EMPTY_STRING;
109
- const loginRequestUrlNormalized = UrlString.removeHashFromUrl(loginRequestUrl);
110
- const currentUrlNormalized = UrlString.removeHashFromUrl(window.location.href);
111
- if (loginRequestUrlNormalized === currentUrlNormalized &&
112
- this.config.auth.navigateToLoginRequestUrl) {
113
- // We are on the page we need to navigate to - handle hash
114
- this.logger.verbose("Current page is loginRequestUrl, handling hash");
115
- const handleHashResult = await this.handleHash(responseHash, state, serverTelemetryManager);
116
- if (loginRequestUrl.indexOf("#") > -1) {
117
- // Replace current hash with non-msal hash, if present
118
- BrowserUtils.replaceHash(loginRequestUrl);
119
- }
120
- return handleHashResult;
121
- }
122
- else if (!this.config.auth.navigateToLoginRequestUrl) {
123
- this.logger.verbose("NavigateToLoginRequestUrl set to false, handling hash");
124
- return this.handleHash(responseHash, state, serverTelemetryManager);
125
- }
126
- else if (!BrowserUtils.isInIframe() ||
127
- this.config.system.allowRedirectInIframe) {
128
- /*
129
- * Returned from authority using redirect - need to perform navigation before processing response
130
- * Cache the hash to be retrieved after the next redirect
131
- */
132
- this.browserStorage.setTemporaryCache(TemporaryCacheKeys.URL_HASH, responseHash, true);
133
- const navigationOptions = {
134
- apiId: ApiId.handleRedirectPromise,
135
- timeout: this.config.system.redirectNavigationTimeout,
136
- noHistory: true,
137
- };
138
- /**
139
- * Default behavior is to redirect to the start page and not process the hash now.
140
- * The start page is expected to also call handleRedirectPromise which will process the hash in one of the checks above.
141
- */
142
- let processHashOnRedirect = true;
143
- if (!loginRequestUrl || loginRequestUrl === "null") {
144
- // Redirect to home page if login request url is null (real null or the string null)
145
- const homepage = BrowserUtils.getHomepage();
146
- // Cache the homepage under ORIGIN_URI to ensure cached hash is processed on homepage
147
- this.browserStorage.setTemporaryCache(TemporaryCacheKeys.ORIGIN_URI, homepage, true);
148
- this.logger.warning("Unable to get valid login request url from cache, redirecting to home page");
149
- processHashOnRedirect =
150
- await this.navigationClient.navigateInternal(homepage, navigationOptions);
151
- }
152
- else {
153
- // Navigate to page that initiated the redirect request
154
- this.logger.verbose(`Navigating to loginRequestUrl: ${loginRequestUrl}`);
155
- processHashOnRedirect =
156
- await this.navigationClient.navigateInternal(loginRequestUrl, navigationOptions);
157
- }
158
- // If navigateInternal implementation returns false, handle the hash now
159
- if (!processHashOnRedirect) {
160
- return this.handleHash(responseHash, state, serverTelemetryManager);
161
- }
162
- }
163
- return null;
164
- }
165
- catch (e) {
166
- if (e instanceof AuthError) {
167
- e.setCorrelationId(this.correlationId);
168
- serverTelemetryManager.cacheFailedRequest(e);
169
- }
170
- this.browserStorage.cleanRequestByInteractionType(InteractionType.Redirect);
171
- throw e;
172
- }
173
- }
174
- /**
175
- * Gets the response hash for a redirect request
176
- * Returns null if interactionType in the state value is not "redirect" or the hash does not contain known properties
177
- * @param hash
178
- */
179
- getRedirectResponseHash(hash) {
180
- this.logger.verbose("getRedirectResponseHash called");
181
- // Get current location hash from window or cache.
182
- const isResponseHash = UrlString.hashContainsKnownProperties(hash);
183
- if (isResponseHash) {
184
- BrowserUtils.clearHash(window);
185
- this.logger.verbose("Hash contains known properties, returning response hash");
186
- return hash;
187
- }
188
- const cachedHash = this.browserStorage.getTemporaryCache(TemporaryCacheKeys.URL_HASH, true);
189
- this.browserStorage.removeItem(this.browserStorage.generateCacheKey(TemporaryCacheKeys.URL_HASH));
190
- this.logger.verbose("Hash does not contain known properties, returning cached hash");
191
- return cachedHash;
192
- }
193
- /**
194
- * Checks if hash exists and handles in window.
195
- * @param hash
196
- * @param state
197
- */
198
- async handleHash(hash, state, serverTelemetryManager) {
199
- const cachedRequest = this.browserStorage.getCachedRequest(state, this.browserCrypto);
200
- this.logger.verbose("handleHash called, retrieved cached request");
201
- const serverParams = UrlString.getDeserializedHash(hash);
202
- if (serverParams.accountId) {
203
- this.logger.verbose("Account id found in hash, calling WAM for token");
204
- if (!this.nativeMessageHandler) {
205
- throw BrowserAuthError.createNativeConnectionNotEstablishedError();
206
- }
207
- 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.browserStorage, cachedRequest.correlationId);
208
- const { userRequestState } = ProtocolUtils.parseRequestState(this.browserCrypto, state);
209
- return nativeInteractionClient
210
- .acquireToken({
211
- ...cachedRequest,
212
- state: userRequestState,
213
- prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
214
- })
215
- .finally(() => {
216
- this.browserStorage.cleanRequestByState(state);
217
- });
218
- }
219
- // Hash contains known properties - handle and return in callback
220
- const currentAuthority = this.browserStorage.getCachedAuthority(state);
221
- if (!currentAuthority) {
222
- throw BrowserAuthError.createNoCachedAuthorityError();
223
- }
224
- this.performanceClient.setPreQueueTime(PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, cachedRequest.correlationId);
225
- const authClient = await this.createAuthCodeClient(serverTelemetryManager, currentAuthority);
226
- this.logger.verbose("Auth code client created");
227
- ThrottlingUtils.removeThrottle(this.browserStorage, this.config.auth.clientId, cachedRequest);
228
- const interactionHandler = new RedirectHandler(authClient, this.browserStorage, cachedRequest, this.logger, this.browserCrypto, this.performanceClient);
229
- return await interactionHandler.handleCodeResponseFromHash(hash, state, authClient.authority, this.networkClient);
230
- }
231
- /**
232
- * Use to log out the current user, and redirect the user to the postLogoutRedirectUri.
233
- * Default behaviour is to redirect the user to `window.location.href`.
234
- * @param logoutRequest
235
- */
236
- async logout(logoutRequest) {
237
- this.logger.verbose("logoutRedirect called");
238
- const validLogoutRequest = this.initializeLogoutRequest(logoutRequest);
239
- const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.logout);
240
- try {
241
- this.eventHandler.emitEvent(EventType.LOGOUT_START, InteractionType.Redirect, logoutRequest);
242
- // Clear cache on logout
243
- await this.clearCacheOnLogout(validLogoutRequest.account);
244
- const navigationOptions = {
245
- apiId: ApiId.logout,
246
- timeout: this.config.system.redirectNavigationTimeout,
247
- noHistory: false,
248
- };
249
- this.performanceClient.setPreQueueTime(PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, validLogoutRequest.correlationId);
250
- const authClient = await this.createAuthCodeClient(serverTelemetryManager, logoutRequest && logoutRequest.authority);
251
- this.logger.verbose("Auth code client created");
252
- // Create logout string and navigate user window to logout.
253
- const logoutUri = authClient.getLogoutUri(validLogoutRequest);
254
- this.eventHandler.emitEvent(EventType.LOGOUT_SUCCESS, InteractionType.Redirect, validLogoutRequest);
255
- // Check if onRedirectNavigate is implemented, and invoke it if so
256
- if (logoutRequest &&
257
- typeof logoutRequest.onRedirectNavigate === "function") {
258
- const navigate = logoutRequest.onRedirectNavigate(logoutUri);
259
- if (navigate !== false) {
260
- this.logger.verbose("Logout onRedirectNavigate did not return false, navigating");
261
- // Ensure interaction is in progress
262
- if (!this.browserStorage.getInteractionInProgress()) {
263
- this.browserStorage.setInteractionInProgress(true);
264
- }
265
- await this.navigationClient.navigateExternal(logoutUri, navigationOptions);
266
- return;
267
- }
268
- else {
269
- // Ensure interaction is not in progress
270
- this.browserStorage.setInteractionInProgress(false);
271
- this.logger.verbose("Logout onRedirectNavigate returned false, stopping navigation");
272
- }
273
- }
274
- else {
275
- // Ensure interaction is in progress
276
- if (!this.browserStorage.getInteractionInProgress()) {
277
- this.browserStorage.setInteractionInProgress(true);
278
- }
279
- await this.navigationClient.navigateExternal(logoutUri, navigationOptions);
280
- return;
281
- }
282
- }
283
- catch (e) {
284
- if (e instanceof AuthError) {
285
- e.setCorrelationId(this.correlationId);
286
- serverTelemetryManager.cacheFailedRequest(e);
287
- }
288
- this.eventHandler.emitEvent(EventType.LOGOUT_FAILURE, InteractionType.Redirect, null, e);
289
- this.eventHandler.emitEvent(EventType.LOGOUT_END, InteractionType.Redirect);
290
- throw e;
291
- }
292
- this.eventHandler.emitEvent(EventType.LOGOUT_END, InteractionType.Redirect);
293
- }
294
- /**
295
- * Use to get the redirectStartPage either from request or use current window
296
- * @param requestStartPage
297
- */
298
- getRedirectStartPage(requestStartPage) {
299
- const redirectStartPage = requestStartPage || window.location.href;
300
- return UrlString.getAbsoluteUrl(redirectStartPage, BrowserUtils.getCurrentUri());
301
- }
13
+ /*
14
+ * Copyright (c) Microsoft Corporation. All rights reserved.
15
+ * Licensed under the MIT License.
16
+ */
17
+ class RedirectClient extends StandardInteractionClient {
18
+ constructor(config, storageImpl, browserCrypto, logger, eventHandler, navigationClient, performanceClient, nativeStorageImpl, nativeMessageHandler, correlationId) {
19
+ super(config, storageImpl, browserCrypto, logger, eventHandler, navigationClient, performanceClient, nativeMessageHandler, correlationId);
20
+ this.nativeStorage = nativeStorageImpl;
21
+ }
22
+ /**
23
+ * Redirects the page to the /authorize endpoint of the IDP
24
+ * @param request
25
+ */
26
+ async acquireToken(request) {
27
+ this.performanceClient.setPreQueueTime(PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, request.correlationId);
28
+ const validRequest = await this.initializeAuthorizationRequest(request, InteractionType.Redirect);
29
+ this.browserStorage.updateCacheEntries(validRequest.state, validRequest.nonce, validRequest.authority, validRequest.loginHint || Constants.EMPTY_STRING, validRequest.account || null);
30
+ const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenRedirect);
31
+ const handleBackButton = (event) => {
32
+ // Clear temporary cache if the back button is clicked during the redirect flow.
33
+ if (event.persisted) {
34
+ this.logger.verbose("Page was restored from back/forward cache. Clearing temporary cache.");
35
+ this.browserStorage.cleanRequestByState(validRequest.state);
36
+ this.eventHandler.emitEvent(EventType.RESTORE_FROM_BFCACHE, InteractionType.Redirect);
37
+ }
38
+ };
39
+ try {
40
+ // Create auth code request and generate PKCE params
41
+ this.performanceClient.setPreQueueTime(PerformanceEvents.StandardInteractionClientInitializeAuthorizationCodeRequest, request.correlationId);
42
+ const authCodeRequest = await this.initializeAuthorizationCodeRequest(validRequest);
43
+ // Initialize the client
44
+ this.performanceClient.setPreQueueTime(PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, request.correlationId);
45
+ const authClient = await this.createAuthCodeClient(serverTelemetryManager, validRequest.authority, validRequest.azureCloudOptions);
46
+ this.logger.verbose("Auth code client created");
47
+ // Create redirect interaction handler.
48
+ const interactionHandler = new RedirectHandler(authClient, this.browserStorage, authCodeRequest, this.logger, this.browserCrypto, this.performanceClient);
49
+ // Create acquire token url.
50
+ const navigateUrl = await authClient.getAuthCodeUrl({
51
+ ...validRequest,
52
+ nativeBroker: NativeMessageHandler.isNativeAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme),
53
+ });
54
+ const redirectStartPage = this.getRedirectStartPage(request.redirectStartPage);
55
+ this.logger.verbosePii(`Redirect start page: ${redirectStartPage}`);
56
+ // Clear temporary cache if the back button is clicked during the redirect flow.
57
+ window.addEventListener("pageshow", handleBackButton);
58
+ // Show the UI once the url has been created. Response will come back in the hash, which will be handled in the handleRedirectCallback function.
59
+ return await interactionHandler.initiateAuthRequest(navigateUrl, {
60
+ navigationClient: this.navigationClient,
61
+ redirectTimeout: this.config.system.redirectNavigationTimeout,
62
+ redirectStartPage: redirectStartPage,
63
+ onRedirectNavigate: request.onRedirectNavigate,
64
+ });
65
+ }
66
+ catch (e) {
67
+ if (e instanceof AuthError) {
68
+ e.setCorrelationId(this.correlationId);
69
+ serverTelemetryManager.cacheFailedRequest(e);
70
+ }
71
+ window.removeEventListener("pageshow", handleBackButton);
72
+ this.browserStorage.cleanRequestByState(validRequest.state);
73
+ throw e;
74
+ }
75
+ }
76
+ /**
77
+ * Checks if navigateToLoginRequestUrl is set, and:
78
+ * - if true, performs logic to cache and navigate
79
+ * - if false, handles hash string and parses response
80
+ * @param hash
81
+ */
82
+ async handleRedirectPromise(hash) {
83
+ const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.handleRedirectPromise);
84
+ try {
85
+ if (!this.browserStorage.isInteractionInProgress(true)) {
86
+ this.logger.info("handleRedirectPromise called but there is no interaction in progress, returning null.");
87
+ return null;
88
+ }
89
+ const responseHash = this.getRedirectResponseHash(hash || window.location.hash);
90
+ if (!responseHash) {
91
+ // Not a recognized server response hash or hash not associated with a redirect request
92
+ this.logger.info("handleRedirectPromise did not detect a response hash as a result of a redirect. Cleaning temporary cache.");
93
+ this.browserStorage.cleanRequestByInteractionType(InteractionType.Redirect);
94
+ return null;
95
+ }
96
+ let state;
97
+ try {
98
+ // Deserialize hash fragment response parameters.
99
+ const serverParams = UrlString.getDeserializedHash(responseHash);
100
+ state = this.validateAndExtractStateFromHash(serverParams, InteractionType.Redirect);
101
+ this.logger.verbose("State extracted from hash");
102
+ }
103
+ catch (e) {
104
+ this.logger.info(`handleRedirectPromise was unable to extract state due to: ${e}`);
105
+ this.browserStorage.cleanRequestByInteractionType(InteractionType.Redirect);
106
+ return null;
107
+ }
108
+ // If navigateToLoginRequestUrl is true, get the url where the redirect request was initiated
109
+ const loginRequestUrl = this.browserStorage.getTemporaryCache(TemporaryCacheKeys.ORIGIN_URI, true) || Constants.EMPTY_STRING;
110
+ const loginRequestUrlNormalized = UrlString.removeHashFromUrl(loginRequestUrl);
111
+ const currentUrlNormalized = UrlString.removeHashFromUrl(window.location.href);
112
+ if (loginRequestUrlNormalized === currentUrlNormalized &&
113
+ this.config.auth.navigateToLoginRequestUrl) {
114
+ // We are on the page we need to navigate to - handle hash
115
+ this.logger.verbose("Current page is loginRequestUrl, handling hash");
116
+ const handleHashResult = await this.handleHash(responseHash, state, serverTelemetryManager);
117
+ if (loginRequestUrl.indexOf("#") > -1) {
118
+ // Replace current hash with non-msal hash, if present
119
+ BrowserUtils.replaceHash(loginRequestUrl);
120
+ }
121
+ return handleHashResult;
122
+ }
123
+ else if (!this.config.auth.navigateToLoginRequestUrl) {
124
+ this.logger.verbose("NavigateToLoginRequestUrl set to false, handling hash");
125
+ return this.handleHash(responseHash, state, serverTelemetryManager);
126
+ }
127
+ else if (!BrowserUtils.isInIframe() ||
128
+ this.config.system.allowRedirectInIframe) {
129
+ /*
130
+ * Returned from authority using redirect - need to perform navigation before processing response
131
+ * Cache the hash to be retrieved after the next redirect
132
+ */
133
+ this.browserStorage.setTemporaryCache(TemporaryCacheKeys.URL_HASH, responseHash, true);
134
+ const navigationOptions = {
135
+ apiId: ApiId.handleRedirectPromise,
136
+ timeout: this.config.system.redirectNavigationTimeout,
137
+ noHistory: true,
138
+ };
139
+ /**
140
+ * Default behavior is to redirect to the start page and not process the hash now.
141
+ * The start page is expected to also call handleRedirectPromise which will process the hash in one of the checks above.
142
+ */
143
+ let processHashOnRedirect = true;
144
+ if (!loginRequestUrl || loginRequestUrl === "null") {
145
+ // Redirect to home page if login request url is null (real null or the string null)
146
+ const homepage = BrowserUtils.getHomepage();
147
+ // Cache the homepage under ORIGIN_URI to ensure cached hash is processed on homepage
148
+ this.browserStorage.setTemporaryCache(TemporaryCacheKeys.ORIGIN_URI, homepage, true);
149
+ this.logger.warning("Unable to get valid login request url from cache, redirecting to home page");
150
+ processHashOnRedirect =
151
+ await this.navigationClient.navigateInternal(homepage, navigationOptions);
152
+ }
153
+ else {
154
+ // Navigate to page that initiated the redirect request
155
+ this.logger.verbose(`Navigating to loginRequestUrl: ${loginRequestUrl}`);
156
+ processHashOnRedirect =
157
+ await this.navigationClient.navigateInternal(loginRequestUrl, navigationOptions);
158
+ }
159
+ // If navigateInternal implementation returns false, handle the hash now
160
+ if (!processHashOnRedirect) {
161
+ return this.handleHash(responseHash, state, serverTelemetryManager);
162
+ }
163
+ }
164
+ return null;
165
+ }
166
+ catch (e) {
167
+ if (e instanceof AuthError) {
168
+ e.setCorrelationId(this.correlationId);
169
+ serverTelemetryManager.cacheFailedRequest(e);
170
+ }
171
+ this.browserStorage.cleanRequestByInteractionType(InteractionType.Redirect);
172
+ throw e;
173
+ }
174
+ }
175
+ /**
176
+ * Gets the response hash for a redirect request
177
+ * Returns null if interactionType in the state value is not "redirect" or the hash does not contain known properties
178
+ * @param hash
179
+ */
180
+ getRedirectResponseHash(hash) {
181
+ this.logger.verbose("getRedirectResponseHash called");
182
+ // Get current location hash from window or cache.
183
+ const isResponseHash = UrlString.hashContainsKnownProperties(hash);
184
+ if (isResponseHash) {
185
+ BrowserUtils.clearHash(window);
186
+ this.logger.verbose("Hash contains known properties, returning response hash");
187
+ return hash;
188
+ }
189
+ const cachedHash = this.browserStorage.getTemporaryCache(TemporaryCacheKeys.URL_HASH, true);
190
+ this.browserStorage.removeItem(this.browserStorage.generateCacheKey(TemporaryCacheKeys.URL_HASH));
191
+ this.logger.verbose("Hash does not contain known properties, returning cached hash");
192
+ return cachedHash;
193
+ }
194
+ /**
195
+ * Checks if hash exists and handles in window.
196
+ * @param hash
197
+ * @param state
198
+ */
199
+ async handleHash(hash, state, serverTelemetryManager) {
200
+ const cachedRequest = this.browserStorage.getCachedRequest(state, this.browserCrypto);
201
+ this.logger.verbose("handleHash called, retrieved cached request");
202
+ const serverParams = UrlString.getDeserializedHash(hash);
203
+ if (serverParams.accountId) {
204
+ this.logger.verbose("Account id found in hash, calling WAM for token");
205
+ if (!this.nativeMessageHandler) {
206
+ throw BrowserAuthError.createNativeConnectionNotEstablishedError();
207
+ }
208
+ 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);
209
+ const { userRequestState } = ProtocolUtils.parseRequestState(this.browserCrypto, state);
210
+ return nativeInteractionClient
211
+ .acquireToken({
212
+ ...cachedRequest,
213
+ state: userRequestState,
214
+ prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
215
+ })
216
+ .finally(() => {
217
+ this.browserStorage.cleanRequestByState(state);
218
+ });
219
+ }
220
+ // Hash contains known properties - handle and return in callback
221
+ const currentAuthority = this.browserStorage.getCachedAuthority(state);
222
+ if (!currentAuthority) {
223
+ throw BrowserAuthError.createNoCachedAuthorityError();
224
+ }
225
+ this.performanceClient.setPreQueueTime(PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, cachedRequest.correlationId);
226
+ const authClient = await this.createAuthCodeClient(serverTelemetryManager, currentAuthority);
227
+ this.logger.verbose("Auth code client created");
228
+ ThrottlingUtils.removeThrottle(this.browserStorage, this.config.auth.clientId, cachedRequest);
229
+ const interactionHandler = new RedirectHandler(authClient, this.browserStorage, cachedRequest, this.logger, this.browserCrypto, this.performanceClient);
230
+ return await interactionHandler.handleCodeResponseFromHash(hash, state, authClient.authority, this.networkClient);
231
+ }
232
+ /**
233
+ * Use to log out the current user, and redirect the user to the postLogoutRedirectUri.
234
+ * Default behaviour is to redirect the user to `window.location.href`.
235
+ * @param logoutRequest
236
+ */
237
+ async logout(logoutRequest) {
238
+ this.logger.verbose("logoutRedirect called");
239
+ const validLogoutRequest = this.initializeLogoutRequest(logoutRequest);
240
+ const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.logout);
241
+ try {
242
+ this.eventHandler.emitEvent(EventType.LOGOUT_START, InteractionType.Redirect, logoutRequest);
243
+ // Clear cache on logout
244
+ await this.clearCacheOnLogout(validLogoutRequest.account);
245
+ const navigationOptions = {
246
+ apiId: ApiId.logout,
247
+ timeout: this.config.system.redirectNavigationTimeout,
248
+ noHistory: false,
249
+ };
250
+ this.performanceClient.setPreQueueTime(PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, validLogoutRequest.correlationId);
251
+ const authClient = await this.createAuthCodeClient(serverTelemetryManager, logoutRequest && logoutRequest.authority);
252
+ this.logger.verbose("Auth code client created");
253
+ // Create logout string and navigate user window to logout.
254
+ const logoutUri = authClient.getLogoutUri(validLogoutRequest);
255
+ this.eventHandler.emitEvent(EventType.LOGOUT_SUCCESS, InteractionType.Redirect, validLogoutRequest);
256
+ // Check if onRedirectNavigate is implemented, and invoke it if so
257
+ if (logoutRequest &&
258
+ typeof logoutRequest.onRedirectNavigate === "function") {
259
+ const navigate = logoutRequest.onRedirectNavigate(logoutUri);
260
+ if (navigate !== false) {
261
+ this.logger.verbose("Logout onRedirectNavigate did not return false, navigating");
262
+ // Ensure interaction is in progress
263
+ if (!this.browserStorage.getInteractionInProgress()) {
264
+ this.browserStorage.setInteractionInProgress(true);
265
+ }
266
+ await this.navigationClient.navigateExternal(logoutUri, navigationOptions);
267
+ return;
268
+ }
269
+ else {
270
+ // Ensure interaction is not in progress
271
+ this.browserStorage.setInteractionInProgress(false);
272
+ this.logger.verbose("Logout onRedirectNavigate returned false, stopping navigation");
273
+ }
274
+ }
275
+ else {
276
+ // Ensure interaction is in progress
277
+ if (!this.browserStorage.getInteractionInProgress()) {
278
+ this.browserStorage.setInteractionInProgress(true);
279
+ }
280
+ await this.navigationClient.navigateExternal(logoutUri, navigationOptions);
281
+ return;
282
+ }
283
+ }
284
+ catch (e) {
285
+ if (e instanceof AuthError) {
286
+ e.setCorrelationId(this.correlationId);
287
+ serverTelemetryManager.cacheFailedRequest(e);
288
+ }
289
+ this.eventHandler.emitEvent(EventType.LOGOUT_FAILURE, InteractionType.Redirect, null, e);
290
+ this.eventHandler.emitEvent(EventType.LOGOUT_END, InteractionType.Redirect);
291
+ throw e;
292
+ }
293
+ this.eventHandler.emitEvent(EventType.LOGOUT_END, InteractionType.Redirect);
294
+ }
295
+ /**
296
+ * Use to get the redirectStartPage either from request or use current window
297
+ * @param requestStartPage
298
+ */
299
+ getRedirectStartPage(requestStartPage) {
300
+ const redirectStartPage = requestStartPage || window.location.href;
301
+ return UrlString.getAbsoluteUrl(redirectStartPage, BrowserUtils.getCurrentUri());
302
+ }
302
303
  }
303
304
 
304
305
  export { RedirectClient };