Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Outlook Add-in: Token Cache Not Reused in NAA Scenario, Leading to Performance Degradation #5237

Open
MortenGuldbaek opened this issue Jan 3, 2025 · 6 comments
Assignees
Labels
Area: authentication Issue related to authentication Area: Outlook Issue related to Outlook add-ins Needs: attention 👋 Waiting on Microsoft to provide feedback

Comments

@MortenGuldbaek
Copy link

When using NAA, the Outlook Add-in is never able to reuse the token cache, due to the BridgeProxy.initializeNestedAppAuthBridge response not containing an accountContext.

Expected Behavior

A user should be able to open and use our Outlook Add-in in their browser or the new Outlook App. They should be able to browse views utilizing Microsoft Graph data by getting a token and using Single Sign-On with MSAL in an NAA scenario without repeated token requests.

Current Behavior

Although the functionality is correct, the actual experience is slow, as every Graph API request triggers a new token request instead of reusing the previously fetched tokens. The same goes for other resources, fx. SharePoint REST.

The bearer tokens previously fetched, and visible in the browser localStorage, should be reused, as to improve performance.

Steps to Reproduce, or Live Example

  1. Set up an Outlook Add-in with Single Sign-On enabled using Nested App Authentication (NAA).
  2. Create a page in the application that loads Graph data on load and includes a button to trigger new requests.
  3. Ensure the page uses the acquireTokenSilent method to fetch a token right before making each request.
  4. Monitor network traffic to see a token request before each Graph data request.

Context

The performance is slow due to token requests being executed before each data load.

My investigation found that the 'BridgeProxy.initializeNestedAppAuthBridge' response never actually returns an account that can be used for the caching:
image
@azure/msal-browser/src/naa/BridgeProxy.ts

The response should contain "accountContext" and "capabilities" but they do not exist.

This is the only place in the entire library that the account context that is used for looking up the token cache is set.

This in turn ensures that the currentAccount is never set:
image
@azure/msal-browser/src/controllers/NestedAppAuthController.ts

As a result, all requests work correctly but make redundant calls to the token endpoint.

Your Environment

  • Platform [PC desktop, Mac, iOS, Office Online]: Office Online
  • Host [Excel, Word, PowerPoint, etc.]: Outlook OWA
  • Office version number: ______
  • Operating System: Windows 11
  • Browser (if using Office Online): Chrome
  • Packages: "@azure/msal-browser": "3.28.0"

Useful logs

Here is an example, but with SharePoint REST (different resource and scopes) from the same app:
image

And the corresponding log:

