Microsoft-authentication-library-for-js: SSO with AAD B2C fails

Created on 28 Mar 2018  Â·  17Comments  Â·  Source: AzureAD/microsoft-authentication-library-for-js

Hi,

We've been hitting issues similar to #208. We are using AAD B2C and have Single Sign On configured on the policies correctly. No issues when using MVC OpenID Connect apps, we get the expected SSO behavior. First time we login to B2C and subsequent apps, pressing the login button redirects to B2C and then instantly returns.

We have not been able to get MSAL.js to work. I strongly suspect the prompt=select_account is interfering with SSO. The suggested workarounds did not work as we got errors back saying login_required despite having an active SSO session.

Repro is this: Two apps sharing a B2C signup or sign in policy configured with SSO. First app is an ASP.NET Core app using MVC and the OIDC middleware. Second app is a SPA app with MSAL.js. Login with the ASP.NET Core app first. Now in the same browser tab, go to the SPA app. You should still be signed into B2C, but when you press login on the SPA site, the redirect to B2C forces a sign in.

The ask is this: MSAL.js, out-of-the-box, needs to support SSO with AAD B2C. No special workarounds, it just needs to work. We have validated that MSAL.js is the issue, and not B2C, since other apps using hello.js, for example, do work correctly.

b2c enhancement

Most helpful comment

We have confirmed that by removing that prompt parameter, MSAL.js does work. So perhaps that needs to be revisited?

This also impacts other flows, like calling edit profile. aquireTokenRedirect always adds that prompt, so even if we try to do an edit profile, it prompts for a login

function editProfile() { clientApplication.acquireTokenRedirect(applicationConfig.b2cScopes, applicationConfig.editProfileAuthority, clientApplication.getUser()); /* NOTE: optional popup login clientApplication.acquireTokenPopup(applicationConfig.b2cScopes, applicationConfig.editProfileAuthority, clientApplication.getUser()).then(function (accessToken) { logMessage(“Edit profile success.“); }, function(error) { logMessage(“Error editing profile:\n” + error); }); */ }

All 17 comments

We have confirmed that by removing that prompt parameter, MSAL.js does work. So perhaps that needs to be revisited?

This also impacts other flows, like calling edit profile. aquireTokenRedirect always adds that prompt, so even if we try to do an edit profile, it prompts for a login

function editProfile() { clientApplication.acquireTokenRedirect(applicationConfig.b2cScopes, applicationConfig.editProfileAuthority, clientApplication.getUser()); /* NOTE: optional popup login clientApplication.acquireTokenPopup(applicationConfig.b2cScopes, applicationConfig.editProfileAuthority, clientApplication.getUser()).then(function (accessToken) { logMessage(“Edit profile success.“); }, function(error) { logMessage(“Error editing profile:\n” + error); }); */ }

@onovotny we just released msal 0.2.3 and it has support for SSO. SSO can be achieved by passing either login_hint or SID.
Can you please tell me if you were passing either login_hint or SID?

@nehaagrawal I have a problem with this. This is my scenario: We have two applications, one SPA that uses msal.js and another MVC application which is not using msal.js. I log in to the MVC application through azure B2C with out SignInSignUp policy and now I have an existing session on Azure, then when I redirect to the SPA and pass a login_hint which msal.js recieves and sends in the extraQueryParams of the loginRedirect. The problem is that when loginRedirect executes it take me to azure using the same policy and it shows the login page and I see the login_hint in the url. Isn't is suppose to log me in or am I doing something wrong?

@SimeonBanev Please try passing the login_hint extraQueryParameter to the acquireTokenSilent method in order to get silent SSO. the login methods are interactive and pass a prompt parameter which is why you are seeing the login page again.

@navyasric But how could that work when there is no logged in user. I tried calling acquireTokenSilent but every time I get the error: 'user_login_error: User login is required' which is understandable give the fact that the clientApplication has no user when you enter the app initially. That is why i tried calling the loginRedirect method so I can get an id_token. Is there something I am missing here which should make the acquireTokenSilent work? I have followed the steps in this article and I am calling it the same way as described - https://github.com/azuread/microsoft-authentication-library-for-js/wiki/Sso

Okay so I debugged the acquireTokenSilent method and it turns out that the problem was that the token request with the loginHint failed and that caused my app to just call it again without an extraQueryParameter so that is why I got the user_login_error. The real problem is that when acquireTokenSilent tries to get the tokens with the login_hint an error is returned: "interaction_required: AADB2C90077: User does not have an existing session and request prompt parameter has a value of 'None'." but that can't be right since I literally logged in to another application with the same tenant and policy 1 minute before that so I have an azure session. I looked up some threads on this issue but I couldn't seem to find any real solution. Any ideas?

