@azure/msal-browser 3.20.0 → 3.21.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 (208) hide show
  1. package/dist/app/IPublicClientApplication.d.ts +53 -53
  2. package/dist/app/IPublicClientApplication.mjs +105 -105
  3. package/dist/app/PublicClientApplication.d.ts +293 -293
  4. package/dist/app/PublicClientApplication.mjs +364 -364
  5. package/dist/app/PublicClientNext.d.ts +276 -276
  6. package/dist/app/PublicClientNext.mjs +354 -354
  7. package/dist/broker/nativeBroker/NativeMessageHandler.d.ts +62 -62
  8. package/dist/broker/nativeBroker/NativeMessageHandler.mjs +254 -254
  9. package/dist/broker/nativeBroker/NativeRequest.d.ts +45 -45
  10. package/dist/broker/nativeBroker/NativeResponse.d.ts +48 -48
  11. package/dist/broker/nativeBroker/NativeStatusCodes.d.ts +7 -7
  12. package/dist/broker/nativeBroker/NativeStatusCodes.mjs +11 -11
  13. package/dist/cache/AccountManager.d.ts +48 -48
  14. package/dist/cache/AccountManager.mjs +126 -126
  15. package/dist/cache/AsyncMemoryStorage.d.ts +50 -50
  16. package/dist/cache/AsyncMemoryStorage.mjs +131 -131
  17. package/dist/cache/BrowserCacheManager.d.ts +410 -385
  18. package/dist/cache/BrowserCacheManager.d.ts.map +1 -1
  19. package/dist/cache/BrowserCacheManager.mjs +1364 -1294
  20. package/dist/cache/BrowserCacheManager.mjs.map +1 -1
  21. package/dist/cache/BrowserStorage.d.ts +11 -11
  22. package/dist/cache/BrowserStorage.mjs +32 -32
  23. package/dist/cache/DatabaseStorage.d.ts +56 -56
  24. package/dist/cache/DatabaseStorage.mjs +200 -200
  25. package/dist/cache/IAsyncStorage.d.ts +27 -27
  26. package/dist/cache/ITokenCache.d.ts +11 -11
  27. package/dist/cache/IWindowStorage.d.ts +27 -27
  28. package/dist/cache/MemoryStorage.d.ts +11 -11
  29. package/dist/cache/MemoryStorage.mjs +31 -31
  30. package/dist/cache/TokenCache.d.ts +77 -77
  31. package/dist/cache/TokenCache.mjs +195 -195
  32. package/dist/config/Configuration.d.ts +213 -208
  33. package/dist/config/Configuration.d.ts.map +1 -1
  34. package/dist/config/Configuration.mjs +128 -128
  35. package/dist/config/Configuration.mjs.map +1 -1
  36. package/dist/controllers/ControllerFactory.d.ts +5 -5
  37. package/dist/controllers/ControllerFactory.mjs +25 -25
  38. package/dist/controllers/IController.d.ts +60 -60
  39. package/dist/controllers/NestedAppAuthController.d.ts +202 -202
  40. package/dist/controllers/NestedAppAuthController.mjs +473 -473
  41. package/dist/controllers/StandardController.d.ts +405 -405
  42. package/dist/controllers/StandardController.d.ts.map +1 -1
  43. package/dist/controllers/StandardController.mjs +1334 -1316
  44. package/dist/controllers/StandardController.mjs.map +1 -1
  45. package/dist/controllers/UnknownOperatingContextController.d.ts +86 -86
  46. package/dist/controllers/UnknownOperatingContextController.mjs +256 -256
  47. package/dist/crypto/BrowserCrypto.d.ts +52 -52
  48. package/dist/crypto/BrowserCrypto.mjs +151 -151
  49. package/dist/crypto/CryptoOps.d.ts +74 -74
  50. package/dist/crypto/CryptoOps.mjs +176 -176
  51. package/dist/crypto/PkceGenerator.d.ts +8 -8
  52. package/dist/crypto/PkceGenerator.mjs +54 -54
  53. package/dist/crypto/SignedHttpRequest.d.ts +30 -30
  54. package/dist/crypto/SignedHttpRequest.mjs +39 -39
  55. package/dist/encode/Base64Decode.d.ts +9 -9
  56. package/dist/encode/Base64Decode.mjs +36 -36
  57. package/dist/encode/Base64Encode.d.ts +19 -19
  58. package/dist/encode/Base64Encode.mjs +43 -43
  59. package/dist/error/BrowserAuthError.d.ts +256 -255
  60. package/dist/error/BrowserAuthError.d.ts.map +1 -1
  61. package/dist/error/BrowserAuthError.mjs +265 -264
  62. package/dist/error/BrowserAuthError.mjs.map +1 -1
  63. package/dist/error/BrowserAuthErrorCodes.d.ts +47 -46
  64. package/dist/error/BrowserAuthErrorCodes.d.ts.map +1 -1
  65. package/dist/error/BrowserAuthErrorCodes.mjs +53 -52
  66. package/dist/error/BrowserAuthErrorCodes.mjs.map +1 -1
  67. package/dist/error/BrowserConfigurationAuthError.d.ts +33 -33
  68. package/dist/error/BrowserConfigurationAuthError.mjs +40 -40
  69. package/dist/error/BrowserConfigurationAuthError.mjs.map +1 -1
  70. package/dist/error/BrowserConfigurationAuthErrorCodes.d.ts +3 -3
  71. package/dist/error/BrowserConfigurationAuthErrorCodes.mjs +7 -7
  72. package/dist/error/NativeAuthError.d.ts +29 -29
  73. package/dist/error/NativeAuthError.mjs +60 -60
  74. package/dist/error/NativeAuthErrorCodes.d.ts +2 -2
  75. package/dist/error/NativeAuthErrorCodes.mjs +6 -6
  76. package/dist/error/NestedAppAuthError.d.ts +14 -14
  77. package/dist/error/NestedAppAuthError.mjs +23 -23
  78. package/dist/event/EventHandler.d.ts +41 -41
  79. package/dist/event/EventHandler.mjs +125 -125
  80. package/dist/event/EventMessage.d.ts +25 -25
  81. package/dist/event/EventMessage.mjs +68 -68
  82. package/dist/event/EventType.d.ts +29 -29
  83. package/dist/event/EventType.mjs +32 -32
  84. package/dist/index.d.ts +40 -40
  85. package/dist/index.mjs +1 -1
  86. package/dist/interaction_client/BaseInteractionClient.d.ts +50 -50
  87. package/dist/interaction_client/BaseInteractionClient.mjs +106 -106
  88. package/dist/interaction_client/HybridSpaAuthorizationCodeClient.d.ts +4 -4
  89. package/dist/interaction_client/HybridSpaAuthorizationCodeClient.mjs +10 -10
  90. package/dist/interaction_client/NativeInteractionClient.d.ts +151 -151
  91. package/dist/interaction_client/NativeInteractionClient.mjs +621 -621
  92. package/dist/interaction_client/PopupClient.d.ts +118 -105
  93. package/dist/interaction_client/PopupClient.d.ts.map +1 -1
  94. package/dist/interaction_client/PopupClient.mjs +460 -434
  95. package/dist/interaction_client/PopupClient.mjs.map +1 -1
  96. package/dist/interaction_client/RedirectClient.d.ts +50 -50
  97. package/dist/interaction_client/RedirectClient.d.ts.map +1 -1
  98. package/dist/interaction_client/RedirectClient.mjs +349 -317
  99. package/dist/interaction_client/RedirectClient.mjs.map +1 -1
  100. package/dist/interaction_client/SilentAuthCodeClient.d.ts +23 -23
  101. package/dist/interaction_client/SilentAuthCodeClient.mjs +57 -57
  102. package/dist/interaction_client/SilentCacheClient.d.ts +16 -16
  103. package/dist/interaction_client/SilentCacheClient.mjs +42 -42
  104. package/dist/interaction_client/SilentIframeClient.d.ts +32 -32
  105. package/dist/interaction_client/SilentIframeClient.d.ts.map +1 -1
  106. package/dist/interaction_client/SilentIframeClient.mjs +111 -101
  107. package/dist/interaction_client/SilentIframeClient.mjs.map +1 -1
  108. package/dist/interaction_client/SilentRefreshClient.d.ts +20 -20
  109. package/dist/interaction_client/SilentRefreshClient.mjs +47 -47
  110. package/dist/interaction_client/StandardInteractionClient.d.ts +48 -48
  111. package/dist/interaction_client/StandardInteractionClient.mjs +199 -199
  112. package/dist/interaction_handler/InteractionHandler.d.ts +33 -33
  113. package/dist/interaction_handler/InteractionHandler.mjs +93 -93
  114. package/dist/interaction_handler/RedirectHandler.d.ts +32 -32
  115. package/dist/interaction_handler/RedirectHandler.d.ts.map +1 -1
  116. package/dist/interaction_handler/RedirectHandler.mjs +135 -134
  117. package/dist/interaction_handler/RedirectHandler.mjs.map +1 -1
  118. package/dist/interaction_handler/SilentHandler.d.ts +13 -13
  119. package/dist/interaction_handler/SilentHandler.mjs +134 -134
  120. package/dist/naa/AccountInfo.d.ts +11 -11
  121. package/dist/naa/AuthBridge.d.ts +8 -8
  122. package/dist/naa/AuthResult.d.ts +6 -6
  123. package/dist/naa/BridgeAccountContext.d.ts +12 -12
  124. package/dist/naa/BridgeCapabilities.d.ts +3 -3
  125. package/dist/naa/BridgeError.d.ts +9 -9
  126. package/dist/naa/BridgeError.mjs +7 -7
  127. package/dist/naa/BridgeProxy.d.ts +67 -67
  128. package/dist/naa/BridgeProxy.d.ts.map +1 -1
  129. package/dist/naa/BridgeProxy.mjs +153 -148
  130. package/dist/naa/BridgeProxy.mjs.map +1 -1
  131. package/dist/naa/BridgeRequest.d.ts +7 -7
  132. package/dist/naa/BridgeRequestEnvelope.d.ts +12 -12
  133. package/dist/naa/BridgeResponseEnvelope.d.ts +13 -13
  134. package/dist/naa/BridgeStatusCode.d.ts +11 -11
  135. package/dist/naa/BridgeStatusCode.mjs +14 -14
  136. package/dist/naa/IBridgeProxy.d.ts +10 -10
  137. package/dist/naa/InitContext.d.ts +8 -8
  138. package/dist/naa/TokenRequest.d.ts +18 -18
  139. package/dist/naa/TokenResponse.d.ts +13 -13
  140. package/dist/naa/mapping/NestedAppAuthAdapter.d.ts +35 -35
  141. package/dist/naa/mapping/NestedAppAuthAdapter.mjs +179 -179
  142. package/dist/navigation/INavigationClient.d.ts +16 -16
  143. package/dist/navigation/NavigationClient.d.ts +22 -22
  144. package/dist/navigation/NavigationClient.mjs +40 -40
  145. package/dist/navigation/NavigationOptions.d.ts +12 -12
  146. package/dist/network/FetchClient.d.ts +26 -26
  147. package/dist/network/FetchClient.mjs +99 -99
  148. package/dist/operatingcontext/BaseOperatingContext.d.ts +41 -41
  149. package/dist/operatingcontext/BaseOperatingContext.mjs +94 -94
  150. package/dist/operatingcontext/NestedAppOperatingContext.d.ts +34 -34
  151. package/dist/operatingcontext/NestedAppOperatingContext.mjs +71 -71
  152. package/dist/operatingcontext/StandardOperatingContext.d.ts +25 -25
  153. package/dist/operatingcontext/StandardOperatingContext.mjs +43 -43
  154. package/dist/operatingcontext/UnknownOperatingContext.d.ts +25 -25
  155. package/dist/operatingcontext/UnknownOperatingContext.mjs +42 -42
  156. package/dist/packageMetadata.d.ts +2 -2
  157. package/dist/packageMetadata.mjs +4 -4
  158. package/dist/request/AuthorizationCodeRequest.d.ts +8 -8
  159. package/dist/request/AuthorizationUrlRequest.d.ts +8 -8
  160. package/dist/request/ClearCacheRequest.d.ts +10 -10
  161. package/dist/request/EndSessionPopupRequest.d.ts +18 -18
  162. package/dist/request/EndSessionRequest.d.ts +15 -15
  163. package/dist/request/InitializeApplicationRequest.d.ts +8 -8
  164. package/dist/request/PopupRequest.d.ts +34 -34
  165. package/dist/request/PopupWindowAttributes.d.ts +15 -15
  166. package/dist/request/RedirectRequest.d.ts +40 -35
  167. package/dist/request/RedirectRequest.d.ts.map +1 -1
  168. package/dist/request/RequestHelpers.d.ts +13 -13
  169. package/dist/request/RequestHelpers.mjs +53 -53
  170. package/dist/request/SilentRequest.d.ts +33 -33
  171. package/dist/request/SsoSilentRequest.d.ts +29 -29
  172. package/dist/response/AuthenticationResult.d.ts +4 -4
  173. package/dist/response/ResponseHandler.d.ts +7 -7
  174. package/dist/response/ResponseHandler.mjs +36 -36
  175. package/dist/telemetry/BrowserPerformanceClient.d.ts +38 -34
  176. package/dist/telemetry/BrowserPerformanceClient.d.ts.map +1 -1
  177. package/dist/telemetry/BrowserPerformanceClient.mjs +163 -163
  178. package/dist/telemetry/BrowserPerformanceClient.mjs.map +1 -1
  179. package/dist/telemetry/BrowserPerformanceMeasurement.d.ts +21 -21
  180. package/dist/telemetry/BrowserPerformanceMeasurement.mjs +92 -92
  181. package/dist/utils/BrowserConstants.d.ts +182 -180
  182. package/dist/utils/BrowserConstants.d.ts.map +1 -1
  183. package/dist/utils/BrowserConstants.mjs +214 -212
  184. package/dist/utils/BrowserConstants.mjs.map +1 -1
  185. package/dist/utils/BrowserProtocolUtils.d.ts +11 -11
  186. package/dist/utils/BrowserProtocolUtils.mjs +21 -21
  187. package/dist/utils/BrowserUtils.d.ts +75 -75
  188. package/dist/utils/BrowserUtils.mjs +157 -157
  189. package/lib/msal-browser.cjs +19027 -18857
  190. package/lib/msal-browser.cjs.map +1 -1
  191. package/lib/msal-browser.js +19027 -18857
  192. package/lib/msal-browser.js.map +1 -1
  193. package/lib/msal-browser.min.js +62 -62
  194. package/package.json +2 -2
  195. package/src/cache/BrowserCacheManager.ts +95 -0
  196. package/src/config/Configuration.ts +9 -1
  197. package/src/controllers/StandardController.ts +30 -12
  198. package/src/error/BrowserAuthError.ts +2 -0
  199. package/src/error/BrowserAuthErrorCodes.ts +1 -0
  200. package/src/interaction_client/PopupClient.ts +202 -117
  201. package/src/interaction_client/RedirectClient.ts +62 -2
  202. package/src/interaction_client/SilentIframeClient.ts +41 -3
  203. package/src/interaction_handler/RedirectHandler.ts +1 -0
  204. package/src/naa/BridgeProxy.ts +7 -2
  205. package/src/packageMetadata.ts +1 -1
  206. package/src/request/RedirectRequest.ts +5 -0
  207. package/src/telemetry/BrowserPerformanceClient.ts +1 -1
  208. package/src/utils/BrowserConstants.ts +2 -0
