microsoft-authentication-library-for-js: User cannot log out

I’m submitting a…

  • Bug report

Browser:

  • Chrome version XX
  • Edge version 76.0.167.1

Library version

Library version: 1.0.1

Current behavior

  1. Use clicks logout. App uses MSAL logout() to redirect to:
https://login.microsoftonline.com/common/oauth2/v2.0/logout
?post_logout_redirect_uri=http://localhost:3000

Sometimes, AD stops at this page and asks the user to select which account they should log out of. Other times, it blows right past it and automatically redirects to the next page.

  1. Page redirects (on AAD/B2C side) to:
https://login.microsoftonline.com/common/oauth2/v2.0/logoutsession

Notice the post_logout_redirect_uri WAS in the first page, but is now gone. MSAL seems to be doing its part, but something gets lost during this redirect on the identity provider.

image

The page stays there with the message “You signed out of your account. It’s a good idea to close all browser windows”. The user has no way to return to the app.

  1. Manually browse back to the app.

  2. User does not appear to be logged in. A request is sent to:

https://login.microsoftonline.com/common/oauth2/v2.0/authorize
?response_type=id_token%20token 
&scope=profile openid offline_access user_impersonation
&client_id=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX
&redirect_uri=http%3A%2F%2Flocalhost%3A3000
&state=d2820c44-3e2c-499b-8ebe-7e338c148413
&nonce=0e6504d0-0a8a-4c71-a06a-7143fee1cc58
&client_info=1&x-client-SKU=MSAL.JS
&x-client-Ver=1.0.0
&client-request-id=26def4cb-74bf-4211-8f39-15a4f13ca05f
&prompt=none

Which returns with the following from the hidden iFrame injected by MSAL: “Loading frame has timed out after: 6 seconds for scope profile openid offline_acces”

And the following from a manual call to MSAL acquireTokenSilent(): “Token renewal operation failed due to timeout.”

This is okay. I’d expect these to fail.

  1. User clicks login button. App calls MSAL loginRedirect(). Page redirects to:
https://login.microsoftonline.com/te/mytenant.onmicrosoft.com/b2c_1_signup-signin/oauth2/v2.0/authorize
?response_type=token    
&scope=profile openid offline_access user_impersonation
&client_id=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX
&redirect_uri=http%3A%2F%2Flocalhost%3A3000
&state=8abd9bb6-605e-4ab3-8f61-0a1ff2e464a7
&nonce=35d90353-9a84-4099-90e2-2ce49a272994
&client_info=1&x-client-SKU=MSAL.JS
&x-client-Ver=1.0.0
&login_req=ba5c17b8-ad9a-4570-89b7-7edc88e11eb2-b2c_1_signup-signin
&domain_req=b39b039b-fe33-4653-8e63-7a7f59b3c864
&domain_hint=organizations
&client-request-id=cbe3310c-3ef5-460f-aae9-fa47973b5461
&prompt=none

User is NOT promped for credentials. They are authenticated and automatically redirected back to the app.

Expected behavior

  1. I expect the user to not have to select what account they want to log out of when they are only logged in with 1 account.
  2. I’d expect them to get redirected back to the app.
  3. I’d expect them to have to provide username and password after they appear to have been logged out in already.

Other

  • I am working with Azure support on this as well, but so far they have seen nothing incorrectly configured on the B2C or Azure end. I decided to post it here in case there is something library related that will help.
  • If the user closes and reopens the browser, they are fully logged out.
  • Before clicking Login and skipping the credentials, there are no cookies or any info stored locally. I have no idea how it is bypassing the credential prompt.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 59 (23 by maintainers)

Most upvoted comments

For anyone who is stumped on this and finds this thread, I found a solution.

Similar to how you have to explicitly set your clientApplication authority before you redirect to login

this.clientApplication.authority = https://${msalTenant}.b2clogin.com/${msalTenant}.onmicrosoft.com/${msalSignInPolicy}; this.clientApplication.loginRedirect();

You have to explicitly set this before triggering logout, otherwise you are directed to the common MS online logout page.

this.clientApplication.authority = https://${msalTenant}.b2clogin.com/${msalTenant}.onmicrosoft.com/${msalSignInPolicy}; this.clientApplication.logout();

I figured this out by examining the network call to openid-configuration when the login process is triggered. This comes back with an object that has the property end_session_endpoint which matches the URL pattern above.

In the source code for logout it looks for an end session endpoint and if it doesnt exist, redirects you to common login online for logout. Where your redirect URI is not configured and it breaks.

tldr; Set the client application authority before logging out. Set the logout redirect uri as a reply URL in your azure B2C application configuration.

I published the recorded steps so you can see:

https://youtu.be/XIiQZL7pERQ

