Microsoft-authentication-library-for-js: Login Flow not working for MS Teams App with 1.2.0-Beta.3

Created on 5 Nov 2019  路  12Comments  路  Source: AzureAD/microsoft-authentication-library-for-js

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[X] Bug report  
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Other... Please describe:

Browser:

  • [X] Chrome version 78.0
  • [X] Firefox version 70.0
  • [ ] IE version XX
  • [ ] Edge version XX
  • [ ] Safari version XX

Library version


Library version: 1.2.0-beta.3

Current behavior


I am trying to make the authentication work in a MS Teams Tab App using MSAL.JS

MS Teams requires me to open a popup for authentication with it's own method (microsoftTeams.authentication.authenticate) as normal popups are blocked by the MS Teams client. So I can not use the loginPopup()-Method of MSAL but have to use loginRedirect() from within the MS Teams Popup.

The authentication itself works and redirects back with a valid id_token in the url-hash. However, the hash is not handled and the redirect callback nevers gets called.

The reason is Line227 in the constructor of the UserAgentApplication:

if (!this.config.framework.isAngular && urlContainsHash && !WindowUtils.isInIframe() && !WindowUtils.isInPopup()) {
            this.handleAuthenticationResponse(urlHash);
}

The last condition WindowUtils.isInPopup() is true in this case, and therefore handleAuthenticationResponse() is never called.

I don't know the reason for this check in this particular case - but is there a way to work around this issue?

Falling back to an older version of MSAL is also no option as I also need the new IFrame-Capapbility to use acquireTokenSilent(). I also tried adal.js, but that is currently not working on mobile due to another IFrame issue.

Expected behavior


The callback of loginRedirect() is also called within a popup-window.

Minimal reproduction of the problem with instructions


Use loginRedirect() from within a popup window.

bug compatibility p2

Most helpful comment

I got it working with this example and version 1.3.0:
https://github.com/nmetulev/teams-msal

All 12 comments

@davelosert We are aware of the compatibility issues using our library within a Teams tab, and unfortunately, the solution is a lot more complicated that just allowing handleAuthenticationResponse to be invoked in the UserAgentApplication constructor when it is inside a popup window in Teams.

We are engaged with Teams Engineering directly to work on a solution, and we'll post an update when we have a solution available.

@jasonnutter: Alright, thank you very much for your response, I really appreciate it. Then I'll patientely wait for your update.

The release notes for 1.2.0 say this:

Iframes Support added (#939, #975, #1053, #1075); msal js now added support for authentication in applications embedded in iframes which implies that an application can now call loginSilent(), acquireTokenSilent() and acquireTokenPopup() from iframes.

Does this mean this ticket should now be closed and MSAL can be used from within MSTeams Tab?

[email protected] is available with a fix for this issue, please let us know if it is still a problem. Thanks!

[email protected] is available with a fix for this issue, please let us know if it is still a problem. Thanks!

works!

Could you advise on what sample would be best to follow for this? I think I've almost got it wired up but I am getting some redirect issues, bouncing around and I'm not sure I've got it figured out. Is the proper auth page flow i.e. call loginRedirect -> (user does login prompt on ms site) -> redirected back to handleCallbackresponse (first time?) -> acquireTokenRedirect -> ms token -> redirected back to handleCallbackresponse (second time?) ...

@taysco Your understanding is correct for redirect flows. What exactly is the issue you are seeing now? As @jasonnutter mentioned above, the teams use case should work with [email protected]

I got it working with this example and version 1.3.0:
https://github.com/nmetulev/teams-msal

I still have problems with logging the user in when my website is running in teams.

msal.loginPopup() does nothing in teams. Is this intended after the above mentioned fix?

So if I understand correctly... I have to use loginRedirect() in teams and loginPopup() on normal webpage... how can I achieve this? I can make a check "if (window.self === window.top) {" if the website is running in iframe... but still some iframes don't have problems opening popups. How would I specify that loginRedirect() only happens in teams?

Tried to implement this check for iframe that I mentioned above... and it doesn't work in teams. it returns true instead of false (don't really understand why teams would make your app think that it is not running in iframe).

