DEV Community

Andrew Elans
Andrew Elans

Posted on

Azure Static Web Apps: Simple Logout Without login_hint

Azure Static Web Apps: Simple Logout Without login_hint

In my previous posts I covered how to pass login_hint to EasyAuth for a smoother sign-in experience. But there's a simpler approach to the logout/login flow that avoids login_hint entirely and is more user-friendly.

The problem with default EasyAuth logout

When you redirect a user to /.auth/logout, EasyAuth signs them out on the Azure AD server. This kills not just their SWA session but every active SSO session tied to that account - Azure Portal, Outlook, Teams, any other app using the same identity.

For an internal app where users are signed into a dozen Microsoft services, that's a bad experience.

A better approach: sign out of SWA only

Instead of a full server-side logout, we can clear the EasyAuth session on the SWA while keeping the Azure AD session alive. The user gets signed out of our app but stays signed into everything else.

The trick is to call the logout endpoints with fetch instead of a redirect:

  1. fetch to /.auth/logout with mode: 'no-cors' (critical - without this the browser blocks the request)
  2. Then fetch to /.auth/logout/complete to clear the EasyAuth cookies

After both calls complete, redirect to / which triggers the sign-in flow where the user sees an account picker.

Angular

async logOut(): Promise<void> {
  if (window.location.host.endsWith('azurestaticapps.net')) {
    const noCors: RequestInit = { mode: 'no-cors' };
    const redirectUri = '?post_logout_redirect_uri=/.auth/me';
    await fetch('/.auth/logout' + redirectUri, noCors).then(() =>
      fetch('/.auth/logout/complete' + redirectUri, noCors),
    );
  }
  window.location.href = '/'; // triggers sign in
}
Enter fullscreen mode Exit fullscreen mode

Vanilla JS

document.getElementById('signout-btn').addEventListener('click', async function (e) {
  // Replace page content with logout message
  document.body.replaceChildren(
    document.createRange().createContextualFragment(`
      <div style="height:calc(100vh - 16px);font-family:'Segoe UI Light','Helvetica Neue',Helvetica,Arial,sans-serif;display:flex;align-items:center;justify-content:center;">
        <div style="text-align:center;">
          <h2>Logout in progress</h2>
          <p>Please do not close the page</p>
        </div>
      </div>`),
  );

  if (location.hostname.includes('azurestaticapps.net')) {
    const noCors = { mode: 'no-cors' };
    await fetch('/.auth/logout?post_logout_redirect_uri=/_layout/tokenhtml/', noCors)
      .then(() =>
        fetch('/.auth/logout/complete?post_logout_redirect_uri=/_layout/tokenhtml/', noCors),
      );
  }

  // If using MSAL browser, sign out through MSAL as well:
  const msal = this.msalPcaObj;
  const account = msal.getActiveAccount();
  await msal.logoutRedirect({
    account,
    postLogoutRedirectUri: location.href,
  });

  // If not using MSAL, redirect to trigger sign in:
  // window.location.href = '/';
});
Enter fullscreen mode Exit fullscreen mode

Optional: full logout with a toggle

If some users do need a full server-side logout (closing all SSO sessions), you can add a checkbox that switches between the fetch-based approach and a standard redirect to /.auth/logout. This gives users control over whether they want a quick re-login or a complete sign-out.

Top comments (0)