Closed tiwarigaurav closed 6 months ago
Can you please check the scopes docs and let us know if it helps?
@sameerag - I have already gone over this document and this does not help. We cannot combine Graph and SharePoint scopes in one request. Even if we could somehow (using a hack), this does not solve the problem i.e. when the access token expires (which is 1 hour) user will need to again click a button to initiate the popup and get another token.
Also pointing out the below text from my initial query -
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.
Getting a token for multiple resources can be achieved in the login.ts implementation (see code snippet below) - the main issue is that the user will need to login every 1 hour which is not ideal in a production app.
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) {
const authParamsSharePoint = {
scopes: ["https://tenant.sharepoint.com/.default"]
};
let spResp = await msalInstance.acquireTokenSilent(authParamsSharePoint);
Office.context.ui.messageParent(JSON.stringify({ status: 'success', result : response }));
} else {
msalInstance.loginRedirect(authParamsGraph);
}
})
.catch(() => {
console.log('failure');
});
};
})();
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.
Why is interaction needed every one hour? You should have a refresh token
in cache, which should help in renewing the access token
silently with acquireTokenSilent
. Also, you cannot combine two different scopes for access_token
but can combine them for consent
in the initial login click and then do separate acquireToken
calls for fetching the corresponding tokens.
Why is interaction needed every one hour? You should have a refresh token in cache, which should help in renewing the access token silently with acquireTokenSilent.
@sameerag - Yes, you are right for when the app is running in Outlook on the browser - but this is not true when the app is running on Outlook desktop application (Windows). It seems that the msalInstance does not have access to the cache from the popup. What I did is tried to get the acquireTokenSilent in the app.ts file after the login popup (see below).
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);
let msalInstance: PublicClientApplication = new PublicClientApplication({
auth: {
authority: "https://login.microsoftonline.com/organizations/",
clientId: "26431e25-8afe-44de-8ff3-43c6e89e8d86",
navigateToLoginRequestUrl: false
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: true,
},
});
const authParamsSharePoint = {
account: messageFromDialog.result.account,
scopes: ["https://tenant_name.sharepoint.com/.default"]
};
// I get an error here
let spResp = await msalInstance.acquireTokenSilent(authParamsSharePoint);
console.log(spResp);
}
else {
// Something went wrong with authentication or the authorization of the web application.
loginDialog.close();
}
}
Using the above I get the following error:
Exception has occurred: ClientAuthError: token_refresh_required: Cannot return token from cache because it must be refreshed. This may be due to one of the following reasons: forceRefresh parameter is set to true, claims have been requested, there is no cached access token or it is expired.
Note: that I need to initiate a new instance of the PublicClientApplication as REACT cannot share the context or variables between the login popup and the app.
Also, you cannot combine two different scopes for access_token but can combine them for consent in the initial login click and then do separate acquireToken calls for fetching the corresponding tokens.
Do you have any documentation or code samples for this?
@sameerag Please let me know if you need more details in investigating our issue. We anticipate quick response and resolution to above.
@sameerag - any updates for us in this issue?
This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @sameerag please follow up.
This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @sameerag please follow up.
This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @sameerag please follow up.
This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @sameerag please follow up.
This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @sameerag please follow up.
This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @sameerag please follow up.
This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @sameerag please follow up.
This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @sameerag please follow up.
This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @sameerag please follow up.
Apologies for missing to close this loop.
MSAL JS is explicitly for web, SPA experience. For desktop, the Office desktop folks probably are the best folks to help address this. Since the popup is doing the auth inside itself (with a redirect), MSAL JS cannot retrieve its cache to enable silent auth, as the popup tearing down will tear the MSAL cache too.
Closing this. If the issue is still unsolved, please raise a new issue. Thanks.
Core Library
MSAL.js (@azure/msal-browser)
Core Library Version
2.32.2
Wrapper Library
Not Applicable
Wrapper Library Version
None
Public or Confidential Client?
Public
Description
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:
In my login.ts file I have the following code:
Using the above setup I can get the Graph Access Token just fine and everything works.
How can I get access token for multiple resources using the msalInstance.acquireTokenSilent(scope) within the app.ts file?
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.
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.
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.
MSAL Configuration
Relevant Code Snippets
No response
Identity Provider
None
Source
External (Customer)