microsoft-authentication-library-for-js: Front-channel logout doesn't work as expected

Core Library

MSAL.js (@azure/msal-browser)

Core Library Version

3.3.0

Wrapper Library

MSAL React (@azure/msal-react)

Wrapper Library Version

2.0.5

Public or Confidential Client?

Public

Description

As stated per docs we should be able to logout a user from all authenticated sessions of a specific app(s) with Azure AD. However, after following all required steps, only the app that initiated the logout request, logged out correctly.

When inspecting the chrome devtools I do see the GET request to the other apps that need to be logged out. As stated per docs this is being done by loading an invisible iframe. So that works as expected as far as I am concerned. The console.log in my Logout.jsx is also being called correctly. However, no sign out appeared.

image

Here are the settings for my app registration in Azure AD

image

Error Message

No error shown. But authenticated session in other apps remains in place. Which shouldn’t happen. However, when I load an iframe myself from app-1 itself for example it does remove the session. When the iframe is loaded from app-2 the session isn’t removed.

App 1 is hosted on https://dbm.localhost:3001 App 2 is hosted on https://localhost:3000

Msal Logs

No response

MSAL Configuration

export const msalConfig = {
  auth: {
    clientId: "hidden for security purposes", // This is the ONLY mandatory field that you need to supply.
    redirectUri: "/", // You must register this URI on Azure Portal/App Registration. Defaults to window.location.origin
    postLogoutRedirectUri: "/", // Indicates the page to navigate after logout.
    clientCapabilities: ["CP1"], // this lets the resource owner know that this client is capable of handling claims challenge.
  },
  cache: {
    cacheLocation: "localStorage", // sessionStorage has the same result
    storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
  },
  system: {
    allowRedirectInIframe: true,
    loggerOptions: {
      loggerCallback: (level, message, containsPii) => {
        if (containsPii) {
          return;
        }
        switch (level) {
          case LogLevel.Error:
            console.error(message);
            return;
          case LogLevel.Info:
            console.info(message);
            return;
          case LogLevel.Verbose:
            console.debug(message);
            return;
          case LogLevel.Warning:
            console.warn(message);
            return;
        }
      },
    },
  },
};

Relevant Code Snippets

Here is the code of the Logout.jsx page that is included in the react-router as a route.

 React, { useEffect } from "react";
import { useMsal } from "@azure/msal-react";
import { BrowserUtils } from "@azure/msal-browser";

export function Logout() {
  const { instance } = useMsal();

  useEffect(() => {
    instance.logoutRedirect({
      account: instance.getActiveAccount(),
      onRedirectNavigate: () => !BrowserUtils.isInIframe(),
    });
  }, [instance]);

  return <div>Logout</div>;
}

Reproduction Steps

  1. Login to app on https://app-1.localhost:3000
  2. Login to app on https://app-2.localhost:3001
  3. Logout from app on https://app-1.localhost:3000
  4. A GET request should happen to logout https://app-2.localhost:3001

Expected Behavior

It should call the https://app-2.localhost:3001/logout (called app-1 and app-2 for demo purposes) url and actually removing the session/localstorage authenticated session of the user.

This does work if you call the url manually. (https://localhost:3001/logout)

The code is being called in the iframe by Azure AD front-channel feature. However the localstorage/session storage isn’t cleared on the actual app that needs to be logged out as well. This implies to me that the browser is blocking this because of the same origin policy. I might be wrong but that’s just a thought that came up to my mind.

Identity Provider

Azure AD / MSA

Browsers Affected (Select all that apply)

Chrome

Regression

No response

Source

Internal (Microsoft)

About this issue

  • Original URL
  • State: closed
  • Created 8 months ago
  • Reactions: 1
  • Comments: 16

Most upvoted comments

@kevinvugts I am facing same issue. Did you happen to find any solution?

Nope, Microsoft support takes ages to get back to my query. … Still no resolution. They even have said they don’t support such a feature.

So in terms of internal knowledge, it’s. a bit dissapointed…

Just checked, for ‘sessionStorage’ disabling #third-party-storage-partitioning doesn’t seem to work at all

That’s correct. I also can confirm this doesn’t work for session storage. @tnorling could you elaborate more on this?

Is this front-channel logout feature event meant for sessionStorage end of the day?

Just checked, for ‘sessionStorage’ disabling #third-party-storage-partitioning doesn’t seem to work at all

I am experiencing the same issue. app2’s front-channel logout URL is called but its local storage is not cleared. It seems to depend on the browser’s handling of cookies. My results after testing in different browsers:

  • Chrome 119: Local storage is not cleared regardless of allowing third-party cookies or not.
  • Firefox 118: Local storage is cleared only if browser privacy is changed from Standard to Custom and changing blocked cookies from Cross-site tracking cookies, and isolate other cross-site cookies to Cross-site tracking cookies.
  • Safari 17: Local storage is cleared if Prevent cross-site tracking is disabled.

If I am correct front-channel logout doesn’t seem to be useful anymore since browsers have and are becoming more strict.

I wonder if the iframe is being closed before your page has fully rendered and triggered the effect. I’d recommend trying a simple HTML page with no React or anything other than instantiating PublicClientApplication and invoking logoutRedirect.