@@ -1,6 +1,6 @@
1
- /*! @azure/msal-browser v3.20.0 2024-07-23 */
1
+ /*! @azure/msal-browser v3.21.0 2024-08-13 */
2
2
  'use strict';
3
- import { OIDC_DEFAULT_SCOPES, invokeAsync, PerformanceEvents, invoke, ThrottlingUtils, ProtocolUtils, AuthError, ProtocolMode, UrlString, ServerResponseType } from '@azure/msal-common';
3
+ import { OIDC_DEFAULT_SCOPES, invokeAsync, PerformanceEvents, AuthError, ServerError, invoke, ThrottlingUtils, ProtocolUtils, ProtocolMode, UrlString, ServerResponseType } from '@azure/msal-common';
4
4
  import { StandardInteractionClient } from './StandardInteractionClient.mjs';
5
5
  import { EventType } from '../event/EventType.mjs';
6
6
  import { ApiId, InteractionType, BrowserConstants } from '../utils/BrowserConstants.mjs';
@@ -12,438 +12,464 @@ import { InteractionHandler } from '../interaction_handler/InteractionHandler.mj
12
12
  import { deserializeResponse } from '../response/ResponseHandler.mjs';
13
13
  import { nativeConnectionNotEstablished, emptyNavigateUri, userCancelled, emptyWindowError, popupWindowError } from '../error/BrowserAuthErrorCodes.mjs';
