Microsoft-authentication-library-for-js: Msal Js Supports Iframe In Iframe scenarios

Created on 31 Jul 2019  路  37Comments  路  Source: AzureAD/microsoft-authentication-library-for-js

As it currently stands msal js blocks certain scenarios when rendered inside of an iframe because there are edge case scenarios that can not be supported.

The goal is to unblock these so that it can be supported.

Linking all the relevant PRs for this ask:

Beta release
Released [email protected] here

  • [x] #939: Allows iframed applications call loginPopup(), acquireTokenPopup() and acquireTokenSilent().
  • [x] #983: Cache cleanup

Next beta release contents

  • [x] #975: Allows iframed applications call loginRedirect(), acquireTokenRedirect() by establishing a trust-relationship model with the top frame. This assumes the top-frame also runs MSAL JS.
  • [x] #1010 , #994 : Supporting multiple instances of MSAL JS and relevant cache cleanup.
    This is also a prerequisite for #975 and allows concurrent acquireTokenSilent() calls.
  • [x] #1042: Clear temporary cache on error exit paths
  • [ ] Documentation of the protocols/logic introduced for the above functionality to work
feature internal

Most helpful comment

Released [email protected] here. Please note that the CDN for this beta is not yet released and will be available early next week.

We are working on releasing a follow up beta for the remaining use cases mentioned in the description.

All 37 comments

What's the time-frame for this to be available for us?

@mozart27 they mention end of September here. Hope they hold up to it 馃槃

We are on track to deliver at end of September! We have some beta versions being tested with customers. Please let us know If you would like to test some betas with us! @sameerag

Hi @DarylThayil, what would it take for me to use a beta version that supports this? I want to see if my use case applies.

Would this unblock the scenarios where MSAL authentication in Teams apps breaks? If I recall Teams renders tab app inside an iframe so there were authentication issues trying to use MSAL...

@AndrewCraswell Teams app's requirements have some specific restrictions on the iframe applications, we are in internal discussions with them. Our solution is generic, and ideally should work but your specific scenario may need some fine tuning from the "Teams" app too.

@yuriys-kentico Can you please expand on your scenario? If you do not want to do it in public, you can reach me by email at sameera.[email protected]. I can share the internal beta build. We are planning a public beta in a week or so, currently it is being tested internally.

@sameerag The scenario is slightly complicated. We have one product called Kentico and another product called Kentico Kontent. The first product is an on-premise installation that is highly customizable but occasionally needs to be inspected locally by us after communication with the customer. Since there is also a database, the complete backups usually run a few gigabytes. Traditionally, we have used FTP to transfer these backups to us. This process has problems.

We are now developing a microservice infrastructure to replace the FTP process. The first phase of this infrastructure is a browser-based frontend that allows a backup to be uploaded or downloaded through a browser. Each backup request is created in Kentico Kontent using an internal project. The Kontent workflow needs to be customized for this scenario since the infrastructure depends on secure URLs for each backup request. The Kontent interface allows for customization through what we call custom elements. These elements sit inside iframes and are hosted externally. Since it is hosted externally and uses JavaScript, it is a good idea to add some kind of authentication. I want to do this authentication using the beta version to see how it interacts with the iframe.

@yuriys-kentico Can we set up a call?

  • For popups for interaction and silent calls for tokens, the beta we have works as expected. That is all your interactions (consent/credential entry) within the iframe are through popup calls - loginPopup() and acquireTokenPopup(), token acquisition in non-interactive usecases is through acquireTokenSilent().

  • For redirect flows, we have a little song and dance going with the top frame as iframes are blocked from interactions by the STS. If your usecase needs those APIs (loginRedirect() and acquireTokenRedirect()), we have a new beta coming up this week and I can help with the directions to test the same.

I would like to discuss the specifics before we put together the release notes for everyone if you want to help us with testing the same.

@sameerag sure, I'll send you an email.

@sameerag I'm using MSAL.js version 1.1.2 and I hosted my MSAL SPA inside the Azure Portal to test if it would work (embedded in an iframe and side-loaded). I can see that the page loads fine, and I can successfully call loginpop and authenticate! However, when I call "acquireTokenSilent" I don't see any outgoing calls or errors generated, it returns a promise that seems to never resolve. No errors in the developer console, within the iframe or in the top frame. Any idea what is going on? If I instead call "acquiretokenpopup" then it works successfully! So something funky going on with the acquire token silent implementation; what could cause the promise "deadlock"? Why is there no error thrown or logged?

