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

MSALObject.getAllAccounts() return empty after loggedin in a excel addin dialog #6485

Closed
coeguru opened this issue Sep 15, 2023 · 11 comments
Closed
Assignees
Labels
msal-browser Related to msal-browser package Needs: Attention 👋 Awaiting response from the MSAL.js team no-issue-activity Issue author has not responded in 5 days public-client Issues regarding PublicClientApplications question Customer is asking for a clarification, use case or information.

Comments

@coeguru
Copy link

coeguru commented Sep 15, 2023

Core Library

MSAL.js (@azure/msal-browser)

Core Library Version

2.34.0

Wrapper Library

Not Applicable

Wrapper Library Version

None

Public or Confidential Client?

Public

Description

myMSALObject.getAllAccounts() return empty when logged in via myMSALObj.loginRedirect(loginRequest); inside Excel Addin Dialog created using Office.context.ui.displayDialogAsync. Because the getAllAccounts() is empty, we are not able to set the active account for fetching the token silently after the initial authentication.

What I see is if I open the dialog as present in the code section. The localStorage is not populated with msal accounts but If I use the myMSALObj.acquireTokenPopup(request) the localstorage is populated but I dont want to use the popup as it is blocked in the browsers by default.

MSAL Configuration

{
    auth: {
      clientId: clientId, // This is the ONLY mandatory field that you need to supply.
      authority: "https://login.microsoftonline.com/common", // Defaults to "https://login.microsoftonline.com/common"
      redirectUri: redirectUri, // You must register this URI on Azure Portal/App Registration. Defaults to window.location.href
      //postLogoutRedirectUri: "https://localhost:3000/signout", // Simply remove this line if you would like navigate to index page after logout.
      navigateToLoginRequestUrl: false, // If "true", will navigate back to the original request location before processing the auth code response.
      // response_type: "access_token"
    },
    cache: {
      cacheLocation: "localStorage", // Configures cache location. "sessionStorage" is more secure, but "localStorage" gives you SSO.
      storeAuthStateInCookie: false, // If you wish to store cache items in cookies as well as browser cache, set this to "true".
    },
    system: {
      loggerOptions: {
        loggerCallback: (level, message, containsPii) => {
          if (containsPii) {
            return;
          }
          switch (level) {
            case msal.LogLevel.Error:
              console.error(message);
              return;
            case msal.LogLevel.Info:
              console.info(message);
              return;
            case msal.LogLevel.Verbose:
              console.debug(message);
              return;
            case msal.LogLevel.Warning:
              console.warn(message);
              return;
          }
        }
      }
    }
 }

Relevant Code Snippets

getAccessTokenMSAL function.