09:49:29 - @azure/[email protected] : Verbose - No active account found, falling back to the host
09:49:29 - @azure/[email protected] : Error - Cached tokens are not found for the account, proceeding with silent token request.
09:49:29 - @azure/[email protected] : Verbose - hydrateCache called
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager.setAccount called
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager.addAccountKeyToMap called
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager.getAccountKeys called
09:49:29 - @azure/[email protected] : Verbose - BrowserCacheManager.addAccountKeyToMap account key already exists in map
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager.setIdTokenCredential called
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager addTokenKey called
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager.getTokenKeys called
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager.getTokenKeys called
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager.getAccessTokenCredential: cache hit
09:49:29 - @azure/[email protected] : Trace - getAliasesFromMetadata called with source: config
09:49:29 - @azure/[email protected] : Trace - getAliasesFromMetadata called with source: hardcoded_values
09:49:29 - @azure/[email protected] : Trace - getAliasesFromMetadata: found cloud discovery metadata in hardcoded_values, returning aliases
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager.getAccessTokenCredential: cache hit
09:49:29 - @azure/[email protected] : Trace - getAliasesFromMetadata called with source: config
09:49:29 - @azure/[email protected] : Trace - getAliasesFromMetadata called with source: hardcoded_values
09:49:29 - @azure/[email protected] : Trace - getAliasesFromMetadata: found cloud discovery metadata in hardcoded_values, returning aliases
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager.getAccessTokenCredential: cache hit
09:49:29 - @azure/[email protected] : Trace - getAliasesFromMetadata called with source: config
09:49:29 - @azure/[email protected] : Trace - getAliasesFromMetadata called with source: hardcoded_values
09:49:29 - @azure/[email protected] : Trace - getAliasesFromMetadata: found cloud discovery metadata in hardcoded_values, returning aliases
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager.getAccessTokenCredential: cache hit
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager removeTokenKey called
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager.getTokenKeys called
09:49:29 - @azure/[email protected] : Info - BrowserCacheManager: removeTokenKey - accessToken removed from map
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager.setAccessTokenCredential called
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager addTokenKey called
09:49:29 - @azure/[email protected] : Trace - BrowserCacheManager.getTokenKeys called
09:49:29 - @azure/[email protected] : Info - BrowserCacheManager: addTokenKey - accessToken added to map
09:49:29 - @azure/[email protected] : Verbose - setActiveAccount: Active account set
09:49:33 - @azure/[email protected] : Verbose - No active account found, falling back to the host
09:49:33 - @azure/[email protected] : Error - Cached tokens are not found for the account, proceeding with silent token request.
09:49:33 - @azure/[email protected] : Verbose - hydrateCache called
09:49:33 - @azure/[email protected] : Trace - BrowserCacheManager.setAccount called
09:49:33 - @azure/[email protected] : Trace - BrowserCacheManager.addAccountKeyToMap called
09:49:33 - @azure/[email protected] : Trace - BrowserCacheManager.getAccountKeys called
09:49:33 - @azure/[email protected] : Verbose - BrowserCacheManager.addAccountKeyToMap account key already exists in map
09:49:33 - @azure/[email protected] : Trace - BrowserCacheManager.setIdTokenCredential called
09:49:33 - @azure/[email protected] : Trace - BrowserCacheManager addTokenKey called
09:49:33 - @azure/[email protected] : Trace - BrowserCacheManager.getTokenKeys called
09:49:33 - @azure/[email protected] : Trace - BrowserCacheManager.getTokenKeys called
09:49:33 - @azure/[email protected] : Trace - BrowserCacheManager.getAccessTokenCredential: cache hit
09:49:33 - @azure/[email protected] : Trace - getAliasesFromMetadata called with source: config
09:49:33 - @azure/[email protected] : Trace - getAliasesFromMetadata called with source: hardcoded_values
09:49:33 - @azure/[email protected] : Trace - getAliasesFromMetadata: found cloud discovery metadata in hardcoded_values, returning aliases
09:49:33 - @azure/[email protected] : Trace - BrowserCacheManager.getAccessTokenCredential: cache hit
09:49:33 - @azure/[email protected] : Trace - getAliasesFromMetadata called with source: config
09:49:33 - @azure/[email protected] : Trace - getAliasesFromMetadata called with source: hardcoded_values
09:49:33 - @azure/[email protected] : Trace - getAliasesFromMetadata: found cloud discovery metadata in hardcoded_values, returning aliases
09:49:33 - @azure/[email protected] : Trace - BrowserCacheManager.getAccessTokenCredential: cache hit
09:49:33 - @azure/[email protected] : Trace - getAliasesFromMetadata called with source: config
09:49:33 - @azure/[email protected] : Trace - getAliasesFromMetadata called with source: hardcoded_values
09:49:33 - @azure/[email protected] : Trace - getAliasesFromMetadata: found cloud discovery metadata in hardcoded_values, returning aliases
09:49:33 - @azure/[email protected] : Trace - BrowserCacheManager.getAccessTokenCredential: cache hit
Copy link

github-actions bot commented Jan 3, 2025

Here are some similar issues that might help you. Please check if they can solve your problem.


Possible solution (Extracted from existing issue, might be incorrect; please verify carefully)

Solution 1:

