Skip to content

Outlook add-in: Nested App Authentication does not work when third-party cookies are disabled in the browser #7280

Open
@adrianhrinko

Description

@adrianhrinko

Core Library

MSAL.js (@azure/msal-browser)

Core Library Version

3.21.0

Wrapper Library

Not Applicable

Wrapper Library Version

None

Public or Confidential Client?

Public

Description

Our Motivation for Using MSAL-Browser:

We encountered issues with SSO token retrieval using the OBO flow due to new third-party cookie restrictions in Safari, Firefox, and, most recently, in Chrome's incognito mode. As it is essential for our Outlook add-in to securely retrieve the SSO token, we decided to implement token retrieval using Nested App Authentication, even though it is currently marked as a preview feature. Our decision was based on information indicating that this approach should resolve the issue (source 1, source 2).

The Problem:

After implementing the solution according to the documentation, we encountered errors during both silent and interactive token retrieval, as shown below. We primarily need to acquire the token within the onMessageSend handler when an email is being sent. However, we also attempted to acquire the token within the task pane (as we are aware of potential issues with popups in event-executed code) and encountered the same results. Our add-in’s JavaScript files are hosted on the Azure CDN, where we have configured the CORS headers as recommended in this issue, but this did not resolve the problem.

Important Facts:

  • Our app registration is configured correctly according to the documentation.
  • Occasionally, we are able to retrieve the token, which indicates that the process can work, but it fails most of the time.

Questions:

  • Could you please advise whether the issue lies within your implementation, or if there might be a misunderstanding or misconfiguration on our side?
  • Is there a reliable method to retrieve an SSO token in any environment, regardless of cookie restrictions or popup blockers?

Error Message

We get this error while trying to get token silently:

Unable to acquire NAA token silently: InteractionRequiredAuthError: login_required: AADSTS50058: A silent sign-in request was sent but no user is signed in. The cookies used to represent the user's session were not sent in the request to Azure AD. This can happen if the user is using Internet Explorer or Edge, and the web app sending the silent sign-in request is in different IE security zone than the Azure AD endpoint (login.microsoftonline.com). Trace ID: 025d5ec5-ee76-4c1a-a30c-09e4285a7600 Correlation ID: 01919457-542e-7b2f-a69a-a691c421d70b Timestamp: 2024-08-27 14:57:17Z
customLogMethod @ logger.ts:41
error @ logger.ts:139
_callee4$ @ ssoTokenHelper.ts:96
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_throw @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_tryAcquireTokenSilent @ ssoTokenHelper.ts:98
tryAcquireTokenSilent @ ssoTokenHelper.ts:90
_callee3$ @ ssoTokenHelper.ts:81
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_getSsoTokenFromNAA @ ssoTokenHelper.ts:88
getSsoTokenFromNAA @ ssoTokenHelper.ts:38
_callee2$ @ ssoTokenHelper.ts:24
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_getSsoToken @ ssoTokenHelper.ts:36
getSsoToken @ ssoTokenHelper.ts:16
_callee$ @ apiHelper.ts:18
tryCatch @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
asyncGeneratorStep @ apiHelper.ts:2
_next @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
sendApiRequest @ apiHelper.ts:9
_callee$ @ emailHandling.ts:81
tryCatch @ emailHandling.ts:2
(anonymous) @ emailHandling.ts:2
(anonymous) @ emailHandling.ts:2
asyncGeneratorStep @ emailHandling.ts:2
_next @ emailHandling.ts:2
(anonymous) @ emailHandling.ts:2
(anonymous) @ emailHandling.ts:2
_evaluateMessage @ emailHandling.ts:93
evaluateMessage @ emailHandling.ts:80
_callee$ @ events.ts:54
tryCatch @ events.ts:2
(anonymous) @ events.ts:2
(anonymous) @ events.ts:2
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
Promise.then
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
(anonymous) @ events.ts:2
(anonymous) @ events.ts:2
_onItemSendHandlerInner @ events.ts:73
onItemSendHandlerInner @ events.ts:44
_callee8$ @ events.ts:254
tryCatch @ events.ts:2
(anonymous) @ events.ts:2
(anonymous) @ events.ts:2
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
Promise.then
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
Promise.then
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
Promise.then
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
(anonymous) @ events.ts:2
(anonymous) @ events.ts:2
_onItemSendHandler @ events.ts:258
onItemSendHandler @ events.ts:195
(anonymous) @ outlook-web-16.01.js:20
setTimeout
a._processAppCommandInvocation @ outlook-web-16.01.js:20
fireEvent @ outlook-web-16.01.js:20
onEvent @ outlook-web-16.01.js:20
(anonymous) @ outlook-web-16.01.js:20
M @ outlook-web-16.01.js:20

