i am working on Office Outlook Add-in and trying to get the token using msal.js to login to MS Graph, but it doesn't work. It is not getting the token silently in acquireTokenSilent method. it is similar to #339 issue and closed the issue without providing any solution. As mentioned by Ideline in the issue #339 , it is working fine with acquireTokenPopup, but i want it get it silently as the user logged already. Apart, i am able to get it working in SPA browser app. It is only with the Office outlook Add-in that is not getting the token silently, my code follows (JavaScript, jQuery Office Outlook Add-in)
function signIn() {
myMSALObj.loginPopup(applicationConfig.graphScopes).then(function (idToken) {
//Login Success
//showWelcomeMessage();
acquireTokenSilentForApp();
}, function (error) {
console.log(error);
});
}
function acquireTokenSilentForApp() {
console.log("Inside acquire token"); // this is called
//Call acquireTokenSilent (iframe) to obtain a token for Microsoft Graph
myMSALObj.acquireTokenSilent(applicationConfig.graphScopes).then(function (accessToken) {
//setAuthToken(applicationConfig.graphEndpoint, accessToken, graphAPICallback);
console.log("Token found 1" +accessToken); // THIS IS NOT CALLED
}, function (error) {
console.log(error);
// Call acquireTokenPopup (popup window) in case of acquireTokenSilent failure due to consent or interaction required ONLY
if (error.indexOf("consent_required") !== -1 || error.indexOf("interaction_required") !== -1 || error.indexOf("login_required") !== -1) {
myMSALObj.acquireTokenPopup(applicationConfig.graphScopes).then(function (accessToken) {
console.log("Token found 2" +accessToken); // THIS IS NOT CALLED EITHER
}, function (error) {
console.log(error);
});
}
});
}
What am i missing here? please help
@Francis-B When you say acquireTokenSilent doesn't work, what is the failure behavior you are seeing? Is there any error message in the network traces or in console logs? Which version of library and what browsers are you seeing this in? Please use the issue template to file so we have the information of the error behavior and the expected behavior.
I have same or similar problem as @Francis-B.
I'm trying to get accesss token in Office Outlook Add-in using msal.js (v.0.2.3.). I'm using the same code as in "Quickstart for MSAL JS".
myMSALObj.loginPopup(applicationConfig.graphScopes).then(function (idToken) {
//Call acquireTokenSilent (iframe) to obtain a token for Microsoft Graph
myMSALObj.acquireTokenSilent(applicationConfig.graphScopes).then(function (accessToken) {
callMSGraph(applicationConfig.graphEndpoint, accessToken, graphAPICallback);
}, function (error) {
console.log(error);
// Call acquireTokenPopup (popup window) in case of acquireTokenSilent failure due to consent or interaction required ONLY
if (error.indexOf("consent_required") !== -1 || error.indexOf("interaction_required") !== -1 || error.indexOf("login_required") !== -1) {
myMSALObj.acquireTokenPopup(applicationConfig.graphScopes).then(function (accessToken) {
callMSGraph(applicationConfig.graphEndpoint, accessToken, graphAPICallback);
}, function (error) {
console.log(error);
});
}
});
}, function (error) {
console.log(error);
});
"loginPopup" works and I get idToken from it, but "acquireTokenSilent" doesn't work. It returns nothing, no errors nor any other responses.
Part of the code in the case of "acquireTokenSilent" failure (acquireTokenPopup), is not being called;
When I call "myMSALObj.logout()", I get error message in Chrome: "Refused to display 'https://login.microsoftonline.com/common//oauth2/v2.0/logout?post_logout_redirect_uri=https%3A%2F%2Flocalhost%3A44333%2F' in a frame because it set 'X-Frame-Options' to 'deny'."
All of the above comes from testing in Chrome v.71.0.3578.80.
In IE11 and Edge I had issues with opening login popup and redirecting, with cors ("HTTPS security is compromised by res://ieframe.dll/forbidframing.htm", "[CORS] The origin 'https://outlook.office.com' failed to allow a cross-origin document resource at 'ms-appx-web:///assets/errorpages/dnserror.html.").
In desktop app (Outlook 2016 v.1808 Build 10730...), "myMSALObj.loginPopup" opens login page in default browser and hangs after login (tries to open origin url in browser).
The same code works fine outside the office environment (in regular web page).
@Francis-B When you say acquireTokenSilent doesn't work, what is the failure behavior you are seeing? Is there any error message in the network traces or in console logs? Which version of library and what browsers are you seeing this in? Please use the issue template to file so we have the information of the error behavior and the expected behavior.
i am facing the exact same issue as in #339 . it is clearly explained there. loginPopup is working and after the login, the acquireTokenSilent is not getting triggered and not able to get the token. But i am able to get the token with acquireTokenPopup method alone. i tried it in OWA for firefox and chrome
@Francis-B When you say acquireTokenSilent doesn't work, what is the failure behavior you are seeing? Is there any error message in the network traces or in console logs? Which version of library and what browsers are you seeing this in? Please use the issue template to file so we have the information of the error behavior and the expected behavior.
any update on this??
Apart, i somehow got it working in IE11, but it still not able to get the token in Outlook Desktop client. Outlook client even though the IE11 is set as the default browser
i am using SPA using MSAL.JS example code in my add-in app.
The else condition is getting is getting executed in Outlook Desktop Client from the below and i am redirected to login Page. But After Login, i think the handle is not returned to the Outlook client add-in, so no token is received.
if (!isIE) {
if (myMSALObj.getUser()) {// avoid duplicate code execution on page load in case of iframe and popup window.
showWelcomeMessage();
acquireTokenPopupAndCallMSGraph();
}
}
else {
document.getElementById("SignIn").onclick = function () {
myMSALObj.loginRedirect(applicationConfig.graphScopes); // Especially this line is getting executed in the OUTLOOK DESKTOP Client
};
if (myMSALObj.getUser() && !myMSALObj.isCallback(window.location.hash)) {// avoid duplicate code execution on page load in case of iframe and popup window.
showWelcomeMessage();
acquireTokenRedirectAndCallMSGraph(); //Whereas in IE11, this is getting executed from my OWA add-in and it if working fine
}
}
What's wrong and what is stopping the outlook client to not getting the handle back to it?
Please help if anybody from MS checking this
Thanks
I'm also having the same exact issue. I used this code sample here in Edge and Chrome. loginPopup works with login_hint but acquireTokenSilent doesn't execute or even fail when called.
Hey @Francis-B,
I am developping an Outlook Add-in and ran the same problems as you using the Msal.js library. I just wanted to share with you what I did:
Gave up using Msal.js
Migrating my authentication to authentication-migration-to-office-js-helpers
This library is really interesting because it uses Office Add-In API and handles the popup so much better. Moreover, with just one call to "authenticator.authenticate" you get an access token. There is no need like in Msal to ask the user to "login" then "acquireTokenPopup".
If you are using a JS framework like React/Angular/Vue along with a router component, make sure not to load it (check https://github.com/OfficeDev/office-js-helpers/issues/19).
Good luck,
Denis
Same issue when authenticating from an Iframe in a JS webapp.
The same code works fine when loaded from the top frame, but not when loaded in a child frame, which is mandatory for me.
Basically the issue seems that acquireTokenSilent() promise never return nor throw.
So the fallback to acquireTokenPopup() never trigger. Even if popup authent is a bad experience, at least it would work.
import {UserAgentApplication} from 'msal/lib-es6';
// Enter Global Config Values & Instantiate MSAL Client application
const MS_CLIENT_ID = 'your client id';
const MS_SCOPES = [
'user.read',
'email',
'files.read',
];
function authCallback(errorDesc, token, error, tokenType) {
// This function is called after loginRedirect and acquireTokenRedirect. Not called with loginPopup
// msal object is bound to the window object after the constructor is called.
console.log(arguments);
}
const clientApplication = new UserAgentApplication(
MS_CLIENT_ID,
null,
authCallback,
{cacheLocation: 'localStorage'},
);
window.ms_login = function () {
return clientApplication.loginPopup(MS_SCOPES)
.then(() => {
console.log('USER infos', clientApplication.getUser());
return clientApplication.acquireTokenSilent(MS_SCOPES)
// NEVER pass this point !!
.then(accessToken => {
console.log('acquireTokenSilent sucess');
return accessToken
}, () => clientApplication.acquireTokenPopup(MS_SCOPES));
})
.then(accessToken => {
console.log('accessToken = ', accessToken);
return accessToken;
})
.catch(err => {
console.error(err);
});
};
// test login
ms_login()
@JeanRemiDelteil Any luck finding a solution?
Based on the description from @JeanRemiDelteil I'm guessing this is related to the @resolveTokenOnlyIfOutOfIframe.
When it returns a Promise on line 83, I think it should return Promise.reject("I'm in an iframe") rather than a Promise constructor that does nothing. Currently, the Promise it returns will never resolve nor reject.
@zamzowd indeed this is the cause in the code.
Though I'm quite taken aback that it's added in the code that it does not resolve when in an Iframe...
My use case is authenticating inside web widgets that always _are_ Iframes.
More than that, for security purpose my authentication is taking place in a dedicated Iframe.
What's the idea behind forcing the authent not to work in Iframe, does that mean that I have to make my own fork where it works ?
@JeanRemiDelteil I'm not really sure as to why. They've written recently that it's because of security concerns for Azure AD, which is strange because it only stops malicious code from using this library, not from actually getting user/token/authority data or triggering an authentication attempt outside of this library.
I've been under the impression that it's to prevent additional iframes created by this library itself when it loads inside the iframe after the redirect from the authority, but in that case the condition can be made more specific (check that the parent window has msal in the same state) rather than disallowing within any iframe.
IMO, this library tends a little too much to making decisions/assumptions on behalf of the developer or the authority. It's with a similar mindset that led to me making pull requests so I can do a silent attempt for a session from the authority if the app has no cached data and without interaction from the user.
BTW I included the change I mentioned to resolveTokenOnlyIfOutOfIframe in my new pull request #572.
@JeanRemiDelteil @Francis-B To summarize your scenario: You have an authenticated user session in the Outlook client, and your add-in(which is in an iframe) wants to silently get access tokens for MS Graph. Is that right?
There is a pattern documented for the authentication flow in Outlook add-ins framework here which makes use of the Office.js API: https://docs.microsoft.com/en-us/office/dev/add-ins/develop/sso-in-office-add-ins
Please try the above approach and let us know if it resolves the issue.
@navyasric relying on SSO to try and get around the problems with using the Microsoft Authentication Libraries (ADAL/MSAL) isn't a solid solution. The documentation that you refer to clearly states:
"You should not rely on SSO as your add-in's only method of authentication. You should implement an alternate authentication system that your add-in can fall back to in certain error situations."
So we are told that we must implement another form of authentication besides SSO which brings us back to the original issue that the MSAL library has issues running inside of Office addins.
Can we get some suggestions on how to patch MSAL to get it to work in Outlook addins, and in every host (Win32 Desktop, Mac, OWA(Chrome/Edge/IE), Android, iOS)
Prior to MSAL I encountered the same issues with ADAL (it didn't play well inside Office Add-ins). I've gone down an approach similar to what @super2ni suggested and wrote the raw HTTP calls to do authentication utilising the Office.js Dialog API to get around the problems with ADAL. I'd really hoped that MSAL would have solved these problems.
I've hosted some basic web pages publically to try and demonstrate these issues with MSAL at it's most basic with Office add-ins.
Here I've taken the Microsoft MSAL JS Quickstart sample, which is a single html page containing all the js to do the MSAL login and make a call to the Graph to return user details. The only changes I've made are specifying the client Id and adding some explanation text to the top of the file. This show MSAL working as expected and you can login and get user details returned.
https://camtosoweb.blob.core.windows.net/$web/index.html
What I've then done is create a second html page (called hosted.html) which shows index.html in a sandboxed iframe with all the same attributes that are used when Outlook Online (Web Access) displays an Outlook Add-in. Here you will see that same index.html page that worked when it wasn't in an iframe falls apart when hosted inside an iframe of another page.
https://camtosoweb.blob.core.windows.net/$web/hosted.html
This is how add-ins to Office are hosted and fundamentally prevents MSAL libraries from being used.
Regarding the security concerns of clickjacking and similar vulnerabilities when inside an iframe:
X-Frame-Options: deny. Trying to write MSAL.js to protect against this is redundant to protections that the authority can provide. While most authorities do this by default, some of them (such as Okta) provide a configuration option to allow iframe embedding (accompanied by a warning about clickjacking).Not only is MSAL.js trying to protect against this vulnerability in the wrong circumstance, it shouldn't have to protect against it at all. Leave it up to the developer using MSAL.js and the authority.
@JeanRemiDelteil @CameronDwyer @zamzowd Yes, this is not a security issue. I have been digging on this for couple days and confirmed that the original intent behind adding @resolveTokenOnlyIfOutOfIframe was to solve an engineering issue they had at that point. We think changing this is possible and we are designing a feasible solution.
I acknowledge this is blocking everyone who wants to use MSAL JS within an iFrame. I have also had internal MSFT applications who also are in need of this functionality.
We plan to pull this into or right after the Final Preview. Since this changes some basic assumptions the library makes regarding window.parent etc, we need some testing before we roll this out.
Thanks @zamzowd for the active participation and helping us with prioritizing some blockers by identifying them and being involved in the community.
This may be resolved in #899 targeting a release by end of September 2019.
Marking this ticket as under consideration. so that after we resolve Iframe in Iframes we can circle back with the office team to see what other scenarios may be missing.
Closing this as we are tracking supporting acquireTokenSilent() in iframes with #899.
How can we already use the beta version ? Is there any sample showing an Office Add-In making use of the MSAL.JS plugin? I've tried to use it but the loginRedirect method keeps opening a new tab in Safari making it verify difficult to perform the authentication.
Thanks.
Most helpful comment
@JeanRemiDelteil @CameronDwyer @zamzowd Yes, this is not a security issue. I have been digging on this for couple days and confirmed that the original intent behind adding @resolveTokenOnlyIfOutOfIframe was to solve an engineering issue they had at that point. We think changing this is possible and we are designing a feasible solution.
I acknowledge this is blocking everyone who wants to use MSAL JS within an iFrame. I have also had internal MSFT applications who also are in need of this functionality.
We plan to pull this into or right after the Final Preview. Since this changes some basic assumptions the library makes regarding window.parent etc, we need some testing before we roll this out.
Thanks @zamzowd for the active participation and helping us with prioritizing some blockers by identifying them and being involved in the community.