azureazure-ad-msalmsal-angular

Srop account selection prompt screen when sign out msal-angular


I am using the latest MSAL libs "@azure/msal-angular": "^4.0.12","@azure/msal-browser": "^4.12.0",. But the logout is still asking for account selection.

Is there a method to stop the account selection prompt on logout when using Azure MSAL libs?

Also, I would like to know the way to redirect users to the sign-up page directly and the password change page directly.

logout() {
const account = this.authService.instance.getActiveAccount();
if (account) {
  console.log("Logging out user:", account);
  console.log("Logging idToken:", account.idTokenClaims);
  this.authService.logoutRedirect({
    account: account,
    logoutHint: account.idTokenClaims?.login_hint,
  });
} else {
  this.authService.logout();
}
}

Solution

  • I successfully logged out without the account selection prompt using the Azure MSAL libraries in the Angular project below by setting loginHint = account.idTokenClaims?.login_hint.

    I configured login_hint as an optional claim for the ID token in the AD app's Token Configuration.

    enter image description here

    Below is the logout method :

    logout(): void {
      const account: AccountInfo | null = this.app.getActiveAccount();
    
      if (!account) {
        console.warn('No active account set. Cannot perform logout.');
        return;
      }
    
      const idToken = account.idToken; 
      const loginHint = account.idTokenClaims?.login_hint;
    
      if (!idToken || !loginHint) {
        console.warn('Missing id_token or login_hint. Proceeding with fallback logout.');
        this.app.logoutRedirect({
          account,
          postLogoutRedirectUri: 'http://localhost:4200',
        });
        return;
      }
    
      console.log('Logging out with login_hint:', loginHint);
      const tenantId = '<TenantID>'; 
      const logoutUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/logout` +
        `?id_token_hint=${encodeURIComponent(idToken)}` +
        `&logout_hint=${encodeURIComponent(loginHint)}` +
        `&post_logout_redirect_uri=${encodeURIComponent('http://localhost:4200')}`;
    
      window.location.href = logoutUrl;
    }
    

    auth.service.ts :

    import { Injectable } from '@angular/core';
    import {
      PublicClientApplication,
      AccountInfo,
      AuthenticationResult,
      AuthError,
    } from '@azure/msal-browser';
    import { msalConfig } from './auth-config';
    
    @Injectable({
      providedIn: 'root',
    })
    export class AuthService {
      private readonly app: PublicClientApplication;
      private isMsalInitialized: boolean = false;
    
      constructor() {
        this.app = new PublicClientApplication(msalConfig);
      }
    
      private async initializeMsal(): Promise<void> {
        try {
          await this.app.initialize();
          const redirectResponse = await this.app.handleRedirectPromise();
    
          if (redirectResponse && redirectResponse.account) {
            this.app.setActiveAccount(redirectResponse.account);
          } else {
            const accounts = this.app.getAllAccounts();
            if (accounts.length > 0) {
              this.app.setActiveAccount(accounts[0]);
            }
          }
    
          this.isMsalInitialized = true;
        } catch (error: unknown) {
          console.error('MSAL initialization error:', error);
        }
      }
    
      async login(): Promise<void> {
        if (!this.isMsalInitialized) {
          await this.initializeMsal();
        }
    
        try {
          const loginResponse: AuthenticationResult = await this.app.loginPopup({
            scopes: ['openid', 'profile', 'User.Read'],
            prompt: 'select_account',
          });
    
          if (loginResponse.account) {
            this.app.setActiveAccount(loginResponse.account);
          }
        } catch (error: unknown) {
          if (error instanceof AuthError) {
            console.error('Authentication error:', error.errorMessage);
          } else {
            console.error('Unexpected error during login:', error);
          }
        }
      }
    
    logout(): void {
      const account: AccountInfo | null = this.app.getActiveAccount();
    
      if (!account) {
        console.warn('No active account set. Cannot perform logout.');
        return;
      }
    
      const idToken = account.idToken; 
      const loginHint = account.idTokenClaims?.login_hint;
    
      if (!idToken || !loginHint) {
        console.warn('Missing id_token or login_hint. Proceeding with fallback logout.');
        this.app.logoutRedirect({
          account,
          postLogoutRedirectUri: 'http://localhost:4200',
        });
        return;
      }
    
      console.log('Logging out with login_hint:', loginHint);
      const tenantId = '<TenantID>'; 
      const logoutUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/logout` +
        `?id_token_hint=${encodeURIComponent(idToken)}` +
        `&logout_hint=${encodeURIComponent(loginHint)}` +
        `&post_logout_redirect_uri=${encodeURIComponent('http://localhost:4200')}`;
    
      window.location.href = logoutUrl;
    }
    }
    

    Here is the complete GitHub repository.

    I added the below URL at the AD app's redirect URI and Enabled the Allow the public client Flows as shown below,

    http://localhost:4200
    

    enter image description here

    I added the openid, profile and User.Read scopes and granted admit consent as shown below.

    enter image description here

    Output :

    I successfully logged in when redirected to the sign-up page and the password change page by clicking on Login button, as shown below.

    enter image description here

    enter image description here

    I successfully logged out without account selection prompt.

    enter image description here