@keystroke 1.1.2 does not resolve promises in silent calls. There is a decorator that restricts this in the code. This ticket(which has a bunch of PRs listed in the description) is an effort to remove that restriction in msal js and allow apps in iframes to resolve tokens.

However identity places some restrictions on interactions on an iframe, hence we have certain conditions placed on redirect flows where there is no popup to fall back. Please watch out for the next beta release or you can ping me to try out an internal beta we are testing out right now if you want to early test this.

Hope this clarifies.

@sameerag I was able to work around the current behavior with below code snippet:
js const key = request.authority + options.scope; if (!this.HACK[key]) this.HACK[key] = msal.acquireTokenPopup(request); return await this.HACK[key];

I tried above code to replace old pattern shown below for now and verified this works, though it will generate a popup which automatically closes in the scenarios where silent token acquisition would work. THIS IS NOT PRODUCTION CODE DON'T WORRY ;)

js const request = { authority: this.authority(), scopes: [options.scope] }; try { const silentResponse = await msal.acquireTokenSilent(request); return silentResponse; } catch (error) { if (error.name === 'InteractionRequiredAuthError') { console.log(error); const interactiveResponse = await msal.acquireTokenPopup(request); return interactiveResponse; } console.error(error); throw error; }

I am only working with MSAL.js for proof-of-concept right now, good to know there is already beta version that will enable these scenarios :)

Do you folks support any use of MSAL.js directly in the Azure Portal for Ibiza Extensions? Curious if you've explored this scenario at all. I noticed the Azure Portal exposes an "OAuthButton" control that also launches a popup to handle user login flows: https://ms.portal.azure.com/?Microsoft_Azure_Playground=true#blade/Microsoft_Azure_Playground/ControlsIndexBlade/OAuthButton_create_Playground

We haven't. Would need some time to check this scenario and if we can support it. Can I reach out may be in a week once we stabilize our beta release? @DarylThayil FYI for the scenario.

@sameerag @DarylThayil Thanks! Some more info as FYI below on integrating with the Azure Portal (please note I'm not actually on their team or anything, nor am I a proper front-end dev, I've just been hacking this stuff together for Azure Stack).

Looking through Ibiza docs, they have a "frame control" where you can host an external page in an iframe: https://ms.portal.azure.com/?Microsoft_Azure_Playground=true#blade/Microsoft_Azure_Playground/ControlsIndexBlade/FrameControl_create_Playground

They include this example for how to host the page, this is what I used
````ts

import * as FrameControl from "Fx/Controls/FrameControl";

const myFrameControl = FrameControl.create(container,
{
onReceiveMessage: (message: any) => {
// Handle message from the iframe.
switch(message.messageType) {
// This is an example of how to listen for messages from your iframe.
case 2:
MsPortalFx.Hubs.Notifications.ClientNotification.publish({
title: "FrameControl",
description: message.data,
status: MsPortalFx.Hubs.Notifications.NotificationStatus.Information,
});
break;
default:
break;
}
},

src: "https://playground.hosting.portal.azure.net/playground/Content/5.0.302.481011398.190913-0124/framecontrolpage.html",

});

````

I was able to host a "hello world" extension locally on my dev box and "side-load" it into the Azure Portal and host a SPA using the msal.js (modifying the src property above). Something like this is probably a decent way to test support for MSAL in iframes in a "real world" app. Note that I only tested the popup flows, not the redirect flows.

Would acquireTokenSilent ever work from an iframe? Isn't that technically impossible because of things like X-Frame-Options: deny (which should be set to prevent clickjacking)?

@eirikb For acquireTokenSilent msal js spins off a hidden iframe and as long as no interaction is needed (SSO when you already have a session with the STS, it is supported in iframes.

X-Frame-Options: deny is set and the setting blocks interactive flows on the same frame -> which translates to acquireTokenRedirect and loginRedirect not working the classic way. We came up with a trust model with the parent app (which is top frame and full window) to support these usecases for certain app models.

In the coming weeks, we plan to release beta versions supporting these changes with a detailed blog post. Hope this clarifies.

@keystroke There was never any restriction on Popups for iframed applications. The restrictions were only for acquireTokenSilent and redirect flows though not restricted from MSAL JS would not work for reasons mentioned above.

Please reach out to me on teams, if you are willing to test out early builds for these scenarios, any testing is appreciated :-)

