0

I am developing an Outlook Web Add-In using

  • Yeoman generator-office
  • Office.Js
  • REACT framework
  • azure/msal-browser version 2.32.2

As per Microsoft/Office Add-In/MSAL team's best practice - I am performing a popup auth in the office dialogue using the office SDK, and then perform loginRedirect inside that popup. In my App.tsx file I have the following code to do the popup:

const dialogLoginUrl: string = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '') + '/login.html';

await Office.context.ui.displayDialogAsync(
  dialogLoginUrl,
  {height: 40, width: 30},
  (result) => {
      if (result.status === Office.AsyncResultStatus.Failed) {
      }
      else {
          loginDialog = result.value;
          loginDialog.addEventHandler(Office.EventType.DialogMessageReceived, this.processLoginMessage);
      }
  }
);

processLoginMessage = async (args: { message: string; origin: string; }) => {
  let messageFromDialog = JSON.parse(args.message);
  if (messageFromDialog.status === 'success') {
    loginDialog.close();
    console.log(messageFromDialog.result.accessToken);    
  }
  else {
    // Something went wrong with authentication or the authorization of the web application.
    loginDialog.close();
  }
}

In my login.ts file I have the following code:

import { PublicClientApplication } from "@azure/msal-browser";

(() => {
    Office.initialize = () => {
        let msalInstance = new PublicClientApplication({
            auth: {
            authority: "https://login.microsoftonline.com/organizations/",
            clientId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx"
            },
            cache: {
            cacheLocation: "localStorage",
            storeAuthStateInCookie: true,
            },
        });

        const authParamsGraph = {
            scopes: ["https://graph.microsoft.com/.default"]
        };
         msalInstance.handleRedirectPromise()
        .then(async (response) => {
            if (response) {
                Office.context.ui.messageParent(JSON.stringify({ status: 'success', result : response }));
            } else {
                msalInstance.loginRedirect(authParamsGraph);
            }
        })
        .catch(() => {
            console.log('failure');
        });
    };
})();

Using the above setup I can get the Graph Access Token just fine and everything works.

What I need is - to get access tokens for other resources as well i.e. SharePoint and Onedrive in the desktop application of Outlook.

In other words "How can I get access token for multiple resources using the msalInstance.acquireTokenSilent(scope)".

What I have tried so far without luck.

After performing the login using the login.ts file in a popup - I init a new MSAL instance and try to get access token for SharePoint using the acquireTokenSilent method. In my app.tsx file I then have:

let msalInstance = new PublicClientApplication({
  auth: {
  authority: "https://login.microsoftonline.com/organizations/",
  clientId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx"
  },
  cache: {
  cacheLocation: "localStorage",
  storeAuthStateInCookie: true,
  },
});

const authParamsSharePoint = {
  account: messageFromDialog.result.account,
  scopes: ["https://tenant.sharepoint.com/.default"]
};

let spResp = await msalInstance.acquireTokenSilent(authParamsSharePoint);

The above works just fine with Outlook in the browser - however does not work in the Outlook desktop application.

I also tried to followed this implementation to request token for multiple resources, with no luck - https://github.com/AhmadiRamin/office-addins-msal/blob/master/src/helpers/msalHelper.ts

However they have used MSAL version 1x (UserAgentApplication) and I am using version 2x (PublicClientApplication). not sure if it causes any difference in behavior.

The main idea is to use the login popup once to initiate the msalinstance and for any subsequent scopes/resources (or when the initial access token expires) use the acquireTokenSilent method - so that the user does not need to click the login button again to get another token.

gts
  • 21
  • 5

1 Answers1

0

As far as I understand the access token for SharePoint will be different from the one for graph, but you can use the one from graph to get one for SharePoint.

See SharePoint Rest API how to get Access Token? for an answer that explains this.

  • 1
    This does not help - there is no refresh token returned when using MSAL.JS. What I have been able to do so far is to call msalInstance.acquireTokenSilent(sharepointScopes) in the login.ts file and get the SharePoint Access Token too. However this is not ideal in a production environment as the access token expires in 1 hour, so the user will again need to click a button to initiate the popup to get another token. What I have seen is - if I can get the msal instance back from the popup to the react app then I can reuse it to call "acquireTokenSilent" - which will solve the issue. – gts Sep 01 '23 at 00:22