And then, when we fallback to get the token interactively, we get:

Unable to acquire NAA token interactively: ServerError: user_cancelled: User cancelled the flow.
customLogMethod @ logger.ts:41
error @ logger.ts:139
_callee5$ @ ssoTokenHelper.ts:105
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_throw @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_tryAcquireTokenPopup @ ssoTokenHelper.ts:107
tryAcquireTokenPopup @ ssoTokenHelper.ts:100
_callee3$ @ ssoTokenHelper.ts:87
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_getSsoTokenFromNAA @ ssoTokenHelper.ts:88
getSsoTokenFromNAA @ ssoTokenHelper.ts:38
_callee2$ @ ssoTokenHelper.ts:24
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_getSsoToken @ ssoTokenHelper.ts:36
getSsoToken @ ssoTokenHelper.ts:16
_callee$ @ apiHelper.ts:18
tryCatch @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
asyncGeneratorStep @ apiHelper.ts:2
_next @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
sendApiRequest @ apiHelper.ts:9
_callee$ @ emailHandling.ts:81
tryCatch @ emailHandling.ts:2
(anonymous) @ emailHandling.ts:2
(anonymous) @ emailHandling.ts:2
asyncGeneratorStep @ emailHandling.ts:2
_next @ emailHandling.ts:2
(anonymous) @ emailHandling.ts:2
(anonymous) @ emailHandling.ts:2
_evaluateMessage @ emailHandling.ts:93
evaluateMessage @ emailHandling.ts:80
_callee$ @ events.ts:54
tryCatch @ events.ts:2
(anonymous) @ events.ts:2
(anonymous) @ events.ts:2
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
Promise.then
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
(anonymous) @ events.ts:2
(anonymous) @ events.ts:2
_onItemSendHandlerInner @ events.ts:73
onItemSendHandlerInner @ events.ts:44
_callee8$ @ events.ts:254
tryCatch @ events.ts:2
(anonymous) @ events.ts:2
(anonymous) @ events.ts:2
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
Promise.then
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
Promise.then
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
Promise.then
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
(anonymous) @ events.ts:2
(anonymous) @ events.ts:2
_onItemSendHandler @ events.ts:258
onItemSendHandler @ events.ts:195
(anonymous) @ outlook-web-16.01.js:20
setTimeout
a._processAppCommandInvocation @ outlook-web-16.01.js:20
fireEvent @ outlook-web-16.01.js:20
onEvent @ outlook-web-16.01.js:20
(anonymous) @ outlook-web-16.01.js:20
M @ outlook-web-16.01.js:20
events_beta.js:1916 [Safetica]: Send handler failed with error TimeoutError: Operation timed out
customLogMethod @ logger.ts:41
error @ logger.ts:139
_callee6$ @ events.ts:126
tryCatch @ events.ts:2
(anonymous) @ events.ts:2
(anonymous) @ events.ts:2
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
(anonymous) @ events.ts:2
(anonymous) @ events.ts:2
_handleSendError @ events.ts:154
handleSendError @ events.ts:125
_callee8$ @ events.ts:256
tryCatch @ events.ts:2
(anonymous) @ events.ts:2
(anonymous) @ events.ts:2
asyncGeneratorStep @ events.ts:2
_throw @ events.ts:2
Promise.then
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
Promise.then
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
Promise.then
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
Promise.then
asyncGeneratorStep @ events.ts:2
_next @ events.ts:2
(anonymous) @ events.ts:2
(anonymous) @ events.ts:2
_onItemSendHandler @ events.ts:258
onItemSendHandler @ events.ts:195
(anonymous) @ outlook-web-16.01.js:20
setTimeout
a._processAppCommandInvocation @ outlook-web-16.01.js:20
fireEvent @ outlook-web-16.01.js:20
onEvent @ outlook-web-16.01.js:20
(anonymous) @ outlook-web-16.01.js:20
M @ outlook-web-16.01.js:20