@nehaagrawal @navyasric I'm not sure how we're expected to use SID or login_hint for SSO. These are still values that need to either be saved in the application or entered by the user. If the user has an active SSO session in B2C, then they should count as authenticated when first entering the application even if the application doesn't have anything to identify the user.

acquireTokenSilent doesn't even check B2C for a session if the application doesn't already have saved or provide some kind of user identification (userObject, sid, or login_hint).

The desired behavior is achieved with prompt=none, but MSAL.js still has prompt=select_account hard-coded in. The apparent reluctance in allowing this is frustrating, and forces us to reconsider using MSAL.js at all.

@onovotny We have a PR in progress to remove prompt=select_account hardcoding. Once this feature is released. I will update the details here.

Is it resolved... ?

Hi @SimeonBanev ... Have you find any solution

@nehaagrawal is there anything done. If yes please please please let me know

@azure/msal-angular npm package is not updated yet, is it in progress or all have ignored this issue... ?

@onovotny @SimeonBanev @zamzowd @vipswelt We release the feature to remove the default prompt=select_account in MSAL.js v0.2.4. Please give it a try and check your scenarios.
You can find more details in this wiki topic.
Closing this issue as it should be fixed. Please reopen if necessary.

@navyasric Thanks for the update. I've been re-engaged on this task, so will be following up here.

The 0.2.4 library, while a step in the right direction, still does not satisfy my use case. I'd like to use acquireTokenSilent([clientId]) on page load to determine if the user has already been authenticated through another application. To be considered Single Sign On, user authentication should work in _this_ application if the user is already authenticated on another application using the same Azure AD, _even if_ the user has not done anything on this application yet.

On calling acquireTokenSilent([clientId]) I am getting the message "User login is required". This is before it even attempts the authentication request against Azure AD.

The issue is in UserAgentApplication.ts:1235. It calls checkSSO which checks if login_hint or sid are in the extraQueryParameters. Both of these values are related to the user, while I'd like the application to check if the user is authenticated without needing any information about the user. The user's cookie should be ready to get from Azure AD since we set prompt=none.

If I comment out the if statement with the checkSSO, then I get the desired behavior. Starting logged out of everything, I can first log into application A, and then go to application B and the acquireTokenSilent on application B pulls my user information from Azure AD.

I would like this issue re-opened until we can get SSO behavior in msal:

  1. Cache is cleared, user is not logged into anything.
  2. User navigates to application A, and logs in.
  3. User navigates to application B, and it determines that the user is already authenticated.

@zamzowd In MSAL.js we require an authenticated user context to be established in the library before the acquireTokenSilent method starts fetching tokens that provide access to APIs. Secondly, the library is also used in scenarios where there can be multiple accounts having active sessions for a user. The acquireTokenSilent method cannot determine which user session to pick and establish the context. Hence a login_hint is required for establishing the user context before providing the silent SSO capability.

Since we removed the default prompt=select_account from the login requests as well, can you try calling the login methods and see if you get the SSO behavior for the user session?

@navyasric If the loginRedirect is called, it does get a token from an active session on the authority without the user needing to select an account or log in again.

I would like to be able to check for this active session on the authority silently on application load, getting an id_token (while the access_token is retrieved/cached for API calls).

I understand that you require either a cached token for user context or a hint (login_hint or sid) for acquireTokenSilent. That's what I would like to see changed. In my pull request #541, I kept the existing behavior of as the default, while allowing my desired behavior with a configuration change.

Could you elaborate on the use case of multiple accounts having active sessions on the client? I couldn't find this in the wiki.

Fundamentally, MSAL.js should be a convenient interface for web developers to get tokens with the OAuth2 authorization flow and cache the tokens for the application. While additional features such as allowing multiple accounts with active sessions may be nice, it shouldn't be provided in such a way that it preempts the call/redirect to the authority without an opt-in or opt-out configuration option.

@navyasric How about different approach, rather than a configuration that changes part of the acquireToken processes:

A new loginSilent function. This will be similar to loginRedirect and loginPopup, except it will go through a hidden iframe with prompt=none to try to get an existing session from the authority. So the sole purpose of this new function is to support the behavior that I am trying to achieve.

It has a couple benefits over my existing pull request:

  1. It doesn't add an additional config / change existing behavior.
  2. It rounds out the login / acquireToken sets. loginX functions will be used for the initial get of an id token from the authority, while acquireTokenX will be follow-up functions used to get the token from cache, refresh tokens, or get access tokens.

I'll try to get the time to write up a new pull request. I'll leave the existing pull request open as well, leaving the decision of which to take on your team. I expect this new approach will be preferable, though.

Was this page helpful?
0 / 5 - 0 ratings