async function getAccessTokenMSAL(request=loginRequest) {
    console.log('loginRequest', request, homeAccountId);
    // Attempt to acquire token silently if user is already signed in.
    if (homeAccountId !== null) {
        const result = await myMSALObj.acquireTokenSilent(request, homeAccountId);
        if (result !== null && result.accessToken !== null) {
            console.log('silent token', JSON.stringify(result));
            return result;
        } else return null;
    } else {
        let promise = await new Promise((resolve, reject) => {
            const url = '/dialog.html';
            var fullUrl =
                location.protocol +
                '//' +
                location.hostname +
                (location.port ? ':' + location.port : '') +
                url;
            //console.log('full url', fullUrl);
            // height and width are percentages of the size of the parent Office application, e.g., Outlook, PowerPoint, Excel, Word, etc.
            Office.context.ui.displayDialogAsync(
                fullUrl,
                { height: 60, width: 30 },
                function (result) {
                    if (result.status === Office.AsyncResultStatus.Failed) {
                        console.log(
                            (result.error.code = ': ' + result.error.message)
                        );
                        reject(result.error.message);
                    } else {
                        console.log('Dialog has initialized. Wiring up events');
                        let loginDialog = result.value;

                        // Handler for the dialog box closing unexpectedly.
                        loginDialog.addEventHandler(
                            Office.EventType.DialogEventReceived,
                            (arg) => {
                                console.log(
                                    'DialogEventReceived: ' + arg.error
                                );
                                loginDialog.close();
                                // For more dialog codes, see https://learn.microsoft.com/office/dev/add-ins/develop/dialog-handle-errors-events#errors-and-events-in-the-dialog-box
                                switch (arg.error) {
                                    case 12002:
                                        reject("The auth dialog box has been directed to a page that it cannot find or load, or the URL syntax is invalid.");
                                        break;
                                    case 12003:
                                        reject("The auth dialog box has been directed to a URL with the HTTP protocol. HTTPS is required.");          
                                        break;
                                    case 12006:
                                        reject("The auth dialog box was closed before the user signed in.");
                                        break;
                                    default:
                                        reject("Unknown error in auth dialog box.");
                                        break;
                                }
                            }
                        );
                        loginDialog.addEventHandler(
                            Office.EventType.DialogMessageReceived,
                            function processMessage2(arg) {
                                console.log(
                                    'Message received in processMessage',
                                    arg.message
                                );
                                let messageFromDialog = JSON.parse(arg.message);
                                
                                if (messageFromDialog.status === 'success') {
                                    // We now have a valid access token.
                                    loginDialog.close();
                                    homeAccountId = messageFromDialog.accountId;
                                    console.log("All Accounts", myMSALObj.getAllAccounts());
                                    // Set the active account so future token requests can be silent.
                                    myMSALObj.setActiveAccount(
                                        myMSALObj.getAccountByHomeId(
                                            homeAccountId
                                        )
                                    );

                                    // Return the token.
                                    resolve({ accessToken: messageFromDialog.result});
                                } else if (messageFromDialog.status === 'test') {
                                    console.log("test", messageFromDialog);
                                }else {
                                    // Something went wrong with authentication or the authorization of the web application.
                                    loginDialog.close();
                                    reject(messageFromDialog.error);
                                }
                            }
                        );
                    }
                }
            );
        });
        return promise;
    }
}

AuthRedicect

// This file copied and modified from https://github.com/Azure-Samples/ms-identity-javascript-tutorial/blob/main/1-Authentication/1-sign-in/App/authRedirect.js

// Create the main myMSALObj instance
// configuration parameters are located at authConfig.js

Office.initialize = async function () {
  if (Office.context.ui.messageParent) {
    try {
      await initialize();
      const response = await myMSALObj.handleRedirectPromise();
      handleResponse(response);
    } catch (error) {
      console.error(error);
      Office.context.ui.messageParent(
        JSON.stringify({ status: "error", error: error.message }),
        { targetOrigin: window.location.origin }
      );
    }
  }
};

function handleResponse(response) {
  /**
   * To see the full list of response object properties, visit:
   * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#response
   */
  Office.context.ui.messageParent(
    JSON.stringify({ status: "test", accounts: myMSALObj.getAllAccounts(),  agent: navigator.userAgent }),
    { targetOrigin: window.location.origin });
  if (response !== null) {
    Office.context.ui.messageParent(
      JSON.stringify({ status: "success", result: response.accessToken, accountId: response.account.homeAccountId }),
      { targetOrigin: window.location.origin }
    );
  } else {
    //log in
    myMSALObj.loginRedirect(loginRequest);
  }
}

These snippets are from https://github.com/OfficeDev/Office-Add-in-samples/tree/main/Samples/auth/Office-Add-in-NodeJS-SSO



### Identity Provider

Azure AD / MSA

### Source

External (Customer)
@coeguru coeguru added the question Customer is asking for a clarification, use case or information. label Sep 15, 2023
@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs: Attention 👋 Awaiting response from the MSAL.js team label Sep 15, 2023
@github-actions github-actions bot added msal-browser Related to msal-browser package public-client Issues regarding PublicClientApplications labels Sep 15, 2023
@coeguru coeguru changed the title myMSALObject.getAllAccounts() return empty after loggedin in a excel addin dialog MSALObject.getAllAccounts() return empty after loggedin in a excel addin dialog Sep 15, 2023
@microsoft-github-policy-service
Copy link
Contributor