14
14
 
15
- /*
16
- * Copyright (c) Microsoft Corporation. All rights reserved.
17
- * Licensed under the MIT License.
18
- */
19
- class PopupClient extends StandardInteractionClient {
20
- constructor(config, storageImpl, browserCrypto, logger, eventHandler, navigationClient, performanceClient, nativeStorageImpl, nativeMessageHandler, correlationId) {
21
- super(config, storageImpl, browserCrypto, logger, eventHandler, navigationClient, performanceClient, nativeMessageHandler, correlationId);
22
- // Properly sets this reference for the unload event.
23
- this.unloadWindow = this.unloadWindow.bind(this);
24
- this.nativeStorage = nativeStorageImpl;
25
- }
26
- /**
27
- * Acquires tokens by opening a popup window to the /authorize endpoint of the authority
28
- * @param request
29
- */
30
- acquireToken(request) {
31
- try {
32
- const popupName = this.generatePopupName(request.scopes || OIDC_DEFAULT_SCOPES, request.authority || this.config.auth.authority);
33
- const popupWindowAttributes = request.popupWindowAttributes || {};
34
- // asyncPopups flag is true. Acquires token without first opening popup. Popup will be opened later asynchronously.
35
- if (this.config.system.asyncPopups) {
36
- this.logger.verbose("asyncPopups set to true, acquiring token");
37
- // Passes on popup position and dimensions if in request
38
- return this.acquireTokenPopupAsync(request, popupName, popupWindowAttributes);
39
- }
40
- else {
41
- // asyncPopups flag is set to false. Opens popup before acquiring token.
42
- this.logger.verbose("asyncPopup set to false, opening popup before acquiring token");
43
- const popup = this.openSizedPopup("about:blank", popupName, popupWindowAttributes);
44
- return this.acquireTokenPopupAsync(request, popupName, popupWindowAttributes, popup);
45
- }
46
- }
47
- catch (e) {
48
- return Promise.reject(e);
49
- }
50
- }
51
- /**
52
- * Clears local cache for the current user then opens a popup window prompting the user to sign-out of the server
53
- * @param logoutRequest
54
- */
55
- logout(logoutRequest) {
56
- try {
57
- this.logger.verbose("logoutPopup called");
58
- const validLogoutRequest = this.initializeLogoutRequest(logoutRequest);
59
- const popupName = this.generateLogoutPopupName(validLogoutRequest);
60
- const authority = logoutRequest && logoutRequest.authority;
61
- const mainWindowRedirectUri = logoutRequest && logoutRequest.mainWindowRedirectUri;
62
- const popupWindowAttributes = logoutRequest?.popupWindowAttributes || {};
63
- // asyncPopups flag is true. Acquires token without first opening popup. Popup will be opened later asynchronously.
64
- if (this.config.system.asyncPopups) {
65
- this.logger.verbose("asyncPopups set to true");
66
- // Passes on popup position and dimensions if in request
67
- return this.logoutPopupAsync(validLogoutRequest, popupName, popupWindowAttributes, authority, undefined, mainWindowRedirectUri);
68
- }
69
- else {
70
- // asyncPopups flag is set to false. Opens popup before logging out.
71
- this.logger.verbose("asyncPopup set to false, opening popup");
72
- const popup = this.openSizedPopup("about:blank", popupName, popupWindowAttributes);
73
- return this.logoutPopupAsync(validLogoutRequest, popupName, popupWindowAttributes, authority, popup, mainWindowRedirectUri);
74
- }
75
- }
76
- catch (e) {
77
- // Since this function is synchronous we need to reject
78
- return Promise.reject(e);
79
- }
80
- }
81
- /**
82
- * Helper which obtains an access_token for your API via opening a popup window in the user's browser
83
- * @param validRequest
84
- * @param popupName
85
- * @param popup
86
- * @param popupWindowAttributes
87
- *
88
- * @returns A promise that is fulfilled when this function has completed, or rejected if an error was raised.
89
- */
90
- async acquireTokenPopupAsync(request, popupName, popupWindowAttributes, popup) {
91
- this.logger.verbose("acquireTokenPopupAsync called");
92
- const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenPopup);
93
- const validRequest = await invokeAsync(this.initializeAuthorizationRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, this.logger, this.performanceClient, this.correlationId)(request, InteractionType.Popup);
94
- preconnect(validRequest.authority);
95
- try {
96
- // Create auth code request and generate PKCE params
97
- const authCodeRequest = await invokeAsync(this.initializeAuthorizationCodeRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationCodeRequest, this.logger, this.performanceClient, this.correlationId)(validRequest);
98
- // Initialize the client
99
- const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)(serverTelemetryManager, validRequest.authority, validRequest.azureCloudOptions, validRequest.account);
100
- const isNativeBroker = NativeMessageHandler.isNativeAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme);
101
- // Start measurement for server calls with native brokering enabled
102
- let fetchNativeAccountIdMeasurement;
103
- if (isNativeBroker) {
104
- fetchNativeAccountIdMeasurement =
105
- this.performanceClient.startMeasurement(PerformanceEvents.FetchAccountIdWithNativeBroker, request.correlationId);
106
- }
107
- // Create acquire token url.
108
- const navigateUrl = await authClient.getAuthCodeUrl({
109
- ...validRequest,
110
- nativeBroker: isNativeBroker,
111
- });
112
- // Create popup interaction handler.
113
- const interactionHandler = new InteractionHandler(authClient, this.browserStorage, authCodeRequest, this.logger, this.performanceClient);
114
- // Show the UI once the url has been created. Get the window handle for the popup.
115
- const popupParameters = {
116
- popup,
117
- popupName,
118
- popupWindowAttributes,
119
- };
120
- const popupWindow = this.initiateAuthRequest(navigateUrl, popupParameters);
121
- this.eventHandler.emitEvent(EventType.POPUP_OPENED, InteractionType.Popup, { popupWindow }, null);
122
- // Monitor the window for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
123
- const responseString = await this.monitorPopupForHash(popupWindow);
124
- const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, this.correlationId)(responseString, this.config.auth.OIDCOptions.serverResponseType, this.logger);
125
- // Remove throttle if it exists
126
- ThrottlingUtils.removeThrottle(this.browserStorage, this.config.auth.clientId, authCodeRequest);
127
- if (serverParams.accountId) {
128
- this.logger.verbose("Account id found in hash, calling WAM for token");
129
- // end measurement for server call with native brokering enabled
130
- if (fetchNativeAccountIdMeasurement) {
131
- fetchNativeAccountIdMeasurement.end({
132
- success: true,
133
- isNativeBroker: true,
134
- });
135
- }
136
- if (!this.nativeMessageHandler) {
137
- throw createBrowserAuthError(nativeConnectionNotEstablished);
138
- }
139
- 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);
140
- const { userRequestState } = ProtocolUtils.parseRequestState(this.browserCrypto, validRequest.state);
141
- return await nativeInteractionClient.acquireToken({
142
- ...validRequest,
143
- state: userRequestState,
144
- prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
145
- });
146
- }
147
- // Handle response from hash string.
148
- const result = await interactionHandler.handleCodeResponse(serverParams, validRequest);
149
- return result;
150
- }
151
- catch (e) {
152
- if (popup) {
153
- // Close the synchronous popup if an error is thrown before the window unload event is registered
154
- popup.close();
155
- }
156
- if (e instanceof AuthError) {
157
- e.setCorrelationId(this.correlationId);
158
- serverTelemetryManager.cacheFailedRequest(e);
159
- }
160
- throw e;
161
- }
162
- }
163
- /**
164
- *
165
- * @param validRequest
166
- * @param popupName
167
- * @param requestAuthority
168
- * @param popup
169
- * @param mainWindowRedirectUri
170
- * @param popupWindowAttributes
171
- */
172
- async logoutPopupAsync(validRequest, popupName, popupWindowAttributes, requestAuthority, popup, mainWindowRedirectUri) {
173
- this.logger.verbose("logoutPopupAsync called");
174
- this.eventHandler.emitEvent(EventType.LOGOUT_START, InteractionType.Popup, validRequest);
175
- const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.logoutPopup);
176
- try {
177
- // Clear cache on logout
178
- await this.clearCacheOnLogout(validRequest.account);
179
- // Initialize the client
180
- const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)(serverTelemetryManager, requestAuthority, undefined, // AzureCloudOptions
181
- validRequest.account || undefined);
182
- try {
183
- authClient.authority.endSessionEndpoint;
184
- }
185
- catch {
186
- if (validRequest.account?.homeAccountId &&
187
- validRequest.postLogoutRedirectUri &&
188
- authClient.authority.protocolMode === ProtocolMode.OIDC) {
189
- void this.browserStorage.removeAccount(validRequest.account?.homeAccountId);
190
- this.eventHandler.emitEvent(EventType.LOGOUT_SUCCESS, InteractionType.Popup, validRequest);
191
- if (mainWindowRedirectUri) {
192
- const navigationOptions = {
193
- apiId: ApiId.logoutPopup,
194
- timeout: this.config.system.redirectNavigationTimeout,
195
- noHistory: false,
196
- };
197
- const absoluteUrl = UrlString.getAbsoluteUrl(mainWindowRedirectUri, getCurrentUri());
198
- await this.navigationClient.navigateInternal(absoluteUrl, navigationOptions);
199
- }
200
- if (popup) {
201
- popup.close();
202
- }
203
- return;
204
- }
205
- }
206
- // Create logout string and navigate user window to logout.
207
- const logoutUri = authClient.getLogoutUri(validRequest);
208
- this.eventHandler.emitEvent(EventType.LOGOUT_SUCCESS, InteractionType.Popup, validRequest);
209
- // Open the popup window to requestUrl.
210
- const popupWindow = this.openPopup(logoutUri, {
211
- popupName,
212
- popupWindowAttributes,
213
- popup,
214
- });
215
- this.eventHandler.emitEvent(EventType.POPUP_OPENED, InteractionType.Popup, { popupWindow }, null);
216
- await this.monitorPopupForHash(popupWindow).catch(() => {
217
- // Swallow any errors related to monitoring the window. Server logout is best effort
218
- });
219
- if (mainWindowRedirectUri) {
220
- const navigationOptions = {
221
- apiId: ApiId.logoutPopup,
222
- timeout: this.config.system.redirectNavigationTimeout,
223
- noHistory: false,
224
- };
225
- const absoluteUrl = UrlString.getAbsoluteUrl(mainWindowRedirectUri, getCurrentUri());
226
- this.logger.verbose("Redirecting main window to url specified in the request");
227
- this.logger.verbosePii(`Redirecting main window to: ${absoluteUrl}`);
228
- await this.navigationClient.navigateInternal(absoluteUrl, navigationOptions);
229
- }
230
- else {
231
- this.logger.verbose("No main window navigation requested");
232
- }
233
- }
234
- catch (e) {
235
- if (popup) {
236
- // Close the synchronous popup if an error is thrown before the window unload event is registered
237
- popup.close();
238
- }
239
- if (e instanceof AuthError) {
240
- e.setCorrelationId(this.correlationId);
241
- serverTelemetryManager.cacheFailedRequest(e);
242
- }
243
- this.browserStorage.setInteractionInProgress(false);
244
- this.eventHandler.emitEvent(EventType.LOGOUT_FAILURE, InteractionType.Popup, null, e);
245
- this.eventHandler.emitEvent(EventType.LOGOUT_END, InteractionType.Popup);
246
- throw e;
247
- }
248
- this.eventHandler.emitEvent(EventType.LOGOUT_END, InteractionType.Popup);
249
- }
250
- /**
251
- * Opens a popup window with given request Url.
252
- * @param requestUrl
253
- */
254
- initiateAuthRequest(requestUrl, params) {
255
- // Check that request url is not empty.
256
- if (requestUrl) {
257
- this.logger.infoPii(`Navigate to: ${requestUrl}`);
258
- // Open the popup window to requestUrl.
259
- return this.openPopup(requestUrl, params);
260
- }
261
- else {
262
- // Throw error if request URL is empty.
263
- this.logger.error("Navigate url is empty");
264
- throw createBrowserAuthError(emptyNavigateUri);
265
- }
266
- }
267
- /**
268
- * Monitors a window until it loads a url with the same origin.
269
- * @param popupWindow - window that is being monitored
270
- * @param timeout - timeout for processing hash once popup is redirected back to application
271
- */
272
- monitorPopupForHash(popupWindow) {
273
- return new Promise((resolve, reject) => {
274
- this.logger.verbose("PopupHandler.monitorPopupForHash - polling started");
275
- const intervalId = setInterval(() => {
276
- // Window is closed
277
- if (popupWindow.closed) {
278
- this.logger.error("PopupHandler.monitorPopupForHash - window closed");
279
- clearInterval(intervalId);
280
- reject(createBrowserAuthError(userCancelled));
281
- return;
282
- }
283
- let href = "";
284
- try {
285
- /*
286
- * Will throw if cross origin,
287
- * which should be caught and ignored
288
- * since we need the interval to keep running while on STS UI.
289
- */
290
- href = popupWindow.location.href;
291
- }
292
- catch (e) { }
293
- // Don't process blank pages or cross domain
294
- if (!href || href === "about:blank") {
295
- return;
296
- }
297
- clearInterval(intervalId);
298
- let responseString = "";
299
- const responseType = this.config.auth.OIDCOptions.serverResponseType;
300
- if (popupWindow) {
301
- if (responseType === ServerResponseType.QUERY) {
302
- responseString = popupWindow.location.search;
303
- }
304
- else {
305
- responseString = popupWindow.location.hash;
306
- }
307
- }
308
- this.logger.verbose("PopupHandler.monitorPopupForHash - popup window is on same origin as caller");
309
- resolve(responseString);
310
- }, this.config.system.pollIntervalMilliseconds);
311
- }).finally(() => {
312
- this.cleanPopup(popupWindow);
313
- });
314
- }
315
- /**
316
- * @hidden
317
- *
318
- * Configures popup window for login.
319
- *
320
- * @param urlNavigate
321
- * @param title
322
- * @param popUpWidth
323
- * @param popUpHeight
324
- * @param popupWindowAttributes
325
- * @ignore
326
- * @hidden
327
- */
328
- openPopup(urlNavigate, popupParams) {
329
- try {
330
- let popupWindow;
331
- // Popup window passed in, setting url to navigate to
332
- if (popupParams.popup) {
333
- popupWindow = popupParams.popup;
334
- this.logger.verbosePii(`Navigating popup window to: ${urlNavigate}`);
335
- popupWindow.location.assign(urlNavigate);
336
- }
337
- else if (typeof popupParams.popup === "undefined") {
338
- // Popup will be undefined if it was not passed in
339
- this.logger.verbosePii(`Opening popup window to: ${urlNavigate}`);
340
- popupWindow = this.openSizedPopup(urlNavigate, popupParams.popupName, popupParams.popupWindowAttributes);
341
- }
342
- // Popup will be null if popups are blocked
343
- if (!popupWindow) {
344
- throw createBrowserAuthError(emptyWindowError);
345
- }
346
- if (popupWindow.focus) {
347
- popupWindow.focus();
348
- }
349
- this.currentWindow = popupWindow;
350
- window.addEventListener("beforeunload", this.unloadWindow);
351
- return popupWindow;
352
- }
353
- catch (e) {
354
- this.logger.error("error opening popup " + e.message);
355
- this.browserStorage.setInteractionInProgress(false);
356
- throw createBrowserAuthError(popupWindowError);
357
- }
358
- }
359
- /**
360
- * Helper function to set popup window dimensions and position
361
- * @param urlNavigate
362
- * @param popupName
363
- * @param popupWindowAttributes
364
- * @returns
365
- */
366
- openSizedPopup(urlNavigate, popupName, popupWindowAttributes) {
367
- /**
368
- * adding winLeft and winTop to account for dual monitor
369
- * using screenLeft and screenTop for IE8 and earlier
370
- */
371
- const winLeft = window.screenLeft ? window.screenLeft : window.screenX;
372
- const winTop = window.screenTop ? window.screenTop : window.screenY;
373
- /**
374
- * window.innerWidth displays browser window"s height and width excluding toolbars
375
- * using document.documentElement.clientWidth for IE8 and earlier
376
- */
377
- const winWidth = window.innerWidth ||
378
- document.documentElement.clientWidth ||
379
- document.body.clientWidth;
380
- const winHeight = window.innerHeight ||
381
- document.documentElement.clientHeight ||
382
- document.body.clientHeight;
383
- let width = popupWindowAttributes.popupSize?.width;
384
- let height = popupWindowAttributes.popupSize?.height;
385
- let top = popupWindowAttributes.popupPosition?.top;
386
- let left = popupWindowAttributes.popupPosition?.left;
387
- if (!width || width < 0 || width > winWidth) {
388
- this.logger.verbose("Default popup window width used. Window width not configured or invalid.");
389
- width = BrowserConstants.POPUP_WIDTH;
390
- }
391
- if (!height || height < 0 || height > winHeight) {
392
- this.logger.verbose("Default popup window height used. Window height not configured or invalid.");
393
- height = BrowserConstants.POPUP_HEIGHT;
394
- }
395
- if (!top || top < 0 || top > winHeight) {
396
- this.logger.verbose("Default popup window top position used. Window top not configured or invalid.");
397
- top = Math.max(0, winHeight / 2 - BrowserConstants.POPUP_HEIGHT / 2 + winTop);
398
- }
399
- if (!left || left < 0 || left > winWidth) {
400
- this.logger.verbose("Default popup window left position used. Window left not configured or invalid.");
401
- left = Math.max(0, winWidth / 2 - BrowserConstants.POPUP_WIDTH / 2 + winLeft);
402
- }
403
- return window.open(urlNavigate, popupName, `width=${width}, height=${height}, top=${top}, left=${left}, scrollbars=yes`);
404
- }
405
- /**
406
- * Event callback to unload main window.
407
- */
408
- unloadWindow(e) {
409
- this.browserStorage.cleanRequestByInteractionType(InteractionType.Popup);
410
- if (this.currentWindow) {
411
- this.currentWindow.close();
412
- }
413
- // Guarantees browser unload will happen, so no other errors will be thrown.
414
- e.preventDefault();
415
- }
416
- /**
417
- * Closes popup, removes any state vars created during popup calls.
418
- * @param popupWindow
419
- */
420
- cleanPopup(popupWindow) {
421
- if (popupWindow) {
422
- // Close window.
423
- popupWindow.close();
424
- }
425
- // Remove window unload function
426
- window.removeEventListener("beforeunload", this.unloadWindow);
427
- // Interaction is completed - remove interaction status.
428
- this.browserStorage.setInteractionInProgress(false);
429
- }
430
- /**
431
- * Generates the name for the popup based on the client id and request
432
- * @param clientId
433
- * @param request
434
- */
435
- generatePopupName(scopes, authority) {
436
- return `${BrowserConstants.POPUP_NAME_PREFIX}.${this.config.auth.clientId}.${scopes.join("-")}.${authority}.${this.correlationId}`;
437
- }
438
- /**
439
- * Generates the name for the popup based on the client id and request for logouts
440
- * @param clientId
441
- * @param request
442
- */
443
- generateLogoutPopupName(request) {
444
- const homeAccountId = request.account && request.account.homeAccountId;
445
- return `${BrowserConstants.POPUP_NAME_PREFIX}.${this.config.auth.clientId}.${homeAccountId}.${this.correlationId}`;
446
- }
15
+ /*
16
+ * Copyright (c) Microsoft Corporation. All rights reserved.
17
+ * Licensed under the MIT License.
18
+ */
19
+ class PopupClient extends StandardInteractionClient {
20
+ constructor(config, storageImpl, browserCrypto, logger, eventHandler, navigationClient, performanceClient, nativeStorageImpl, nativeMessageHandler, correlationId) {
21
+ super(config, storageImpl, browserCrypto, logger, eventHandler, navigationClient, performanceClient, nativeMessageHandler, correlationId);
22
+ // Properly sets this reference for the unload event.
23
+ this.unloadWindow = this.unloadWindow.bind(this);
24
+ this.nativeStorage = nativeStorageImpl;
25
+ }
26
+ /**
27
+ * Acquires tokens by opening a popup window to the /authorize endpoint of the authority
28
+ * @param request
29
+ */
30
+ acquireToken(request) {
31
+ try {
32
+ const popupName = this.generatePopupName(request.scopes || OIDC_DEFAULT_SCOPES, request.authority || this.config.auth.authority);
33
+ const popupWindowAttributes = request.popupWindowAttributes || {};
34
+ // asyncPopups flag is true. Acquires token without first opening popup. Popup will be opened later asynchronously.
35
+ if (this.config.system.asyncPopups) {
36
+ this.logger.verbose("asyncPopups set to true, acquiring token");
37
+ // Passes on popup position and dimensions if in request
38
+ return this.acquireTokenPopupAsync(request, popupName, popupWindowAttributes);
39
+ }
40
+ else {
41
+ // asyncPopups flag is set to false. Opens popup before acquiring token.
42
+ this.logger.verbose("asyncPopup set to false, opening popup before acquiring token");
43
+ const popup = this.openSizedPopup("about:blank", popupName, popupWindowAttributes);
44
+ return this.acquireTokenPopupAsync(request, popupName, popupWindowAttributes, popup);
45
+ }
46
+ }
47
+ catch (e) {
48
+ return Promise.reject(e);
49
+ }
50
+ }
51
+ /**
52
+ * Clears local cache for the current user then opens a popup window prompting the user to sign-out of the server
53
+ * @param logoutRequest
54
+ */
55
+ logout(logoutRequest) {
56
+ try {
57
+ this.logger.verbose("logoutPopup called");
58
+ const validLogoutRequest = this.initializeLogoutRequest(logoutRequest);
59
+ const popupName = this.generateLogoutPopupName(validLogoutRequest);
60
+ const authority = logoutRequest && logoutRequest.authority;
61
+ const mainWindowRedirectUri = logoutRequest && logoutRequest.mainWindowRedirectUri;
62
+ const popupWindowAttributes = logoutRequest?.popupWindowAttributes || {};
63
+ // asyncPopups flag is true. Acquires token without first opening popup. Popup will be opened later asynchronously.
64
+ if (this.config.system.asyncPopups) {
65
+ this.logger.verbose("asyncPopups set to true");
66
+ // Passes on popup position and dimensions if in request
67
+ return this.logoutPopupAsync(validLogoutRequest, popupName, popupWindowAttributes, authority, undefined, mainWindowRedirectUri);
68
+ }
69
+ else {
70
+ // asyncPopups flag is set to false. Opens popup before logging out.
71
+ this.logger.verbose("asyncPopup set to false, opening popup");
72
+ const popup = this.openSizedPopup("about:blank", popupName, popupWindowAttributes);
73
+ return this.logoutPopupAsync(validLogoutRequest, popupName, popupWindowAttributes, authority, popup, mainWindowRedirectUri);
74
+ }
75
+ }
76
+ catch (e) {
77
+ // Since this function is synchronous we need to reject
78
+ return Promise.reject(e);
79
+ }
80
+ }
81
+ /**
82
+ * Helper which initializes authorization clients and requests
83
+ * @param validRequest
84
+ * @param popupName
85
+ * @param popup
86
+ * @param popupWindowAttributes
87
+ *
88
+ * @returns A promise that is fulfilled when this function has completed, or rejected if an error was raised.
89
+ */
90
+ async acquireTokenPopupAsync(request, popupName, popupWindowAttributes, popup) {
91
+ this.logger.verbose("acquireTokenPopupAsync called");
92
+ const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.acquireTokenPopup);
93
+ const validRequest = await invokeAsync(this.initializeAuthorizationRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationRequest, this.logger, this.performanceClient, this.correlationId)(request, InteractionType.Popup);
94
+ preconnect(validRequest.authority);
95
+ let authClient;
96
+ try {
97
+ // Create auth code request and generate PKCE params
98
+ const authCodeRequest = await invokeAsync(this.initializeAuthorizationCodeRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationCodeRequest, this.logger, this.performanceClient, this.correlationId)(validRequest);
99
+ // Initialize the client
100
+ authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)(serverTelemetryManager, validRequest.authority, validRequest.azureCloudOptions, validRequest.account);
101
+ return await invokeAsync(this.acquireTokenPopupAsyncHelper.bind(this), PerformanceEvents.PopupClientTokenHelper, this.logger, this.performanceClient, this.correlationId)(authClient, authCodeRequest, validRequest, request, popupName, popupWindowAttributes, popup);
102
+ }
103
+ catch (e) {
104
+ if (popup) {
105
+ // Close the synchronous popup if an error is thrown before the window unload event is registered
106
+ popup.close();
107
+ }
108
+ if (e instanceof AuthError) {
109
+ e.setCorrelationId(this.correlationId);
110
+ serverTelemetryManager.cacheFailedRequest(e);
111
+ }
112
+ if (!authClient ||
113
+ !(e instanceof ServerError) ||
114
+ e.errorCode !== BrowserConstants.INVALID_GRANT_ERROR) {
115
+ throw e;
116
+ }
117
+ this.performanceClient.addFields({
118
+ retryError: e.errorCode,
119
+ }, this.correlationId);
120
+ const retryAuthCodeRequest = await invokeAsync(this.initializeAuthorizationCodeRequest.bind(this), PerformanceEvents.StandardInteractionClientInitializeAuthorizationCodeRequest, this.logger, this.performanceClient, this.correlationId)(validRequest);
121
+ return await invokeAsync(this.acquireTokenPopupAsyncHelper.bind(this), PerformanceEvents.PopupClientTokenHelper, this.logger, this.performanceClient, this.correlationId)(authClient, retryAuthCodeRequest, validRequest, request, popupName, popupWindowAttributes, popup);
122
+ }
123
+ }
124
+ /**
125
+ * Helper which obtains an access_token for your API via opening a popup window in the user's browser
126
+ * @param authClient
127
+ * @param authCodeRequest
128
+ * @param validRequest
129
+ * @param request
130
+ * @param popupName
131
+ * @param popupWindowAttributes
132
+ * @param popup
133
+ * @returns A promise that is fulfilled when this function has completed, or rejected if an error was raised.
134
+ */
135
+ async acquireTokenPopupAsyncHelper(authClient, authCodeRequest, validRequest, request, popupName, popupWindowAttributes, popup) {
136
+ const correlationId = validRequest.correlationId;
137
+ this.performanceClient.addQueueMeasurement(PerformanceEvents.PopupClientTokenHelper, correlationId);
138
+ const isNativeBroker = NativeMessageHandler.isNativeAvailable(this.config, this.logger, this.nativeMessageHandler, request.authenticationScheme);
139
+ // Start measurement for server calls with native brokering enabled
140
+ let fetchNativeAccountIdMeasurement;
141
+ if (isNativeBroker) {
142
+ fetchNativeAccountIdMeasurement =
143
+ this.performanceClient.startMeasurement(PerformanceEvents.FetchAccountIdWithNativeBroker, request.correlationId);
144
+ }
145
+ // Create acquire token url.
146
+ const navigateUrl = await authClient.getAuthCodeUrl({
147
+ ...validRequest,
148
+ nativeBroker: isNativeBroker,
149
+ });
150
+ // Create popup interaction handler.
151
+ const interactionHandler = new InteractionHandler(authClient, this.browserStorage, authCodeRequest, this.logger, this.performanceClient);
152
+ // Show the UI once the url has been created. Get the window handle for the popup.
153
+ const popupParameters = {
154
+ popup,
155
+ popupName,
156
+ popupWindowAttributes,
157
+ };
158
+ const popupWindow = this.initiateAuthRequest(navigateUrl, popupParameters);
159
+ this.eventHandler.emitEvent(EventType.POPUP_OPENED, InteractionType.Popup, { popupWindow }, null);
160
+ // Monitor the window for the hash. Return the string value and close the popup when the hash is received. Default timeout is 60 seconds.
161
+ const responseString = await this.monitorPopupForHash(popupWindow);
162
+ const serverParams = invoke(deserializeResponse, PerformanceEvents.DeserializeResponse, this.logger, this.performanceClient, this.correlationId)(responseString, this.config.auth.OIDCOptions.serverResponseType, this.logger);
163
+ // Remove throttle if it exists
164
+ ThrottlingUtils.removeThrottle(this.browserStorage, this.config.auth.clientId, authCodeRequest);
165
+ if (serverParams.accountId) {
166
+ this.logger.verbose("Account id found in hash, calling WAM for token");
167
+ // end measurement for server call with native brokering enabled
168
+ if (fetchNativeAccountIdMeasurement) {
169
+ fetchNativeAccountIdMeasurement.end({
170
+ success: true,
171
+ isNativeBroker: true,
172
+ });
173
+ }
174
+ if (!this.nativeMessageHandler) {
175
+ throw createBrowserAuthError(nativeConnectionNotEstablished);
176
+ }
177
+ 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);
178
+ const { userRequestState } = ProtocolUtils.parseRequestState(this.browserCrypto, validRequest.state);
179
+ return nativeInteractionClient.acquireToken({
180
+ ...validRequest,
181
+ state: userRequestState,
182
+ prompt: undefined, // Server should handle the prompt, ideally native broker can do this part silently
183
+ });
184
+ }
185
+ // Handle response from hash string.
186
+ const result = await interactionHandler.handleCodeResponse(serverParams, validRequest);
187
+ return result;
188
+ }
189
+ /**
190
+ *
191
+ * @param validRequest
192
+ * @param popupName
193
+ * @param requestAuthority
194
+ * @param popup
195
+ * @param mainWindowRedirectUri
196
+ * @param popupWindowAttributes
197
+ */
198
+ async logoutPopupAsync(validRequest, popupName, popupWindowAttributes, requestAuthority, popup, mainWindowRedirectUri) {
199
+ this.logger.verbose("logoutPopupAsync called");
200
+ this.eventHandler.emitEvent(EventType.LOGOUT_START, InteractionType.Popup, validRequest);
201
+ const serverTelemetryManager = this.initializeServerTelemetryManager(ApiId.logoutPopup);
202
+ try {
203
+ // Clear cache on logout
204
+ await this.clearCacheOnLogout(validRequest.account);
205
+ // Initialize the client
206
+ const authClient = await invokeAsync(this.createAuthCodeClient.bind(this), PerformanceEvents.StandardInteractionClientCreateAuthCodeClient, this.logger, this.performanceClient, this.correlationId)(serverTelemetryManager, requestAuthority, undefined, // AzureCloudOptions
207
+ validRequest.account || undefined);
208
+ try {
209
+ authClient.authority.endSessionEndpoint;
210
+ }
211
+ catch {
212
+ if (validRequest.account?.homeAccountId &&
213
+ validRequest.postLogoutRedirectUri &&
214
+ authClient.authority.protocolMode === ProtocolMode.OIDC) {
215
+ void this.browserStorage.removeAccount(validRequest.account?.homeAccountId);
216
+ this.eventHandler.emitEvent(EventType.LOGOUT_SUCCESS, InteractionType.Popup, validRequest);
217
+ if (mainWindowRedirectUri) {
218
+ const navigationOptions = {
219
+ apiId: ApiId.logoutPopup,
220
+ timeout: this.config.system.redirectNavigationTimeout,
221
+ noHistory: false,
222
+ };
223
+ const absoluteUrl = UrlString.getAbsoluteUrl(mainWindowRedirectUri, getCurrentUri());
224
+ await this.navigationClient.navigateInternal(absoluteUrl, navigationOptions);
225
+ }
226
+ if (popup) {
227
+ popup.close();
228
+ }
229
+ return;
230
+ }
231
+ }
232
+ // Create logout string and navigate user window to logout.
233
+ const logoutUri = authClient.getLogoutUri(validRequest);
234
+ this.eventHandler.emitEvent(EventType.LOGOUT_SUCCESS, InteractionType.Popup, validRequest);
235
+ // Open the popup window to requestUrl.
236
+ const popupWindow = this.openPopup(logoutUri, {
237
+ popupName,
238
+ popupWindowAttributes,
239
+ popup,
240
+ });
241
+ this.eventHandler.emitEvent(EventType.POPUP_OPENED, InteractionType.Popup, { popupWindow }, null);
242
+ await this.monitorPopupForHash(popupWindow).catch(() => {
243
+ // Swallow any errors related to monitoring the window. Server logout is best effort
244
+ });
245
+ if (mainWindowRedirectUri) {
246
+ const navigationOptions = {
247
+ apiId: ApiId.logoutPopup,
248
+ timeout: this.config.system.redirectNavigationTimeout,
249
+ noHistory: false,
250
+ };
251
+ const absoluteUrl = UrlString.getAbsoluteUrl(mainWindowRedirectUri, getCurrentUri());
252
+ this.logger.verbose("Redirecting main window to url specified in the request");
253
+ this.logger.verbosePii(`Redirecting main window to: ${absoluteUrl}`);
254
+ await this.navigationClient.navigateInternal(absoluteUrl, navigationOptions);
255
+ }
256
+ else {
257
+ this.logger.verbose("No main window navigation requested");
258
+ }
259
+ }
260
+ catch (e) {
261
+ if (popup) {
262
+ // Close the synchronous popup if an error is thrown before the window unload event is registered
263
+ popup.close();
264
+ }
265
+ if (e instanceof AuthError) {
266
+ e.setCorrelationId(this.correlationId);
267
+ serverTelemetryManager.cacheFailedRequest(e);
268
+ }
269
+ this.browserStorage.setInteractionInProgress(false);
270
+ this.eventHandler.emitEvent(EventType.LOGOUT_FAILURE, InteractionType.Popup, null, e);
271
+ this.eventHandler.emitEvent(EventType.LOGOUT_END, InteractionType.Popup);
272
+ throw e;
273
+ }
274
+ this.eventHandler.emitEvent(EventType.LOGOUT_END, InteractionType.Popup);
275
+ }
276
+ /**
277
+ * Opens a popup window with given request Url.
278
+ * @param requestUrl
279
+ */
280
+ initiateAuthRequest(requestUrl, params) {
281
+ // Check that request url is not empty.
282
+ if (requestUrl) {
283
+ this.logger.infoPii(`Navigate to: ${requestUrl}`);
284
+ // Open the popup window to requestUrl.
285
+ return this.openPopup(requestUrl, params);
286
+ }
287
+ else {
288
+ // Throw error if request URL is empty.
289
+ this.logger.error("Navigate url is empty");
290
+ throw createBrowserAuthError(emptyNavigateUri);
291
+ }
292
+ }
293
+ /**
294
+ * Monitors a window until it loads a url with the same origin.
295
+ * @param popupWindow - window that is being monitored
296
+ * @param timeout - timeout for processing hash once popup is redirected back to application
297
+ */
298
+ monitorPopupForHash(popupWindow) {
299
+ return new Promise((resolve, reject) => {
300
+ this.logger.verbose("PopupHandler.monitorPopupForHash - polling started");
301
+ const intervalId = setInterval(() => {
302
+ // Window is closed
303
+ if (popupWindow.closed) {
304
+ this.logger.error("PopupHandler.monitorPopupForHash - window closed");
305
+ clearInterval(intervalId);
306
+ reject(createBrowserAuthError(userCancelled));
307
+ return;
308
+ }
309
+ let href = "";
310
+ try {
311
+ /*
312
+ * Will throw if cross origin,
313
+ * which should be caught and ignored
314
+ * since we need the interval to keep running while on STS UI.
315
+ */
316
+ href = popupWindow.location.href;
317
+ }
318
+ catch (e) { }
319
+ // Don't process blank pages or cross domain
320
+ if (!href || href === "about:blank") {
321
+ return;
322
+ }
323
+ clearInterval(intervalId);
324
+ let responseString = "";
325
+ const responseType = this.config.auth.OIDCOptions.serverResponseType;
326
+ if (popupWindow) {
327
+ if (responseType === ServerResponseType.QUERY) {
328
+ responseString = popupWindow.location.search;
329
+ }
330
+ else {
331
+ responseString = popupWindow.location.hash;
332
+ }
333
+ }
334
+ this.logger.verbose("PopupHandler.monitorPopupForHash - popup window is on same origin as caller");
335
+ resolve(responseString);
336
+ }, this.config.system.pollIntervalMilliseconds);
337
+ }).finally(() => {
338
+ this.cleanPopup(popupWindow);
339
+ });
340
+ }
341
+ /**
342
+ * @hidden
343
+ *
344
+ * Configures popup window for login.
345
+ *
346
+ * @param urlNavigate
347
+ * @param title
348
+ * @param popUpWidth
349
+ * @param popUpHeight
350
+ * @param popupWindowAttributes
351
+ * @ignore
352
+ * @hidden
353
+ */
354
+ openPopup(urlNavigate, popupParams) {
355
+ try {
356
+ let popupWindow;
357
+ // Popup window passed in, setting url to navigate to
358
+ if (popupParams.popup) {
359
+ popupWindow = popupParams.popup;
360
+ this.logger.verbosePii(`Navigating popup window to: ${urlNavigate}`);
361
+ popupWindow.location.assign(urlNavigate);
362
+ }
363
+ else if (typeof popupParams.popup === "undefined") {
364
+ // Popup will be undefined if it was not passed in
365
+ this.logger.verbosePii(`Opening popup window to: ${urlNavigate}`);
366
+ popupWindow = this.openSizedPopup(urlNavigate, popupParams.popupName, popupParams.popupWindowAttributes);
367
+ }
368
+ // Popup will be null if popups are blocked
369
+ if (!popupWindow) {
370
+ throw createBrowserAuthError(emptyWindowError);
371
+ }
372
+ if (popupWindow.focus) {
373
+ popupWindow.focus();
374
+ }
375
+ this.currentWindow = popupWindow;
376
+ window.addEventListener("beforeunload", this.unloadWindow);
377
+ return popupWindow;
378
+ }
379
+ catch (e) {
380
+ this.logger.error("error opening popup " + e.message);
381
+ this.browserStorage.setInteractionInProgress(false);
382
+ throw createBrowserAuthError(popupWindowError);
383
+ }
384
+ }
385
+ /**
386
+ * Helper function to set popup window dimensions and position
387
+ * @param urlNavigate
388
+ * @param popupName
389
+ * @param popupWindowAttributes
390
+ * @returns
391
+ */
392
+ openSizedPopup(urlNavigate, popupName, popupWindowAttributes) {
393
+ /**
394
+ * adding winLeft and winTop to account for dual monitor
395
+ * using screenLeft and screenTop for IE8 and earlier
396
+ */
397
+ const winLeft = window.screenLeft ? window.screenLeft : window.screenX;
398
+ const winTop = window.screenTop ? window.screenTop : window.screenY;
399
+ /**
400
+ * window.innerWidth displays browser window"s height and width excluding toolbars
401
+ * using document.documentElement.clientWidth for IE8 and earlier
402
+ */
403
+ const winWidth = window.innerWidth ||
404
+ document.documentElement.clientWidth ||
405
+ document.body.clientWidth;
406
+ const winHeight = window.innerHeight ||
407
+ document.documentElement.clientHeight ||
408
+ document.body.clientHeight;
409
+ let width = popupWindowAttributes.popupSize?.width;
410
+ let height = popupWindowAttributes.popupSize?.height;
411
+ let top = popupWindowAttributes.popupPosition?.top;
412
+ let left = popupWindowAttributes.popupPosition?.left;
413
+ if (!width || width < 0 || width > winWidth) {
414
+ this.logger.verbose("Default popup window width used. Window width not configured or invalid.");
415
+ width = BrowserConstants.POPUP_WIDTH;
416
+ }
417
+ if (!height || height < 0 || height > winHeight) {
418
+ this.logger.verbose("Default popup window height used. Window height not configured or invalid.");
419
+ height = BrowserConstants.POPUP_HEIGHT;
420
+ }
421
+ if (!top || top < 0 || top > winHeight) {
422
+ this.logger.verbose("Default popup window top position used. Window top not configured or invalid.");
423
+ top = Math.max(0, winHeight / 2 - BrowserConstants.POPUP_HEIGHT / 2 + winTop);
424
+ }
425
+ if (!left || left < 0 || left > winWidth) {
426
+ this.logger.verbose("Default popup window left position used. Window left not configured or invalid.");
427
+ left = Math.max(0, winWidth / 2 - BrowserConstants.POPUP_WIDTH / 2 + winLeft);
428
+ }
429
+ return window.open(urlNavigate, popupName, `width=${width}, height=${height}, top=${top}, left=${left}, scrollbars=yes`);
430
+ }
431
+ /**
432
+ * Event callback to unload main window.
433
+ */
434
+ unloadWindow(e) {
435
+ this.browserStorage.cleanRequestByInteractionType(InteractionType.Popup);
436
+ if (this.currentWindow) {
437
+ this.currentWindow.close();
438
+ }
439
+ // Guarantees browser unload will happen, so no other errors will be thrown.
440
+ e.preventDefault();
441
+ }
442
+ /**
443
+ * Closes popup, removes any state vars created during popup calls.
444
+ * @param popupWindow
445
+ */
446
+ cleanPopup(popupWindow) {
447
+ if (popupWindow) {
448
+ // Close window.
449
+ popupWindow.close();
450
+ }
451
+ // Remove window unload function
452
+ window.removeEventListener("beforeunload", this.unloadWindow);
453
+ // Interaction is completed - remove interaction status.
454
+ this.browserStorage.setInteractionInProgress(false);
455
+ }
456
+ /**
457
+ * Generates the name for the popup based on the client id and request
458
+ * @param clientId
459
+ * @param request
460
+ */
461
+ generatePopupName(scopes, authority) {
462
+ return `${BrowserConstants.POPUP_NAME_PREFIX}.${this.config.auth.clientId}.${scopes.join("-")}.${authority}.${this.correlationId}`;
463
+ }
464
+ /**
465
+ * Generates the name for the popup based on the client id and request for logouts
466
+ * @param clientId
467
+ * @param request
468
+ */
469
+ generateLogoutPopupName(request) {
470
+ const homeAccountId = request.account && request.account.homeAccountId;
471
+ return `${BrowserConstants.POPUP_NAME_PREFIX}.${this.config.auth.clientId}.${homeAccountId}.${this.correlationId}`;
472
+ }
447
473
  }
448
474
 
449
475
  export { PopupClient };