I recently updated to 1.2.1 and this is still an issue.
Issue summary: msalApp.logout() appears to log the user out, but after “logging out” the user can click “login” and be logged in again without being required to enter their username and password.

This is a serious security issue for user’s who login to our application on a public computer, then logout thinking that they have prevented someone from accessing their account.

potential solution: re-setting the authority I tried re-setting the authority like @m-sala-digital88 and @BoshJeckerleg suggested, but clicking the login button still logs the user in without prompting for a username and password.

workarounds

  1. Redirect the user to: https://login.microsoftonline.com/common/oauth2/logout
  2. Redirect the user to: https://login.microsoftonline.com/<tenantid>/oauth2/logout?client_id=<clientId>&post_logout_redirect_uri=<encodedurl>
  3. Redirect the user to: https://login.microsoftonline.com/common/oauth2/logout?post_logout_redirect_uri=xxxxxxxxx

The issue with 2 and 3 in my situation, is that we have two web applications sharing this Azure Active Directory and the Azure portal only accepts a single logout url.

The other issue with with this workaround is that in my case we also allow users to login with username and password. For users who opt to login with username and password rather than their microsoft live account, redirecting them to a logout URL does not log them out.

@jasonnutter and @sameerag I see that you closed this issue because we do not support silent sign out in order to prevent DDOS attaches. . Obviously, this thread morphed into something different than the original issue. Would it be better if I open a new issue? In my summary I did not include some of the issues the original post included. I expect the user to not have to select what account they want to log out of when they are only logged in with 1 account. I'd expect them to get redirected back to the app.. and because of this I hope my summary clarifies and prioritizes the main issue.

Found a half decent workaround: Redirect the user to: https://login.microsoftonline.com/common/oauth2/logout

Additionally, you can setup a logout redirect back to your app: https://stackoverflow.com/questions/45935305/azure-ad-logout-url-not-redirecting

@DarylThayil that is correct.

  1. Cache initially empty.
  2. User logs in. Redirected to AAD username/password form. Redirected back to app.
  3. Values added to cache.
  4. User logs out. Redirected to AAD signout page. Never redirected back.
  5. Cache is empty.
  6. Click login button again. Redirected to AAD. Username/password form flashes. Redirects back to app without credentials.
  7. Values are in the cache.

@verbedr Here is my configuration:

FLOW_SIGN_IN_SIGN_UP = "B2C_1_signup-signin";
authority: string = "https://mytenant.b2clogin.com/mytenant.onmicrosoft.com";

let userAgentConfig: Configuration = {
    auth: {
        clientId: environmentVariables.appsettings.auth.clientId,
        redirectUri: 'https://localhost:3000',
        postLogoutRedirectUri: 'https://localhost:3000', 
        validateAuthority: false
    },
    cache: {
        cacheLocation: 'localStorage'
    },
    system: {
        logger: this.logger
    }
}

this.userAgentApp = new UserAgentApplication(userAgentConfig);

login() {
    let authParams: AuthenticationParameters = {
        scopes: [
            "openid", 
            "profile"
        ]
    };
    this.userAgentApp.authority = `${this.authority}/${this.FLOW_SIGN_IN_SIGN_UP}`;
    this.userAgentApp.loginRedirect(authParams);
}

logout() {
    this.userAgentApp.logout();
}

I ended up not using msal because of this particular bug (this thread). So I rolled my own and followed the specs, including checking the signature against jwks key on browsers that support windows.crypto.subtle (something that I do not think msal.js is doing?). I am using the redirect flow, so no hidden iframes (this is what I guess would be used for single sign out if its not a call from the server as I originally thought). In my particular case I can’t use the logout URL field since I have no iframe. But by just logging out using https://login.microsoftonline.com/common/oauth2/logout?post_logout_redirect_uri=http://localhost:4200/logout and clearing my session and local storage all works fine, including the redirect after a logout.

Btw, I just tried to insert http://localhost in my logout url and it worked just fine. I am using the v2 API.

Actually “localhost” is a very common and important scenario for developers. One needs the OAuth flows to support apps running locally, e.g. http://localhost:3000 when working with ReactJS. “Sign in” needs to allow users coming from localhost and needs to redirect to localhost, “logout” needs to redirect to localhost after signing out, etc.

I am running into the same issue. What I found to be particularly painful for users is if they choose the wrong account to login with. They choose an account that has not signed up yet. They receive an error informing them as much, click the Login button intending to try and login with another account, but they immediately receive the error again. No opportunity to choose a different account. I tried adding the logout() function in the error catch, but this does not help. I hope this is resolved soon.

FYI Clearing the cookies stored under https://login.microsoftonline.com allows the user to select a different account the next time they click the login button.