Ultimately we have another fallback implemented, when NAA does not work, to at least try the old OBO flow. Then we get:

ssoTokenHelper.ts:32 Uncaught (in promise) AccessDeniedError: Do Office není nikdo přihlášený. Před odesláním se přihlaste.
    at _callee2$ (ssoTokenHelper.ts:32:11)
    at tryCatch (ssoTokenHelper.ts:2:1)
    at Generator.<anonymous> (ssoTokenHelper.ts:2:1)
    at Generator.throw (ssoTokenHelper.ts:2:1)
    at asyncGeneratorStep (ssoTokenHelper.ts:2:1)
    at _throw (ssoTokenHelper.ts:2:1)
_callee2$ @ ssoTokenHelper.ts:32
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_throw @ ssoTokenHelper.ts:2
Promise.catch
sendLogs @ justificationInput.tsx:123
(anonymous) @ useARIAButtonProps.js:39
(anonymous) @ useEventCallback.js:26
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291
executeDispatch @ react-dom.development.js:9041
processDispatchQueueItemsInOrder @ react-dom.development.js:9073
processDispatchQueue @ react-dom.development.js:9086
dispatchEventsForPlugins @ react-dom.development.js:9097
(anonymous) @ react-dom.development.js:9288
batchedUpdates$1 @ react-dom.development.js:26179
batchedUpdates @ react-dom.development.js:3991
dispatchEventForPluginEventSystem @ react-dom.development.js:9287
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465
dispatchEvent @ react-dom.development.js:6457
dispatchDiscreteEvent @ react-dom.development.js:6430

MSAL Logs

