@azure/msal-browser 3.11.0 → 3.13.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 (92) hide show
  1. package/dist/app/IPublicClientApplication.mjs +1 -1
  2. package/dist/app/PublicClientApplication.mjs +1 -1
  3. package/dist/app/PublicClientNext.mjs +1 -1
  4. package/dist/broker/nativeBroker/NativeMessageHandler.mjs +1 -1
  5. package/dist/broker/nativeBroker/NativeStatusCodes.mjs +1 -1
  6. package/dist/cache/AsyncMemoryStorage.mjs +1 -1
  7. package/dist/cache/BrowserCacheManager.d.ts +10 -2
  8. package/dist/cache/BrowserCacheManager.d.ts.map +1 -1
  9. package/dist/cache/BrowserCacheManager.mjs +31 -3
  10. package/dist/cache/BrowserCacheManager.mjs.map +1 -1
  11. package/dist/cache/BrowserStorage.mjs +1 -1
  12. package/dist/cache/DatabaseStorage.mjs +1 -1
  13. package/dist/cache/MemoryStorage.mjs +1 -1
  14. package/dist/cache/TokenCache.mjs +1 -1
  15. package/dist/config/Configuration.mjs +1 -1
  16. package/dist/controllers/ControllerFactory.mjs +1 -1
  17. package/dist/controllers/NestedAppAuthController.d.ts.map +1 -1
  18. package/dist/controllers/NestedAppAuthController.mjs +3 -8
  19. package/dist/controllers/NestedAppAuthController.mjs.map +1 -1
  20. package/dist/controllers/StandardController.d.ts +14 -0
  21. package/dist/controllers/StandardController.d.ts.map +1 -1
  22. package/dist/controllers/StandardController.mjs +162 -103
  23. package/dist/controllers/StandardController.mjs.map +1 -1
  24. package/dist/controllers/UnknownOperatingContextController.d.ts.map +1 -1
  25. package/dist/controllers/UnknownOperatingContextController.mjs +2 -2
  26. package/dist/controllers/UnknownOperatingContextController.mjs.map +1 -1
  27. package/dist/crypto/BrowserCrypto.mjs +1 -1
  28. package/dist/crypto/CryptoOps.mjs +1 -1
  29. package/dist/crypto/PkceGenerator.mjs +1 -1
  30. package/dist/crypto/SignedHttpRequest.mjs +1 -1
  31. package/dist/encode/Base64Decode.mjs +1 -1
  32. package/dist/encode/Base64Encode.mjs +1 -1
  33. package/dist/error/BrowserAuthError.mjs +1 -1
  34. package/dist/error/BrowserAuthErrorCodes.mjs +1 -1
  35. package/dist/error/BrowserConfigurationAuthError.mjs +1 -1
  36. package/dist/error/BrowserConfigurationAuthErrorCodes.mjs +1 -1
  37. package/dist/error/NativeAuthError.mjs +1 -1
  38. package/dist/error/NativeAuthErrorCodes.mjs +1 -1
  39. package/dist/error/NestedAppAuthError.mjs +1 -1
  40. package/dist/event/EventHandler.mjs +1 -1
  41. package/dist/event/EventMessage.mjs +1 -1
  42. package/dist/event/EventType.mjs +1 -1
  43. package/dist/index.mjs +1 -1
  44. package/dist/interaction_client/BaseInteractionClient.mjs +1 -1
  45. package/dist/interaction_client/HybridSpaAuthorizationCodeClient.mjs +1 -1
  46. package/dist/interaction_client/NativeInteractionClient.mjs +1 -1
  47. package/dist/interaction_client/PopupClient.mjs +1 -1
  48. package/dist/interaction_client/RedirectClient.mjs +1 -1
  49. package/dist/interaction_client/SilentAuthCodeClient.mjs +1 -1
  50. package/dist/interaction_client/SilentCacheClient.mjs +1 -1
  51. package/dist/interaction_client/SilentIframeClient.mjs +1 -1
  52. package/dist/interaction_client/SilentRefreshClient.mjs +1 -1
  53. package/dist/interaction_client/StandardInteractionClient.mjs +1 -1
  54. package/dist/interaction_handler/InteractionHandler.mjs +1 -1
  55. package/dist/interaction_handler/RedirectHandler.mjs +1 -1
  56. package/dist/interaction_handler/SilentHandler.mjs +2 -1
  57. package/dist/interaction_handler/SilentHandler.mjs.map +1 -1
  58. package/dist/naa/BridgeError.mjs +1 -1
  59. package/dist/naa/BridgeProxy.d.ts +0 -2
  60. package/dist/naa/BridgeProxy.d.ts.map +1 -1
  61. package/dist/naa/BridgeProxy.mjs +4 -10
  62. package/dist/naa/BridgeProxy.mjs.map +1 -1
  63. package/dist/naa/BridgeStatusCode.mjs +1 -1
  64. package/dist/naa/mapping/NestedAppAuthAdapter.mjs +1 -1
  65. package/dist/navigation/NavigationClient.mjs +1 -1
  66. package/dist/network/FetchClient.mjs +1 -1
  67. package/dist/operatingcontext/BaseOperatingContext.mjs +1 -1
  68. package/dist/operatingcontext/StandardOperatingContext.mjs +1 -1
  69. package/dist/operatingcontext/TeamsAppOperatingContext.mjs +1 -1
  70. package/dist/operatingcontext/UnknownOperatingContext.mjs +1 -1
  71. package/dist/packageMetadata.d.ts +1 -1
  72. package/dist/packageMetadata.mjs +2 -2
  73. package/dist/request/RequestHelpers.mjs +1 -1
  74. package/dist/response/ResponseHandler.mjs +1 -1
  75. package/dist/telemetry/BrowserPerformanceClient.mjs +1 -1
  76. package/dist/telemetry/BrowserPerformanceMeasurement.mjs +1 -1
  77. package/dist/utils/BrowserConstants.mjs +1 -1
  78. package/dist/utils/BrowserProtocolUtils.mjs +1 -1
  79. package/dist/utils/BrowserUtils.mjs +1 -1
  80. package/lib/msal-browser.cjs +364 -207
  81. package/lib/msal-browser.cjs.map +1 -1
  82. package/lib/msal-browser.js +364 -207
  83. package/lib/msal-browser.js.map +1 -1
  84. package/lib/msal-browser.min.js +67 -66
  85. package/package.json +4 -4
  86. package/src/cache/BrowserCacheManager.ts +49 -1
  87. package/src/controllers/NestedAppAuthController.ts +7 -6
  88. package/src/controllers/StandardController.ts +329 -246
  89. package/src/controllers/UnknownOperatingContextController.ts +3 -1
  90. package/src/interaction_handler/SilentHandler.ts +1 -0
  91. package/src/naa/BridgeProxy.ts +3 -12
  92. package/src/packageMetadata.ts +1 -1