@sameerag does this beta you're talking about have any relation to https://youtu.be/xLjT1Hw5a1E?t=1472 ?

UPDATE

939 is merged to dev today. Working on stabilizing #980 and #994 today to release the first beta npm release publicly.

Released [email protected] here. Please note that the CDN for this beta is not yet released and will be available early next week.

We are working on releasing a follow up beta for the remaining use cases mentioned in the description.

UPDATE:

975 and #1010 in the final leg of testing.

UPDATE:
Added #1042 to handle cache cleanup in error cases.

Released couples of betas now with all the changes, latest beta being msal 1.2.0-beta.2. Gearing up for the release of msal 1.2.0 with samples and documentation.

Note: The betas are available in npm, we will be making the CDN release for the latest beta soon, and then follow up with the wiki update on the release notes.

Is there to be a scenario for Microsoft Teams and MSAL? (Which Is an Iframe, on iframe with an Iframe?)
I can get the current beta to work with Teams in a browser, but not the actual Teams app itself, I am unable to complete login via pop-up or msteams.authenitcation + re-direct.

UPDATE:

To facilitate feedback from various teams, we have been releasing betas for the last 2 months and currently at msal 1.2.0-beta.4. The final PR needed for cache cleanup is merged this week to dev and we are releasing msal 1.2.0-beta.5 today. There will be a msal 1.2.0 released later this week which will be the same as msal 1.2.0-beta.5.

Is there something we need to do to activate this capability. I'm on 1.2.0-beta.5 but when I run the process of acquiring a token via acquireTokenSilent but that fails with the error ClientAuthError: Token calls are blocked in hidden iframes still. Are these changes suppose to allow acquireTokenSilent to work correctly?

I'm on chrome.

@aappddeevv This is expected. Please check the beta release notes here. You can either:

  1. Choose to ignore this error
  2. Set a blank page or any page without scripts running as the redirectUri for acquireTokenSilent() calls.

[email protected] will be released soon (which is technically same content as [email protected]) with sample code for option 2.

Thanks. I had read a bunch of those notes but did not understand that option (1) was available. I assume (1) means ignore the error but it is still working all Ok.

@aappddeevv yes, your understanding is correct. We will try to get this message across board in the release notes for [email protected]. Thank you for the quick testing and feedback.

I must admit, I still can't get this library to work consistently on its own sometimes.

I am trying to get an idtoken first then an access token. I do not provide any scopes to my loginRedirect() request so that only openid and profile are sent. The request goes out but when I try to get a token (acquireTokenSilent) the cookie is not set and I get a AADSTS50058: A silent sign-in request was sent but no user is signed in... error from the authorize endpoint.

  • If I set a minimal scope, such as "user.read" I do not get this error.
  • If I set a minimal scope, with a custom scope, "api:///user", I do not get this error but I'm not logged in as there is a msal.error in storage with message "login_required.". The "my app" (not graph) token for my app resource will not validate with passport-azure-ad. The authorize request for my api custom scope returns "302".

@aappddeevv If this isn't specific to iframe-in-iframe, can you please open a separate issue with your questions? Thanks!

I can do that, but I I thought it was due to the use of "redirect" which runs in an embedded iframe vs "popup".

@aappddeevv Currently, applications running inside an embedded iframe will not be able to use loginRedirect, as the AAD login UI cannot be shown in an iframe. We're working on a long-term solution for this, but for now, you will need to use popup methods when MSAL is running inside an iframe.

Hmm..perhaps I am on the wrong issue then. I'm not able to get redirect methods to work in the toplevel iframe. My app is not in an embedded iframe. I'll keep playing with this issue and see if its pilot error. Thanks.

@aappddeevv Ah, yes if you need help with an application running in the top frame, please open a new issue, thanks!

[email protected] released.

  • Please check the release in npm; CDN release will be coming soon; mostly today.
  • Please read the release blog and the changelog for the feature/fixes summary.
Was this page helpful?
0 / 5 - 0 ratings