logger.ts:41 [Safetica]: Creating NPCA for SSO retrieval
ssoTokenHelper.ts:62 [Wed, 28 Aug 2024 10:15:29 GMT] : [] : @azure/[email protected] : Info - Nested App Auth Bridge available: true
ssoTokenHelper.ts:65 [Wed, 28 Aug 2024 10:15:29 GMT] : [] : @azure/[email protected] : Verbose - BrowserCrypto: modern crypto interface available
logger.ts:41 [Safetica]: Getting SSO from NAA silently
logger.ts:41 [Safetica]: Getting SSO from NAA silently
ssoTokenHelper.ts:62 [Wed, 28 Aug 2024 10:15:29 GMT] : [] : @azure/[email protected] : Info - Emitting event: msal:acquireTokenStart
ssoTokenHelper.ts:65 [Wed, 28 Aug 2024 10:15:29 GMT] : [] : @azure/[email protected] : Verbose - No active account found, falling back to the host
ssoTokenHelper.ts:59 [Wed, 28 Aug 2024 10:15:29 GMT] : [] : @azure/[email protected] : Error - Cached tokens are not found for the account, proceeding with silent token request.
loggerCallback @ ssoTokenHelper.ts:59
executeCallback @ Logger.mjs:83
logMessage @ Logger.mjs:76
error @ Logger.mjs:90
acquireTokenFromCache @ NestedAppAuthController.mjs:198
await in acquireTokenFromCache
acquireTokenSilentInternal @ NestedAppAuthController.mjs:135
acquireTokenSilent @ NestedAppAuthController.mjs:277
acquireTokenSilent @ PublicClientApplication.mjs:91
_callee4$ @ ssoTokenHelper.ts:93
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_tryAcquireTokenSilent @ ssoTokenHelper.ts:98
tryAcquireTokenSilent @ ssoTokenHelper.ts:90
_callee3$ @ ssoTokenHelper.ts:81
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_getSsoTokenFromNAA @ ssoTokenHelper.ts:88
getSsoTokenFromNAA @ ssoTokenHelper.ts:38
_callee2$ @ ssoTokenHelper.ts:24
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_getSsoToken @ ssoTokenHelper.ts:36
getSsoToken @ ssoTokenHelper.ts:16
_callee$ @ apiHelper.ts:18
tryCatch @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
asyncGeneratorStep @ apiHelper.ts:2
_next @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
_sendApiRequest @ apiHelper.ts:90
sendApiRequest @ apiHelper.ts:9
_callee3$ @ logger.ts:168
tryCatch @ logger.ts:2
(anonymous) @ logger.ts:2
(anonymous) @ logger.ts:2
asyncGeneratorStep @ logger.ts:2
_next @ logger.ts:2
Promise.then
asyncGeneratorStep @ logger.ts:2
_next @ logger.ts:2
Promise.then
asyncGeneratorStep @ logger.ts:2
_next @ logger.ts:2
(anonymous) @ logger.ts:2
(anonymous) @ logger.ts:2
sendLogsToBackendAsync @ logger.ts:169
sendLogs @ justificationInput.tsx:123
(anonymous) @ useARIAButtonProps.js:39
(anonymous) @ useEventCallback.js:26
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291
executeDispatch @ react-dom.development.js:9041
processDispatchQueueItemsInOrder @ react-dom.development.js:9073
processDispatchQueue @ react-dom.development.js:9086
dispatchEventsForPlugins @ react-dom.development.js:9097
(anonymous) @ react-dom.development.js:9288
batchedUpdates$1 @ react-dom.development.js:26179
batchedUpdates @ react-dom.development.js:3991
dispatchEventForPluginEventSystem @ react-dom.development.js:9287
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465
dispatchEvent @ react-dom.development.js:6457
dispatchDiscreteEvent @ react-dom.development.js:6430
Show 24 more frames
Show less
ssoTokenHelper.ts:62 [Wed, 28 Aug 2024 10:15:29 GMT] : [] : @azure/[email protected] : Info - Emitting event: msal:acquireTokenFailure
An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can escape its sandboxing.
An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can escape its sandboxing.
An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can escape its sandboxing.
An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can escape its sandboxing.
An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can escape its sandboxing.
An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can escape its sandboxing.
logger.ts:41 [Safetica]: Justification saved: 0,
aadcdn.msauth.net/shared/1.0/content/js/BssoInterrupt_Core_JQnUxWSvwsd9FrpspQmznw2.js:18 BSSO Telemetry: {"result":"Error","error":"NoExtension","type":"ChromeSsoTelemetry","data":{},"traces":["BrowserSSO Initialized","Creating ChromeBrowserCore provider","Sending message for method CreateProviderAsync","Received message for method CreateProviderAsync","Error: ChromeBrowserCore error NoExtension: Extension is not installed."]}
ssoTokenHelper.ts:62 [Wed, 28 Aug 2024 10:15:31 GMT] : [] : @azure/[email protected] : Info - Emitting event: msal:acquireTokenFailure
logger.ts:41 [Safetica]: Unable to acquire NAA token silently: InteractionRequiredAuthError: login_required: AADSTS50058: A silent sign-in request was sent but no user is signed in. The cookies used to represent the user's session were not sent in the request to Azure AD. This can happen if the user is using Internet Explorer or Edge, and the web app sending the silent sign-in request is in different IE security zone than the Azure AD endpoint (login.microsoftonline.com). Trace ID: 610938fa-0f9f-4054-bfec-375137adbe00 Correlation ID: 0191987b-b55f-7531-8ec0-5dab532c2dd8 Timestamp: 2024-08-28 10:15:31Z
customLogMethod @ logger.ts:41
error @ logger.ts:139
_callee4$ @ ssoTokenHelper.ts:96
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_throw @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_tryAcquireTokenSilent @ ssoTokenHelper.ts:98
tryAcquireTokenSilent @ ssoTokenHelper.ts:90
_callee3$ @ ssoTokenHelper.ts:81
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_getSsoTokenFromNAA @ ssoTokenHelper.ts:88
getSsoTokenFromNAA @ ssoTokenHelper.ts:38
_callee2$ @ ssoTokenHelper.ts:24
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_getSsoToken @ ssoTokenHelper.ts:36
getSsoToken @ ssoTokenHelper.ts:16
_callee$ @ apiHelper.ts:18
tryCatch @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
asyncGeneratorStep @ apiHelper.ts:2
_next @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
_sendApiRequest @ apiHelper.ts:90
sendApiRequest @ apiHelper.ts:9
_callee3$ @ logger.ts:168
tryCatch @ logger.ts:2
(anonymous) @ logger.ts:2
(anonymous) @ logger.ts:2
asyncGeneratorStep @ logger.ts:2
_next @ logger.ts:2
Promise.then
asyncGeneratorStep @ logger.ts:2
_next @ logger.ts:2
Promise.then
asyncGeneratorStep @ logger.ts:2
_next @ logger.ts:2
(anonymous) @ logger.ts:2
(anonymous) @ logger.ts:2
sendLogsToBackendAsync @ logger.ts:169
sendLogs @ justificationInput.tsx:123
(anonymous) @ useARIAButtonProps.js:39
(anonymous) @ useEventCallback.js:26
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291
executeDispatch @ react-dom.development.js:9041
processDispatchQueueItemsInOrder @ react-dom.development.js:9073
processDispatchQueue @ react-dom.development.js:9086
dispatchEventsForPlugins @ react-dom.development.js:9097
(anonymous) @ react-dom.development.js:9288
batchedUpdates$1 @ react-dom.development.js:26179
batchedUpdates @ react-dom.development.js:3991
dispatchEventForPluginEventSystem @ react-dom.development.js:9287
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465
dispatchEvent @ react-dom.development.js:6457
dispatchDiscreteEvent @ react-dom.development.js:6430
Show 17 more frames
Show less
logger.ts:41 [Safetica]: Getting SSO from NAA interactively
ssoTokenHelper.ts:62 [Wed, 28 Aug 2024 10:15:31 GMT] : [] : @azure/[email protected] : Info - Emitting event: msal:acquireTokenStart
BssoInterrupt_Core_JQnUxWSvwsd9FrpspQmznw2.js:18 BSSO Telemetry: {"result":"Error","error":"NoExtension","type":"ChromeSsoTelemetry","data":{},"traces":["BrowserSSO Initialized","Creating ChromeBrowserCore provider","Sending message for method CreateProviderAsync","Received message for method CreateProviderAsync","Error: ChromeBrowserCore error NoExtension: Extension is not installed."]}
ssoTokenHelper.ts:62 [Wed, 28 Aug 2024 10:15:32 GMT] : [] : @azure/[email protected] : Info - Emitting event: msal:acquireTokenFailure
logger.ts:41 [Safetica]: Unable to acquire NAA token interactively: ServerError: user_cancelled: User cancelled the flow.
customLogMethod @ logger.ts:41
error @ logger.ts:139
_callee5$ @ ssoTokenHelper.ts:105
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_throw @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_tryAcquireTokenPopup @ ssoTokenHelper.ts:107
tryAcquireTokenPopup @ ssoTokenHelper.ts:100
_callee3$ @ ssoTokenHelper.ts:87
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_getSsoTokenFromNAA @ ssoTokenHelper.ts:88
getSsoTokenFromNAA @ ssoTokenHelper.ts:38
_callee2$ @ ssoTokenHelper.ts:24
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_getSsoToken @ ssoTokenHelper.ts:36
getSsoToken @ ssoTokenHelper.ts:16
_callee$ @ apiHelper.ts:18
tryCatch @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
asyncGeneratorStep @ apiHelper.ts:2
_next @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
_sendApiRequest @ apiHelper.ts:90
sendApiRequest @ apiHelper.ts:9
_callee3$ @ logger.ts:168
tryCatch @ logger.ts:2
(anonymous) @ logger.ts:2
(anonymous) @ logger.ts:2
asyncGeneratorStep @ logger.ts:2
_next @ logger.ts:2
Promise.then
asyncGeneratorStep @ logger.ts:2
_next @ logger.ts:2
Promise.then
asyncGeneratorStep @ logger.ts:2
_next @ logger.ts:2
(anonymous) @ logger.ts:2
(anonymous) @ logger.ts:2
sendLogsToBackendAsync @ logger.ts:169
sendLogs @ justificationInput.tsx:123
(anonymous) @ useARIAButtonProps.js:39
(anonymous) @ useEventCallback.js:26
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291
executeDispatch @ react-dom.development.js:9041
processDispatchQueueItemsInOrder @ react-dom.development.js:9073
processDispatchQueue @ react-dom.development.js:9086
dispatchEventsForPlugins @ react-dom.development.js:9097
(anonymous) @ react-dom.development.js:9288
batchedUpdates$1 @ react-dom.development.js:26179
batchedUpdates @ react-dom.development.js:3991
dispatchEventForPluginEventSystem @ react-dom.development.js:9287
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465
dispatchEvent @ react-dom.development.js:6457
dispatchDiscreteEvent @ react-dom.development.js:6430
Show 17 more frames
Show less
BssoInterrupt_Core_JQnUxWSvwsd9FrpspQmznw2.js:18 BSSO Telemetry: {"result":"Error","error":"NoExtension","type":"ChromeSsoTelemetry","data":{},"traces":["BrowserSSO Initialized","Creating ChromeBrowserCore provider","Sending message for method CreateProviderAsync","Received message for method CreateProviderAsync","Error: ChromeBrowserCore error NoExtension: Extension is not installed."]}
logger.ts:41 [Safetica]: Unable to acquire Office runtime token: [object Object]
customLogMethod @ logger.ts:41
error @ logger.ts:139
_callee6$ @ ssoTokenHelper.ts:113
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_throw @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_getSsoTokenFromOfficeRuntime @ ssoTokenHelper.ts:116
getSsoTokenFromOfficeRuntime @ ssoTokenHelper.ts:109
_callee2$ @ ssoTokenHelper.ts:29
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
Promise.then
asyncGeneratorStep @ ssoTokenHelper.ts:2
_next @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
_getSsoToken @ ssoTokenHelper.ts:36
getSsoToken @ ssoTokenHelper.ts:16
_callee$ @ apiHelper.ts:18
tryCatch @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
asyncGeneratorStep @ apiHelper.ts:2
_next @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
(anonymous) @ apiHelper.ts:2
_sendApiRequest @ apiHelper.ts:90
sendApiRequest @ apiHelper.ts:9
_callee3$ @ logger.ts:168
tryCatch @ logger.ts:2
(anonymous) @ logger.ts:2
(anonymous) @ logger.ts:2
asyncGeneratorStep @ logger.ts:2
_next @ logger.ts:2
Promise.then
asyncGeneratorStep @ logger.ts:2
_next @ logger.ts:2
Promise.then
asyncGeneratorStep @ logger.ts:2
_next @ logger.ts:2
(anonymous) @ logger.ts:2
(anonymous) @ logger.ts:2
sendLogsToBackendAsync @ logger.ts:169
sendLogs @ justificationInput.tsx:123
(anonymous) @ useARIAButtonProps.js:39
(anonymous) @ useEventCallback.js:26
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291
executeDispatch @ react-dom.development.js:9041
processDispatchQueueItemsInOrder @ react-dom.development.js:9073
processDispatchQueue @ react-dom.development.js:9086
dispatchEventsForPlugins @ react-dom.development.js:9097
(anonymous) @ react-dom.development.js:9288
batchedUpdates$1 @ react-dom.development.js:26179
batchedUpdates @ react-dom.development.js:3991
dispatchEventForPluginEventSystem @ react-dom.development.js:9287
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465
dispatchEvent @ react-dom.development.js:6457
dispatchDiscreteEvent @ react-dom.development.js:6430
Show 17 more frames
Show less
ssoTokenHelper.ts:32 Uncaught (in promise) AccessDeniedError: Do Office není nikdo přihlášený. Před odesláním se přihlaste.
at _callee2$ (ssoTokenHelper.ts:32:11)
at tryCatch (ssoTokenHelper.ts:2:1)
at Generator. (ssoTokenHelper.ts:2:1)
at Generator.throw (ssoTokenHelper.ts:2:1)
at asyncGeneratorStep (ssoTokenHelper.ts:2:1)
at _throw (ssoTokenHelper.ts:2:1)
_callee2$ @ ssoTokenHelper.ts:32
tryCatch @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
(anonymous) @ ssoTokenHelper.ts:2
asyncGeneratorStep @ ssoTokenHelper.ts:2
_throw @ ssoTokenHelper.ts:2
Promise.catch
sendLogs @ justificationInput.tsx:123
(anonymous) @ useARIAButtonProps.js:39
(anonymous) @ useEventCallback.js:26
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291
executeDispatch @ react-dom.development.js:9041
processDispatchQueueItemsInOrder @ react-dom.development.js:9073
processDispatchQueue @ react-dom.development.js:9086
dispatchEventsForPlugins @ react-dom.development.js:9097
(anonymous) @ react-dom.development.js:9288
batchedUpdates$1 @ react-dom.development.js:26179
batchedUpdates @ react-dom.development.js:3991
dispatchEventForPluginEventSystem @ react-dom.development.js:9287
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465
dispatchEvent @ react-dom.development.js:6457
dispatchDiscreteEvent @ react-dom.development.js:6430
Show 17 more frames
Show less
owa.JquerySignalR.m.abc5d963.js:1