Then because this didn't work I made use of 'msal:loginFailure' subscription where I checked if there was an 'popup-window-error'.. and if there was I called 'loginRedirect()'. Somehow this doesn't work all of the time. I have to press the login button 4 times to get logged in because I get an error that my 'handleRedirectCallback' is not handled.. which 100% is.

I just hope any of you has a better solution.

I figured out a couple hours after I posted. My issue ended up being a react issue where calling the same route twice doesn't actually update window.location.hash so my callback was never working. Once I split it so there was a redirect end, it started working.

I think your confusing that MSAL.js does Teams things. It doesn't.. you need to use the msteams-js-sdk to create a iframe/popup which has your MSAL loginRedirect flow inside that. So you popup the MSAL login tab via the teams sdk, then login using loginRedirect (which was fixed recently), then pass the accessToken back into your teams app via notifySuccess() (which also closes the teams popup)

So yes, you must use loginRedirect in a ms tabs them pop up. You do not use loginPopup at all in MS Teams. MSAL is simply running in the teams iframe so it must use the redirect flow. So you'll ideally have two files, auth-tab-start and auth-tab-end. In auth-tab-start, you'll do the MSAL authentication and make sur eyou have redirectUri: 'auth-tab-end' AND make sure you have navigateToLoginRequestUrl set to false. The redirectUri is ignored if navigateToLoginRequestUrl is true... (I think that's messed up btw.)

My MSAL config in the tab-start looks like:
private msalConfig = {
auth: {
clientId: process.env.REACT_APP_AAD_CLIENTID as string,
redirectUri: ${window.location.origin}/tab/end,
navigateToLoginRequestUrl: false,
authority: 'https://login.microsoftonline.com/common',
},
cache: {
cacheLocation: 'localStorage' as any,
storeAuthStateInCookie: false,
},
};

In my tab-end I have this, once I get the token, I return the access token to the teams client via microsoftTeams.authentication.notifySuccess

authRedirectCallBack = async (error, response) => {
    if (error) {
        console.log(error);
    } else {
        console.log('auth redirect 1');
        if (response.tokenType === 'id_token') {
            try {
                const tokenResponse = await this.myMSALObj.acquireTokenSilent(this.tokenRequest);
                if (tokenResponse) {
                    microsoftTeams.authentication.notifySuccess(tokenResponse.accessToken);
                }
            } catch (error) {
                // Call acquireTokenPopup (popup window) in case of acquireTokenSilent failure due to consent or interaction required ONLY
                if (requiresInteraction(error.errorCode)) {
                    this.myMSALObj.acquireTokenRedirect(this.tokenRequest);
                }
            }
        } else if (response.tokenType === 'access_token') {
            microsoftTeams.authentication.notifySuccess(response.accessToken);
        } else {
            console.log('token type is:' + response.tokenType);
        }
    }
};

}

Then in my teams app, I have a button which does this to kick off the teams iframe. This is the way to get MSAL in a popup... not loginPopup:

login() {
    return new Promise((resolve, reject) => {
        microsoftTeams.authentication.authenticate({
            url: `${window.location.origin}/tab/silent-msal`,
            width: 600,
            height: 535,
            successCallback: (result) => { // result is what is passed into notifySuccess in tab end
                console.log('login success', result);
                this.accessToken = result;
                const user = this.myMSALObj.getAccount();
                console.log('user', user);
                resolve(user);
            },
            failureCallback: (reason) => {
                console.log('login rejected', reason);
                reject(reason);
            },
        });
    });
}

Hopefully this helps... I realize it's in pieces so you kinda have to glue it back together... if you need a better sample, I can probably put one together later tomorrow.

Hi, @taysco I have the same issue on react app.
On auth-end page, it does Nothing even though it redirects after login and hence popup do not close.
Can I see your code samples how did you solve react location hash issue?

Also if you can share your full auth-start, auth-end code, that would be really helpful.
Thank you.

Was this page helpful?
0 / 5 - 0 ratings