There is a new NAA sample in PR that shows how to implement NAA in events. In particular, you have to be careful how to configure webpack to avoid pulling in hot reload code when importing MSAL JS. This might help with the issues you are seeing.

Reference:

Solution 2:

Acquiring an access token via NAA in send event now works with beta channel version 16.0.18028.20004.

Reference:

Solution 3:

The sample is now published at https://github.com/OfficeDev/Office-Add-in-samples/tree/main/Samples/auth/Outlook-Event-SSO-NAA. This might provide guidance on implementing NAA correctly.

Reference:

@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs: triage 🔍 New issue, needs PM on rotation to triage ASAP label Jan 3, 2025
@exextoc exextoc added Needs: attention 👋 Waiting on Microsoft to provide feedback Area: Outlook Issue related to Outlook add-ins and removed Needs: triage 🔍 New issue, needs PM on rotation to triage ASAP Similar-Issue Possible-Solution labels Jan 3, 2025
@exextoc exextoc self-assigned this Jan 3, 2025
@davidchesnut
Copy link
Member

Hi @MortenGuldbaek,

I'm not able to reproduce this behavior. Can you share which scopes you are requesting? Also do you see the same behavior in other browsers? if not, could be there is a setting in Chrome throwing it off and we could try to track down what it is.

Thanks,
David

@davidchesnut davidchesnut added Area: authentication Issue related to authentication Needs: author feedback Waiting for author (creator) of Issue to provide more info and removed Needs: attention 👋 Waiting on Microsoft to provide feedback labels Jan 10, 2025
@microsoft-github-policy-service microsoft-github-policy-service bot added the Status: no recent activity Issue or PR is stale (no recent activity) label Jan 15, 2025
@MortenGuldbaek
Copy link
Author

Hi David, thanks for responding

I just tried re-running the Add-in from Microsoft Edge, and I experience the same behavior here.

The scopes we are requesting in the silent request are the following:

SharePoint REST call
https://.sharepoint.com/.default openid profile offline_access

Graph REST call
https://graph.microsoft.com/.default openid profile offline_access

Looking over the AzureAD/microsoft-authentication-library-for-js issue list, it seems there are several related issues where token cache is not being used, so it might be related.

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs: attention 👋 Waiting on Microsoft to provide feedback and removed Status: no recent activity Issue or PR is stale (no recent activity) Needs: author feedback Waiting for author (creator) of Issue to provide more info labels Jan 15, 2025
@davidchesnut
Copy link
Member

Hi @MortenGuldbaek,

What scopes are covered by the graph.microsoft.com/.default scope? Are you requesting anything other than openid, profile, and offline_access? It's required to have at least one resource scope to get a valid access token. More info. Even though this will work on some platform scenarios, just wondering if that has anything to do with the behavior.

Thanks,
David

@MortenGuldbaek
Copy link
Author

Hi @davidchesnut we have several scopes scopes other than the ones you mention. The same goes for our other resources, fx. for SharePoint REST.

We do also get a valid token in all scenarios, it just won't reuse the token cache it creates in localStorage.

@ottD
Copy link

ottD commented Jan 21, 2025

I'm encountering the same issue with an Outlook add-in with NAA not using cached tokens but issuing a token request for every web request the add-in makes. This can be reproduced by running the below sample add-in in OWA (add your client ID in msalconfig.ts) and repeatedly clicking on the Get User Data button once the taskpane has loaded: Outlook-Add-in-SSO-NAA.zip

The repro add-in is the Outlook NAA sample add-in with session storage enabled:
https://github.com/OfficeDev/Office-Add-in-samples/tree/main/Samples/auth/Outlook-Add-in-SSO-NAA

Note: I tested with the latest "@azure/msal-browser" 4.0.1 in OWA in Chrome. The issue does not occur when using Outlook Desktop (new or legacy).

Image

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: authentication Issue related to authentication Area: Outlook Issue related to Outlook add-ins Needs: attention 👋 Waiting on Microsoft to provide feedback
Projects
None yet
Development

No branches or pull requests

4 participants