Network Trace (Preferrably Fiddler)

  • Sent
  • Pending

MSAL Configuration

{
    auth: {
      clientId: clientId,
      authority: "https://login.microsoftonline.com/common"
    }
}

Relevant Code Snippets

import env from "../../env";
import { TokenRetrievalFailedError } from "../definitions/errors";
import logger from "../logging/logger";
import { isNAASupported } from "./featureSetHelper";
import { createNestablePublicClientApplication, IPublicClientApplication, LogLevel } from "@azure/msal-browser";

const defaultSsoOptions: OfficeRuntime.AuthOptions = {
  allowSignInPrompt: true,
  allowConsentPrompt: false,
  forMSGraphAccess: false,
};

export async function getSsoToken(): Promise<string> {
  try {
    var token = undefined;
    const clientId = env.CLIENT_ID;
    
    if(isNAASupported() && clientId)
      token = await getSsoTokenFromNAA(clientId)

    if (token)
      return token;

    return await getSsoTokenFromOfficeRuntime();
  } catch (error: any) {
    const msg = getErrorMessage(error);
    throw new TokenRetrievalFailedError(msg)
  } 
}

async function getSsoTokenFromNAA(clientId: string): Promise<string | undefined> {
  const tokenRequest = {
    scopes: ["openid", "profile"],
  };

  logger.debug("Creating NPCA for SSO retrieval")

  const npca = await createNestablePublicClientApplication({
    auth: {
      clientId: clientId,
      authority: "https://login.microsoftonline.com/common"
    }
  });
    
  logger.debug("Getting SSO from NAA silently")

  var authResult = await tryAcquireTokenSilent(npca, tokenRequest)
  if (authResult)
    return authResult

  logger.debug("Getting SSO from NAA interactively")

  return await tryAcquireTokenPopup(npca, tokenRequest)
}