This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @hectormmg please follow up.

1 similar comment
@microsoft-github-policy-service
Copy link
Contributor

This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @hectormmg please follow up.

@coeguru
Copy link
Author

coeguru commented Sep 28, 2023

Hey we are still facing the issue, @hectormmg do you know when will you be able to get to this ?

@vdeunzue
Copy link

vdeunzue commented Oct 5, 2023

We are experiencing the same issue where some people in some browsers (firefox & safari) and mobile browsers, after the loginRedirect(); the getAllAccounts call returns an empty array. We however are using:

@azure/msal-angular": "^1.1.2
msal": "^1.4.6

@cvium
Copy link

cvium commented Oct 18, 2023

I have also run into this issue

@coeguru
Copy link
Author

coeguru commented Nov 6, 2023

@hectormmg , Any update on this. its been like 2 months since I posted the question. It would be nice to get some light on it.

@hectormmg
Copy link
Member

@coeguru sorry for the delay, I see you shared snippets from a Node sample, have you looked at the add-in sample for msal-browser?

https://github.com/OfficeDev/Office-Add-in-samples/blob/main/Samples/auth/Office-Add-in-Microsoft-Graph-React/l

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs: Author Feedback Awaiting response from issue author no-issue-activity Issue author has not responded in 5 days and removed Needs: Attention 👋 Awaiting response from the MSAL.js team labels Nov 14, 2023
@cvium
Copy link

cvium commented Nov 20, 2023

@coeguru sorry for the delay, I see you shared snippets from a Node sample, have you looked at the add-in sample for msal-browser?

https://github.com/OfficeDev/Office-Add-in-samples/blob/main/Samples/auth/Office-Add-in-Microsoft-Graph-React/l

The addin sample does not utilize msal.js in any meaningful way if you ask me. It does use msal.js to authenticate the user, but the accesstoken is simply stored in the React state without any way to refresh it again. As such, it does not save the account.

@coeguru
Copy link
Author

coeguru commented Nov 20, 2023

Yeah the sample code even basic compared to the code snippets I mentioned, we ended up caching the token in localStorage and not rely on MSAL to cache.

Even this document mentions us to not rely on the local cache of any library.
https://learn.microsoft.com/en-us/office/dev/add-ins/develop/auth-with-office-dialog-api

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs: Attention 👋 Awaiting response from the MSAL.js team and removed Needs: Author Feedback Awaiting response from issue author labels Nov 20, 2023
@parinda296
Copy link

@hectormmg
I've encountered a similar issue while using the dialog API for login. The local storage of the dialog isn't accessible to the task pane, causing getAllAccounts to return null upon add-in reload which results in the failure of acquireTokenSilent. This behavior changed due to recent storage partitioning updates in Chrome and other browsers.

Are there any upcoming plans for @azure/msal-browser to incorporate alternatives for enabling silent login without relying solely on local storage? Considering evolving browser security measures like storage partitioning and third-party cookies phase out.

@coeguru
You mentioned that instead of relying on the library you are storing access tokens within local storage from your code.
how are you managing silent login in case of task pane reload or token expiration similar to @azure/msal-browser library's acquireTokenSilent method?

@coeguru
Copy link
Author

coeguru commented Nov 28, 2023

@parinda296 , The token has the validity of 1hr. If there a new call to get the token in that one hour, I get it from the localStorage. If the token is expired, I am currently asking the user to login again.

There are 2 ways in which we can get around the token expiry -

  1. If you are using the token as a way to identify the user and you dont need the exact microsoft auth token, then we can generate our own token and store it in the local storage. Since we are generating the token, we can have a longer token.
  2. Not sure if there is a refresh token flow for login using msal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
msal-browser Related to msal-browser package Needs: Attention 👋 Awaiting response from the MSAL.js team no-issue-activity Issue author has not responded in 5 days public-client Issues regarding PublicClientApplications question Customer is asking for a clarification, use case or information.
Projects
None yet
Development

No branches or pull requests

5 participants