We are using react-aad-msal to authenticate users with Azure AD via AD B2C. B2C is configured with custom policies, but nothing specific to logout. We are passing authority, domain_hint and login_hint in authenticationparameters which change dynamically based on what user enters in the application email prompt before they are redirected to B2C login.
The initial login works fine, however after calling authProvider.logout() if different use tries to login and his external idp doesn't change, but login_hint does it still somehow holds on to the token of the previous user. I see it going to post logout redirect uri. Local storage is empty, authenticationState is Unauthenticated, but then out of the blue the token of the previous user appears in local storage. Setting prompt to 'login' doesn't help. Anyone had similar issues? Where is it getting the token from? Strangely enough it works correctly in FireFox, but not in Chrome. Also, after changing the user it sometimes randomly goes into endless loop with a message that login is already in process in the browser console.
Related
I am using MSALjs to logout a user on my application. When the msalService.logoutRedirect() is triggered, the page redirects and is logged out. However, my application does not have an "un-guarded" route, thus the redirect after logout (postLogoutRedirectUri) is set to return to the application's last active page. And when it returns to the application, the MSAL guard automatically finds a valid MS session and logs back in again automatically (after redirects).
If I change the postLogoutRedirectUri to https://login.microsoftonline.com/common/oauth2/logout, the logout does work and I am signed out correctly. However, I would like to immediately be prompted to sign back in, which is why I intend on returning to the application so the MsalGuard can prompt sign in.
Per a recent GitHub issue , one of the MSAL contributors said the following:
This is a nuance of how B2C works. By default B2C might not log you out of your federated identity provider when you call the logout endpoint, this is explained in more detail here. I unfortunately don't know enough about B2C configuration to give you a definitive answer but you may need to create a custom policy which redirects to the AAD logout endpoint you mentioned: 'https://login.microsoftonline.com/common/oauth2/logout' as this endpoint is the one that ultimately closes your session with AAD. You can also have B2C pass through your postLogoutRedirectUri to this endpoint so that AAD redirects you back to your application after the logout instead of ending on the "Close this window" screen, if desired.
How can I set this up so the logout is triggered correctly and all sessions are signed out?
Furthermore, if I manually change the metadata of the openid-config to have the "end_session_endpoint" equal to the microsoftonline logout link from above, the behavior seems to be more in line with what I would expect.
You could send the apps post logout redirect uri to the federated IdPs logout url. You can set the postLogoutRedirectURI in MSAL config object.
And at the federated IdP, set the logout url to the application.
Approach only works if you are using 1 federated IdP, and is the only IdP available.
function signOut() {
const logoutRequest = {
postLogoutRedirectUri: "https://login.microsoftonline.com/common/oauth2/v2.0/logout?
post_logout_redirect_uri=https://myapp.com"
msalConfig.auth.redirectUri
};
myMSALObj.logoutPopup(logoutRequest);
}
Otherwise, make an unguarded page in your app that redirects to the guarded page, but sets the MSAL prompt parameter to “login”. At least then the B2C login page will appear, and allow the user to select how they want to login. They may still get SSO if they select a federated IdP.
We have a Custom Policy that is based on the SocialAndLocalAccounts starter pack.
We have been adding support from Home Realm Discovery based on this sample HomeRealmDiscovery-Modern to redirect users using third-party-providers to their correct sign-in page (IdP)
We have also added support for Domain Hints to entirely skip our sign-in page for users that sign-in via a third-party identity provider.
The policy makes use of the new released Self-Served Password Reset as per official docs.
What's the issue?
When the user goes through the "Self-Served Password Reset", the B2C session is left in a corrupted state. If the user is redirected back to B2C, the session is not picked up.
How can we say that? What is the use case?
Steps to reproduce:
1: User goes to the application which redirects the user to the B2C Sign-In page.
2: User enters local account email (Gmail) and on the next Screen clicks on "Forgot your password" link which is implemented using the Self-Served Password Reset.
3: User goes correctly through the password reset flow, and ultimately enters the "MFA" factor (SMS code).
4: User correctly gets redirected to the Application with an ID token, successful login.
6: User clicks a link to a new/different application using the same custom policy.
7: The new application redirects the user to B2C (same custom policy)
Expected Result: The user should have a valid B2C Session and should not be prompted to sign-in again, but instead redirected to the callback of the new application with a valid id-token.
Actual Result: The user is sent back to the new application with an error message in the callback URL, and because of the error redirected back to B2C to re-login.
Error Message:
AADB2C90051: No suitable claims providers were found.
Correlation ID: c014004a-d2da-4000-83e5-6d648f9acccc
Timestamp: 2021-06-16 07:17:16Z
IMPORTANT: If the user goes through the normal sign-in flow (no password reset), everything works correctly. The user can switch between different applications and B2C picks-up the session correctly, without throwing errors or prompting a new sign-in. SSO among the different apps works as intended.
Here is the full TrustFrameworkExtention file which contains all the logic and extends from the Base file of the starter pack:
TrustFrameworkExtention.xml
Try this:
In CreateidentityProvidersCollectionLogic change SM-Noop to SM-DOMAIN.
In SM-DOMAIN add:
<PersistedClaim ClaimTypeReferenceId="identityProviders" />
i have a relying party application(web application) registered in AAD B2C and i am inviting the users to my groups in my tenant, for that, i sent the invitation url to them and user signup/sign in and enter in my application.
this process works perfectly if i test this flow in incognito window, but it saves my (inviter) credentials and on even clicking the invitation link this link dont sign up with the email mentioned in invitation rather it signs in with the already signed in(inviter) account.
any help would be much appreciated.
This is the normal behavior. When a user successfully authenticates with a local or social account, Azure AD B2C stores a cookie-based session on the user's browser.
It is not expected that the invitee will be using the same browser as the inviter.
You do however have some options in configuring session behavior: https://learn.microsoft.com/en-us/azure/active-directory-b2c/session-behavior?pivots=b2c-user-flow#configure-azure-ad-b2c-session-behavior
For instance you can disable KMSI so that a persistent cookie will not be saved in the browser. That means users have to login every time the browser is restarted. But it resolves your problem. In any case, you should work under the assumption that invitees will open the invite link on their own machines with their own browsers.
I have created azure ad b2c custom sign-in policy with KMSI(keep me sign in) option, and using it in blazor server application,
But automatic sign in not working after browser close, Need to click 'Login' button.
After click login button no need to enter credential again, if at the time of previous sign-in KMSI check box checked.
But I want to sign-in automatically if at the time of sign in KMSI check box checked.
Could you check the authorization request the app sends to Azure AD B2C, whether it contains the prompt=login query string parameter? If yes, please make sure to remove this param.
This is expected, your app cookie is not persisted, so the app has no idea you’re still logged in at B2C. Therefore you have to click login in the app and then you get SSO through AAD B2C.
You could maintain a cookie set by the app to automatically send the user via the login endpoint if they had signed in previously with KMSI. You can use a claims resolver to send the KMSI claim into the token so your app can understand the user logged in with KMSI.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/claim-resolver-overview
I tested KMSI functionality on my side, and I can repro your symptom. My test is based on this demo: https://github.com/Azure-Samples/active-directory-b2c-dotnet-webapp-and-webapi
This is my test process below:
Registering a local account.
Login by this account, and enabled KMSI
I logged in successfully:
Close the browser, reopen it and got to my app index, my index page is allowed to be visited by anonymous, so it not knows who am I: I think this is the issue that you are concerned about:
But when I click “Claims” tag which users are needed to be authenticated, it redirected to my b2c domain :
As I enabled KMSI, so there is a cookie under my b2c domain:
As this cookie exists, B2C will provide me with the resource I requested for: b2c side sends a request to redirect URL with id token and code :
Finally, it redirected to “Claim” page and this app knows who am I :
In a word, there are two kinds of sessions here: a session between user and B2C and a session between the user and your application.
Once you close your browser, by default, you will lose the cookie that user on your application, so users access to some page with no auth needed of your app after reopening the browser, there will be no cookie, your application not know the user. But on the B2C side, this cookie will be persisted there due to KMSI. Only users request some functionality needs to be authenticated on your app, users will be redirected to the B2C domain and B2C will send users’ information to your app will make KMSI work.
In my opinion, maybe extending the lifetime of your application cookie will be a solution here. At the same time, you also need to expand session timeout to make sure that your application could recognize that long lifetime cookie. But as we know, it will be a high consumption for server RAM if it holds lots of sessions.
I’ve implemented the password change custom policy according to the documentation and use msal.js on the frontend to start the password change flow. This works accept that the user needs to sign in again although the user is already signed in to the application. So it asks the user credentials every time. Why isn’t B2C detecting that the user has already signed in and how can I solve this?
Thanks!
MSAL.js is setting the prompt parameter, therefore, forcing B2C to ignore the cookie, therefore, forcing the sign-in.
const urlNavigate = authenticationRequest.createNavigateUrl(scopes) + "&prompt=select_account" + "&response_mode=fragment";
Source
You can verify this by taking the URL MSAL.js redirects the user to and removing the prompt query parameter.
Related GitHub Issue: Allow Controlling the prompt parameter. We need to convince the MSAL library owners we need control over this parameter.
If you are trying to test through the B2C Custom Policies "Run now" endpoint, just remove the &prompt=login query parameter from the link. If you are already logged in it will skip the login, if you are not, it will still prompt for your credentials.
Credit to Jas Suri: Azure B2C EditProfile custom policy without Signing In first