@@ -141,6 +141,9 @@ export class StandardController implements IController {
141
141
  Promise<AuthenticationResult>
142
142
  >;
143
143
 
144
+ // Active Iframe request
145
+ private activeIframeRequest: [Promise<void>, string] | undefined;
146
+
144
147
  private ssoSilentMeasurement?: InProgressPerformanceEvent;
145
148
  private acquireTokenByCodeAsyncMeasurement?: InProgressPerformanceEvent;
146
149
  /**
@@ -204,7 +207,8 @@ export class StandardController implements IController {
204
207
  this.config.cache,
205
208
  this.browserCrypto,
206
209
  this.logger,
207
- buildStaticAuthorityOptions(this.config.auth)
210
+ buildStaticAuthorityOptions(this.config.auth),
211
+ this.performanceClient
208
212
  )
209
213
  : DEFAULT_BROWSER_CACHE_MANAGER(
210
214
  this.config.auth.clientId,
@@ -224,7 +228,9 @@ export class StandardController implements IController {
224
228
  this.config.auth.clientId,
225
229
  nativeCacheOptions,
226
230
  this.browserCrypto,
227
- this.logger
231
+ this.logger,
232
+ undefined,
233
+ this.performanceClient
228
234
  );
229
235
 
230
236
  // Initialize the token cache
@@ -332,7 +338,6 @@ export class StandardController implements IController {
332
338
  // Block token acquisition before initialize has been called
333
339
  BrowserUtils.blockAPICallsBeforeInitialize(this.initialized);
334
340
 
335
- const loggedInAccounts = this.getAllAccounts();
336
341
  if (this.isBrowserEnvironment) {
337
342
  /**
338
343
  * Store the promise on the PublicClientApplication instance if this is the first invocation of handleRedirectPromise,
@@ -342,155 +347,11 @@ export class StandardController implements IController {
342
347
  const redirectResponseKey = hash || "";
343
348
  let response = this.redirectResponse.get(redirectResponseKey);
344
349
  if (typeof response === "undefined") {
345
- const request: NativeTokenRequest | null =
346
- this.browserStorage.getCachedNativeRequest();
347
- const useNative =
348
- request &&
349
- NativeMessageHandler.isNativeAvailable(
350
- this.config,
351
- this.logger,
352
- this.nativeExtensionProvider
353
- ) &&
354
- this.nativeExtensionProvider &&
355
- !hash;
356
- const correlationId = useNative
357
- ? request?.correlationId
358
- : this.browserStorage.getTemporaryCache(
359
- TemporaryCacheKeys.CORRELATION_ID,
360
- true
361
- ) || "";
362
- const rootMeasurement = this.performanceClient.startMeasurement(
363
- "acquireTokenRedirect",
364
- correlationId
365
- );
366
- this.eventHandler.emitEvent(
367
- EventType.HANDLE_REDIRECT_START,
368
- InteractionType.Redirect
369
- );
350
+ response = this.handleRedirectPromiseInternal(hash);
351
+ this.redirectResponse.set(redirectResponseKey, response);
370
352
  this.logger.verbose(
371
353
  "handleRedirectPromise has been called for the first time, storing the promise"
372
354
  );
373
- let redirectResponse: Promise<AuthenticationResult | null>;
374
- if (useNative && this.nativeExtensionProvider) {
375
- this.logger.trace(
376
- "handleRedirectPromise - acquiring token from native platform"
377
- );
378
- const nativeClient = new NativeInteractionClient(
379
- this.config,
380
- this.browserStorage,
381
- this.browserCrypto,
382
- this.logger,
383
- this.eventHandler,
384
- this.navigationClient,
385
- ApiId.handleRedirectPromise,
386
- this.performanceClient,
387
- this.nativeExtensionProvider,
388
- request.accountId,
389
- this.nativeInternalStorage,
390
- request.correlationId
391
- );
392
-
393
- redirectResponse = invokeAsync(
394
- nativeClient.handleRedirectPromise.bind(nativeClient),
395
- PerformanceEvents.HandleNativeRedirectPromiseMeasurement,
396
- this.logger,
397
- this.performanceClient,
398
- rootMeasurement.event.correlationId
399
- )(
400
- this.performanceClient,
401
- rootMeasurement.event.correlationId
402
- );
403
- } else {
404
- this.logger.trace(
405
- "handleRedirectPromise - acquiring token from web flow"
406
- );
407
- const redirectClient =
408
- this.createRedirectClient(correlationId);
409
- redirectResponse = invokeAsync(
410
- redirectClient.handleRedirectPromise.bind(
411
- redirectClient
412
- ),
413
- PerformanceEvents.HandleRedirectPromiseMeasurement,
414
- this.logger,
415
- this.performanceClient,
416
- rootMeasurement.event.correlationId
417
- )(
418
- hash,
419
- this.performanceClient,
420
- rootMeasurement.event.correlationId
421
- );
422
- }
423
-
424
- response = redirectResponse
425
- .then((result: AuthenticationResult | null) => {
426
- if (result) {
427
- // Emit login event if number of accounts change
428
-
429
- const isLoggingIn =
430
- loggedInAccounts.length <
431
- this.getAllAccounts().length;
432
- if (isLoggingIn) {
433
- this.eventHandler.emitEvent(
434
- EventType.LOGIN_SUCCESS,
435
- InteractionType.Redirect,
436
- result
437
- );
438
- this.logger.verbose(
439
- "handleRedirectResponse returned result, login success"
440
- );
441
- } else {
442
- this.eventHandler.emitEvent(
443
- EventType.ACQUIRE_TOKEN_SUCCESS,
444
- InteractionType.Redirect,
445
- result
446
- );
447
- this.logger.verbose(
448
- "handleRedirectResponse returned result, acquire token success"
449
- );
450
- }
451
- rootMeasurement.end({ success: true });
452
- }
453
- this.eventHandler.emitEvent(
454
- EventType.HANDLE_REDIRECT_END,
455
- InteractionType.Redirect
456
- );
457
- rootMeasurement.end({ success: false });
458
-
459
- return result;
460
- })
461
- .catch((e) => {
462
- const eventError = e as EventError;
463
- // Emit login event if there is an account
464
- if (loggedInAccounts.length > 0) {
465
- this.eventHandler.emitEvent(
466
- EventType.ACQUIRE_TOKEN_FAILURE,
467
- InteractionType.Redirect,
468
- null,
469
- eventError
470
- );
471
- } else {
472
- this.eventHandler.emitEvent(
473
- EventType.LOGIN_FAILURE,
474
- InteractionType.Redirect,
475
- null,
476
- eventError
477
- );
478
- }
479
- this.eventHandler.emitEvent(
480
- EventType.HANDLE_REDIRECT_END,
481
- InteractionType.Redirect
482
- );
483
-
484
- rootMeasurement.end(
485
- {
486
- success: false,
487
- },
488
- eventError
489
- );
490
-
491
- throw e;
492
- });
493
- this.redirectResponse.set(redirectResponseKey, response);
494
355
  } else {
495
356
  this.logger.verbose(
496
357
  "handleRedirectPromise has been called previously, returning the result from the first call"
@@ -505,6 +366,156 @@ export class StandardController implements IController {
505
366
  return null;
506
367
  }
507
368
 
369
+ /**
370
+ * The internal details of handleRedirectPromise. This is separated out to a helper to allow handleRedirectPromise to memoize requests
371
+ * @param hash
372
+ * @returns
373
+ */
374
+ private async handleRedirectPromiseInternal(
375
+ hash?: string
376
+ ): Promise<AuthenticationResult | null> {
377
+ const loggedInAccounts = this.getAllAccounts();
378
+ const request: NativeTokenRequest | null =
379
+ this.browserStorage.getCachedNativeRequest();
380
+ const useNative =
381
+ request &&
382
+ NativeMessageHandler.isNativeAvailable(
383
+ this.config,
384
+ this.logger,
385
+ this.nativeExtensionProvider
386
+ ) &&
387
+ this.nativeExtensionProvider &&
388
+ !hash;
389
+ const correlationId = useNative
390
+ ? request?.correlationId
391
+ : this.browserStorage.getTemporaryCache(
392
+ TemporaryCacheKeys.CORRELATION_ID,
393
+ true
394
+ ) || "";
395
+ const rootMeasurement = this.performanceClient.startMeasurement(
396
+ "acquireTokenRedirect",
397
+ correlationId
398
+ );
399
+ this.eventHandler.emitEvent(
400
+ EventType.HANDLE_REDIRECT_START,
401
+ InteractionType.Redirect
402
+ );
403
+
404
+ let redirectResponse: Promise<AuthenticationResult | null>;
405
+ if (useNative && this.nativeExtensionProvider) {
406
+ this.logger.trace(
407
+ "handleRedirectPromise - acquiring token from native platform"
408
+ );
409
+ const nativeClient = new NativeInteractionClient(
410
+ this.config,
411
+ this.browserStorage,
412
+ this.browserCrypto,
413
+ this.logger,
414
+ this.eventHandler,
415
+ this.navigationClient,
416
+ ApiId.handleRedirectPromise,
417
+ this.performanceClient,
418
+ this.nativeExtensionProvider,
419
+ request.accountId,
420
+ this.nativeInternalStorage,
421
+ request.correlationId
422
+ );
423
+
424
+ redirectResponse = invokeAsync(
425
+ nativeClient.handleRedirectPromise.bind(nativeClient),
426
+ PerformanceEvents.HandleNativeRedirectPromiseMeasurement,
427
+ this.logger,
428
+ this.performanceClient,
429
+ rootMeasurement.event.correlationId
430
+ )(this.performanceClient, rootMeasurement.event.correlationId);
431
+ } else {
432
+ this.logger.trace(
433
+ "handleRedirectPromise - acquiring token from web flow"
434
+ );
435
+ const redirectClient = this.createRedirectClient(correlationId);
436
+ redirectResponse = invokeAsync(
437
+ redirectClient.handleRedirectPromise.bind(redirectClient),
438
+ PerformanceEvents.HandleRedirectPromiseMeasurement,
439
+ this.logger,
440
+ this.performanceClient,
441
+ rootMeasurement.event.correlationId
442
+ )(
443
+ hash,
444
+ this.performanceClient,
445
+ rootMeasurement.event.correlationId
446
+ );
447
+ }
448
+
449
+ return redirectResponse
450
+ .then((result: AuthenticationResult | null) => {
451
+ if (result) {
452
+ // Emit login event if number of accounts change
453
+
454
+ const isLoggingIn =
455
+ loggedInAccounts.length < this.getAllAccounts().length;
456
+ if (isLoggingIn) {
457
+ this.eventHandler.emitEvent(
458
+ EventType.LOGIN_SUCCESS,
459
+ InteractionType.Redirect,
460
+ result
461
+ );
462
+ this.logger.verbose(
463
+ "handleRedirectResponse returned result, login success"
464
+ );
465
+ } else {
466
+ this.eventHandler.emitEvent(
467
+ EventType.ACQUIRE_TOKEN_SUCCESS,
468
+ InteractionType.Redirect,
469
+ result
470
+ );
471
+ this.logger.verbose(
472
+ "handleRedirectResponse returned result, acquire token success"
473
+ );
474
+ }
475
+ rootMeasurement.end({ success: true });
476
+ }
477
+ this.eventHandler.emitEvent(
478
+ EventType.HANDLE_REDIRECT_END,
479
+ InteractionType.Redirect
480
+ );
481
+ rootMeasurement.end({ success: false });
482
+
483
+ return result;
484
+ })
485
+ .catch((e) => {
486
+ const eventError = e as EventError;
487
+ // Emit login event if there is an account
488
+ if (loggedInAccounts.length > 0) {
489
+ this.eventHandler.emitEvent(
490
+ EventType.ACQUIRE_TOKEN_FAILURE,
491
+ InteractionType.Redirect,
492
+ null,
493
+ eventError
494
+ );
495
+ } else {
496
+ this.eventHandler.emitEvent(
497
+ EventType.LOGIN_FAILURE,
498
+ InteractionType.Redirect,
499
+ null,
500
+ eventError
501
+ );
502
+ }
503
+ this.eventHandler.emitEvent(
504
+ EventType.HANDLE_REDIRECT_END,
505
+ InteractionType.Redirect
506
+ );
507
+
508
+ rootMeasurement.end(
509
+ {
510
+ success: false,
511
+ },
512
+ eventError
513
+ );
514
+
515
+ throw e;
516
+ });
517
+ }
518
+
508
519
  /**
509
520
  * Use when you want to obtain an access_token for your API by redirecting the user's browser window to the authorization endpoint. This function redirects
510
521
  * the page, so any code that follows this function will not execute.
@@ -1966,24 +1977,180 @@ export class StandardController implements IController {
1966
1977
  document.addEventListener("visibilitychange", () =>
1967
1978
  this.trackPageVisibility(request.correlationId)
1968
1979
  );
1969
- let result: Promise<AuthenticationResult>;
1980
+
1981
+ const silentRequest = await invokeAsync(
1982
+ initializeSilentRequest,
1983
+ PerformanceEvents.InitializeSilentRequest,
1984
+ this.logger,
1985
+ this.performanceClient,
1986
+ request.correlationId
1987
+ )(request, account, this.config, this.performanceClient, this.logger);
1988
+ const cacheLookupPolicy =
1989
+ request.cacheLookupPolicy || CacheLookupPolicy.Default;
1990
+
1991
+ const result = this.acquireTokenSilentNoIframe(
1992
+ silentRequest,
1993
+ cacheLookupPolicy
1994
+ ).catch(async (refreshTokenError: AuthError) => {
1995
+ const shouldTryToResolveSilently =
1996
+ checkIfRefreshTokenErrorCanBeResolvedSilently(
1997
+ refreshTokenError,
1998
+ cacheLookupPolicy
1999
+ );
2000
+
2001
+ if (shouldTryToResolveSilently) {
2002
+ if (!this.activeIframeRequest) {
2003
+ let _resolve: () => void,
2004
+ _reject: (reason?: AuthError | Error) => void;
2005
+ // Always set the active request tracker immediately after checking it to prevent races
2006
+ this.activeIframeRequest = [
2007
+ new Promise((resolve, reject) => {
2008
+ _resolve = resolve;
2009
+ _reject = reject;
2010
+ }),
2011
+ silentRequest.correlationId,
2012
+ ];
2013
+ this.logger.verbose(
2014
+ "Refresh token expired/invalid or CacheLookupPolicy is set to Skip, attempting acquire token by iframe.",
2015
+ silentRequest.correlationId
2016
+ );
2017
+ return invokeAsync(
2018
+ this.acquireTokenBySilentIframe.bind(this),
2019
+ PerformanceEvents.AcquireTokenBySilentIframe,
2020
+ this.logger,
2021
+ this.performanceClient,
2022
+ silentRequest.correlationId
2023
+ )(silentRequest)
2024
+ .then((iframeResult) => {
2025
+ _resolve();
2026
+ return iframeResult;
2027
+ })
2028
+ .catch((e) => {
2029
+ _reject(e);
2030
+ throw e;
2031
+ })
2032
+ .finally(() => {
2033
+ this.activeIframeRequest = undefined;
2034
+ });
2035
+ } else if (cacheLookupPolicy !== CacheLookupPolicy.Skip) {
2036
+ const [activePromise, activeCorrelationId] =
2037
+ this.activeIframeRequest;
2038
+ this.logger.verbose(
2039
+ `Iframe request is already in progress, awaiting resolution for request with correlationId: ${activeCorrelationId}`,
2040
+ silentRequest.correlationId
2041
+ );
2042
+ const awaitConcurrentIframeMeasure =
2043
+ this.performanceClient.startMeasurement(
2044
+ PerformanceEvents.AwaitConcurrentIframe,
2045
+ silentRequest.correlationId
2046
+ );
2047
+ awaitConcurrentIframeMeasure.add({
2048
+ awaitIframeCorrelationId: activeCorrelationId,
2049
+ });
2050
+
2051
+ // Await for errors first so we can distinguish errors thrown by activePromise versus errors thrown by .then below
2052
+ await activePromise.catch(() => {
2053
+ awaitConcurrentIframeMeasure.end({
2054
+ success: false,
2055
+ });
2056
+ this.logger.info(
2057
+ `Iframe request with correlationId: ${activeCorrelationId} failed. Interaction is required.`
2058
+ );
2059
+ // If previous iframe request failed, it's unlikely to succeed this time. Throw original error.
2060
+ throw refreshTokenError;
2061
+ });
2062
+
2063
+ return activePromise.then(() => {
2064
+ awaitConcurrentIframeMeasure.end({ success: true });
2065
+ this.logger.verbose(
2066
+ `Parallel iframe request with correlationId: ${activeCorrelationId} succeeded. Retrying cache and/or RT redemption`,
2067
+ silentRequest.correlationId
2068
+ );
2069
+ // Retry cache lookup and/or RT exchange after iframe completes
2070
+ return this.acquireTokenSilentNoIframe(
2071
+ silentRequest,
2072
+ cacheLookupPolicy
2073
+ );
2074
+ });
2075
+ } else {
2076
+ // Cache policy set to skip and another iframe request is already in progress
2077
+ this.logger.warning(
2078
+ "Another iframe request is currently in progress and CacheLookupPolicy is set to Skip. This may result in degraded performance and/or reliability for both calls. Please consider changing the CacheLookupPolicy to take advantage of request queuing and token cache.",
2079
+ silentRequest.correlationId
2080
+ );
2081
+ return invokeAsync(
2082
+ this.acquireTokenBySilentIframe.bind(this),
2083
+ PerformanceEvents.AcquireTokenBySilentIframe,
2084
+ this.logger,
2085
+ this.performanceClient,
2086
+ silentRequest.correlationId
2087
+ )(silentRequest);
2088
+ }
2089
+ } else {
2090
+ // Error cannot be silently resolved or iframe renewal is not allowed, interaction required
2091
+ throw refreshTokenError;
2092
+ }
2093
+ });
2094
+
2095
+ return result
2096
+ .then((response) => {
2097
+ this.eventHandler.emitEvent(
2098
+ EventType.ACQUIRE_TOKEN_SUCCESS,
2099
+ InteractionType.Silent,
2100
+ response
2101
+ );
2102
+ if (request.correlationId) {
2103
+ this.performanceClient.addFields(
2104
+ {
2105
+ fromCache: response.fromCache,
2106
+ isNativeBroker: response.fromNativeBroker,
2107
+ requestId: response.requestId,
2108
+ },
2109
+ request.correlationId
2110
+ );
2111
+ }
2112
+
2113
+ return response;
2114
+ })
2115
+ .catch((tokenRenewalError: Error) => {
2116
+ this.eventHandler.emitEvent(
2117
+ EventType.ACQUIRE_TOKEN_FAILURE,
2118
+ InteractionType.Silent,
2119
+ null,
2120
+ tokenRenewalError
2121
+ );
2122
+ throw tokenRenewalError;
2123
+ })
2124
+ .finally(() => {
2125
+ document.removeEventListener("visibilitychange", () =>
2126
+ this.trackPageVisibility(request.correlationId)
2127
+ );
2128
+ });
2129
+ }
2130
+
2131
+ /**
2132
+ * AcquireTokenSilent without the iframe fallback. This is used to enable the correct fallbacks in cases where there's a potential for multiple silent requests to be made in parallel and prevent those requests from making concurrent iframe requests.
2133
+ * @param silentRequest
2134
+ * @param cacheLookupPolicy
2135
+ * @returns
2136
+ */
2137
+ private async acquireTokenSilentNoIframe(
2138
+ silentRequest: CommonSilentFlowRequest,
2139
+ cacheLookupPolicy: CacheLookupPolicy
2140
+ ): Promise<AuthenticationResult> {
1970
2141
  if (
1971
2142
  NativeMessageHandler.isNativeAvailable(
1972
2143
  this.config,
1973
2144
  this.logger,
1974
2145
  this.nativeExtensionProvider,
1975
- request.authenticationScheme
2146
+ silentRequest.authenticationScheme
1976
2147
  ) &&
1977
- account.nativeAccountId
2148
+ silentRequest.account.nativeAccountId
1978
2149
  ) {
1979
2150
  this.logger.verbose(
1980
2151
  "acquireTokenSilent - attempting to acquire token from native platform"
1981
2152
  );
1982
- const silentRequest: SilentRequest = {
1983
- ...request,
1984
- account,
1985
- };
1986
- result = this.acquireTokenNative(
2153
+ return this.acquireTokenNative(
1987
2154
  silentRequest,
1988
2155
  ApiId.acquireTokenSilent_silentFlow
1989
2156
  ).catch(async (e: AuthError) => {
@@ -1995,10 +2162,9 @@ export class StandardController implements IController {
1995
2162
  this.nativeExtensionProvider = undefined; // Prevent future requests from continuing to attempt
1996
2163
 
1997
2164
  // Cache will not contain tokens, given that previous WAM requests succeeded. Skip cache and RT renewal and go straight to iframe renewal
1998
- const silentIframeClient = this.createSilentIframeClient(
1999
- request.correlationId
2165
+ throw createClientAuthError(
2166
+ ClientAuthErrorCodes.tokenRefreshRequired
2000
2167
  );
2001
- return silentIframeClient.acquireToken(request);
2002
2168
  }
2003
2169
  throw e;
2004
2170
  });
@@ -2006,25 +2172,7 @@ export class StandardController implements IController {
2006
2172
  this.logger.verbose(
2007
2173
  "acquireTokenSilent - attempting to acquire token from web flow"
2008
2174
  );
2009
-
2010
- const silentRequest = await invokeAsync(
2011
- initializeSilentRequest,
2012
- PerformanceEvents.InitializeSilentRequest,
2013
- this.logger,
2014
- this.performanceClient,
2015
- request.correlationId
2016
- )(
2017
- request,
2018
- account,
2019
- this.config,
2020
- this.performanceClient,
2021
- this.logger
2022
- );
2023
-
2024
- const cacheLookupPolicy =
2025
- request.cacheLookupPolicy || CacheLookupPolicy.Default;
2026
-
2027
- result = invokeAsync(
2175
+ return invokeAsync(
2028
2176
  this.acquireTokenFromCache.bind(this),
2029
2177
  PerformanceEvents.AcquireTokenFromCache,
2030
2178
  this.logger,
@@ -2032,10 +2180,7 @@ export class StandardController implements IController {
2032
2180
  silentRequest.correlationId
2033
2181
  )(silentRequest, cacheLookupPolicy).catch(
2034
2182
  (cacheError: AuthError) => {
2035
- if (
2036
- request.cacheLookupPolicy ===
2037
- CacheLookupPolicy.AccessToken
2038
- ) {
2183
+ if (cacheLookupPolicy === CacheLookupPolicy.AccessToken) {
2039
2184
  throw cacheError;
2040
2185
  }
2041
2186
 
@@ -2051,71 +2196,10 @@ export class StandardController implements IController {
2051
2196
  this.logger,
2052
2197
  this.performanceClient,
2053
2198
  silentRequest.correlationId
2054
- )(silentRequest, cacheLookupPolicy).catch(
2055
- (refreshTokenError: AuthError) => {
2056
- const shouldTryToResolveSilently =
2057
- checkIfRefreshTokenErrorCanBeResolvedSilently(
2058
- refreshTokenError,
2059
- silentRequest,
2060
- cacheLookupPolicy
2061
- );
2062
-
2063
- if (shouldTryToResolveSilently) {
2064
- this.logger.verbose(
2065
- "Refresh token expired/invalid or CacheLookupPolicy is set to Skip, attempting acquire token by iframe.",
2066
- silentRequest.correlationId
2067
- );
2068
- return invokeAsync(
2069
- this.acquireTokenBySilentIframe.bind(this),
2070
- PerformanceEvents.AcquireTokenBySilentIframe,
2071
- this.logger,
2072
- this.performanceClient,
2073
- silentRequest.correlationId
2074
- )(silentRequest);
2075
- } else {
2076
- // Error cannot be silently resolved or iframe renewal is not allowed, interaction required
2077
- throw refreshTokenError;
2078
- }
2079
- }
2080
- );
2199
+ )(silentRequest, cacheLookupPolicy);
2081
2200
  }
2082
2201
  );
2083
2202
  }
2084
-
2085
- return result
2086
- .then((response) => {
2087
- this.eventHandler.emitEvent(
2088
- EventType.ACQUIRE_TOKEN_SUCCESS,
2089
- InteractionType.Silent,
2090
- response
2091
- );
2092
- if (request.correlationId) {
2093
- this.performanceClient.addFields(
2094
- {
2095
- fromCache: response.fromCache,
2096
- isNativeBroker: response.fromNativeBroker,
2097
- requestId: response.requestId,
2098
- },
2099
- request.correlationId
2100
- );
2101
- }
2102
-
2103
- return response;
2104
- })
2105
- .catch((tokenRenewalError: Error) => {
2106
- this.eventHandler.emitEvent(
2107
- EventType.ACQUIRE_TOKEN_FAILURE,
2108
- InteractionType.Silent,
2109
- null,
2110
- tokenRenewalError
2111
- );
2112
- throw tokenRenewalError;
2113
- })
2114
- .finally(() => {
2115
- document.removeEventListener("visibilitychange", () =>
2116
- this.trackPageVisibility(request.correlationId)
2117
- );
2118
- });
2119
2203
  }
2120
2204
  }
2121
2205
 
@@ -2128,7 +2212,6 @@ export class StandardController implements IController {
2128
2212
  */
2129
2213
  function checkIfRefreshTokenErrorCanBeResolvedSilently(
2130
2214
  refreshTokenError: AuthError,
2131
- silentRequest: CommonSilentFlowRequest,
2132
2215
  cacheLookupPolicy: CacheLookupPolicy
2133
2216
  ): boolean {
2134
2217
  const noInteractionRequired = !(
@@ -106,7 +106,9 @@ export class UnknownOperatingContextController implements IController {
106
106
  this.config.auth.clientId,
107
107
  this.config.cache,
108
108
  this.browserCrypto,
109
- this.logger
109
+ this.logger,
110
+ undefined,
111
+ this.performanceClient
110
112
  )
111
113
  : DEFAULT_BROWSER_CACHE_MANAGER(
112
114
  this.config.auth.clientId,
@@ -195,6 +195,7 @@ function loadFrameSync(urlNavigate: string): HTMLIFrameElement {
195
195
  function createHiddenIframe(): HTMLIFrameElement {
196
196
  const authFrame = document.createElement("iframe");
197
197
 
198
+ authFrame.className = "msalSilentIframe";
198
199
  authFrame.style.visibility = "hidden";
199
200
  authFrame.style.position = "absolute";
200
201
  authFrame.style.width = authFrame.style.height = "0";