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.