async function tryAcquireTokenSilent(pca: IPublicClientApplication, tokenRequest: { scopes: string[] }): Promise<string | undefined> {
  try {
    logger.debug("Getting SSO from NAA silently")
    const userAccount = await pca.acquireTokenSilent(tokenRequest);
    return userAccount.accessToken;
  } catch (error) {
    logger.error(`Unable to acquire NAA token silently: ${error}`);
  }
}

async function tryAcquireTokenPopup(pca: IPublicClientApplication, tokenRequest: { scopes: string[] }): Promise<string | undefined> {
  try {
    const userAccount = await pca.acquireTokenPopup(tokenRequest);
    return userAccount.accessToken;
  } catch (error) {
    logger.error(`Unable to acquire NAA token interactively: ${error}`);
  }
}

async function getSsoTokenFromOfficeRuntime(): Promise<string> {
  try {
    return await OfficeRuntime.auth.getAccessToken(JSON.parse(JSON.stringify(defaultSsoOptions)));
  } catch (error: any) {
    logger.error(`Unable to acquire Office runtime token: ${error}`);
    throw error;
  }
}

Reproduction Steps

  1. Create plain outlook add-in project with onItemSend event handler and task pane.
  2. Create new app registration within your tenant with delegated permissions (["openid", "profile"]) and SPA redirect URL (can be brk-multihub://localhost:3000 if you run the add-in locally).
  3. replace clientId within our snippet with your clientId
  4. use the snippet to retrieve SSO token inside Safari or chrome browser (incognito window):
    a. when sending mail (in event handler)
    b. from task pane (on button click, for example)

Now you should get similar errors.

Expected Behavior

We expect this new way of authentication to work also within browser environment with third-party cookies restriction implemented. The add-in should get the token successfully.

Identity Provider

Entra ID (formerly Azure AD) / MSA

Browsers Affected (Select all that apply)

Chrome, Firefox, Safari

Regression

None

Source

External (Customer)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs: Attention 👋Awaiting response from the MSAL.js teambug-unconfirmedA reported bug that needs to be investigated and confirmedmore-information-neededUse this label when you are waiting on information from the issue creatormsal-browserRelated to msal-browser packagepublic-clientIssues regarding PublicClientApplicationsquestionCustomer is asking for a clarification, use case or information.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions