Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-authentication is required when reloading page using MSAL Angular 4.0.2 and Angular 19.1 #7533

Open
2 tasks
gsadrija opened this issue Jan 27, 2025 · 13 comments
Labels
bug-unconfirmed A reported bug that needs to be investigated and confirmed msal-angular Related to @azure/msal-angular package msal-browser Related to msal-browser package public-client Issues regarding PublicClientApplications question Customer is asking for a clarification, use case or information.

Comments

@gsadrija
Copy link

Core Library

MSAL.js (@azure/msal-browser)

Core Library Version

4.0.2

Wrapper Library

MSAL Angular (@azure/msal-angular)

Wrapper Library Version

4.0-2

Public or Confidential Client?

Public

Description

Hi there,

I did an upgrade to v4 of MSAL angular after upgrading to Angular 19.1.

After the upgrade, I now have to re-authenticate every time I reload the page, even though the cache location in my msalConfig is set to LocalStorage.
I know that there is a behavioural change as seen in:

https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/v3-migration.md

However, there should be no effect when just reloading the page.

Error Message

No response

MSAL Logs

No response

Network Trace (Preferrably Fiddler)

  • Sent
  • Pending

MSAL Configuration

msalConfiguration: {
    auth: {
      clientId: '...',
      authority:
        '...',
      redirectUri: 'http://localhost:4200',
      postLogoutRedirectUri: 'http://localhost:4200/logout',
      scopes: [
        'user.read',
        'openid',
        'profile',
        '...',
      ],
      unprotectedResources: ['https://www.microsoft.com/en-us/', './locale/'],
      protectedResourceMap: [
        ['https://graph.microsoft.com/v1.0/me', ['user.read']],
        [
          '...',
          ['...'],
        ],
        [
          'https://localhost:5001/api',
          ['...'],
        ],
      ],
    },
    cache: {
      cacheLocation: BrowserCacheLocation.LocalStorage,
    },
  },

Relevant Code Snippets

app.config.ts is implemented as follows

export function MSALInstanceFactory(): IPublicClientApplication {
  return new PublicClientApplication({
    auth: {
      clientId: environment.msalConfiguration.auth.clientId,
      authority: environment.msalConfiguration.auth.authority,
      redirectUri: environment.msalConfiguration.auth.redirectUri,
      postLogoutRedirectUri:
        environment.msalConfiguration.auth.postLogoutRedirectUri,
      navigateToLoginRequestUrl: true,
    },
    cache: {
      cacheLocation: environment.msalConfiguration.cache.cacheLocation,
    },
  });
}

export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {
  const protectedResourceMap = new Map<string, Array<string>>(
    environment.msalConfiguration.auth.protectedResourceMap as [
      string,
      string[],
    ][]
  );

  return {
    interactionType: InteractionType.Redirect,
    protectedResourceMap: protectedResourceMap,
  };
}

export function MSALGuardConfigFactory(): MsalGuardConfiguration {
  return {
    interactionType: InteractionType.Redirect,
    authRequest: {
      scopes: environment.msalConfiguration.auth.scopes,
    },
  };
}

export const appConfig: ApplicationConfig = {
  providers: [
    ...
    {
      provide: HTTP_INTERCEPTORS,
      useClass: MsalInterceptor,
      multi: true,
    },
    {
      provide: MSAL_INSTANCE,
      useFactory: MSALInstanceFactory,
    },
    {
      provide: MSAL_GUARD_CONFIG,
      useFactory: MSALGuardConfigFactory,
    },
    {
      provide: MSAL_INTERCEPTOR_CONFIG,
      useFactory: MSALInterceptorConfigFactory,
    },
    MsalService,
    MsalGuard,
    MsalBroadcastService,
  ],
};

Reproduction Steps

  1. Upgrade to MSAL for Angular to version 4.0.2
  2. Clear application storage
  3. Authenticate
  4. Use app
  5. Reload page

Expected Behavior

Reloading the page should not require the user the authenticate again when using LocalStorage as cacheLocation.

Identity Provider

Entra ID (formerly Azure AD) / MSA

Browsers Affected (Select all that apply)

Chrome

Regression

@azure/msal-angular: 3.1.0

@gsadrija gsadrija added bug-unconfirmed A reported bug that needs to be investigated and confirmed question Customer is asking for a clarification, use case or information. labels Jan 27, 2025
@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs: Attention 👋 Awaiting response from the MSAL.js team label Jan 27, 2025
@github-actions github-actions bot added msal-angular Related to @azure/msal-angular package msal-browser Related to msal-browser package public-client Issues regarding PublicClientApplications labels Jan 27, 2025
@vvolodin
Copy link

vvolodin commented Jan 27, 2025

I'm also having the same issue.
I also had to re-login after updating the library. It seems it would be a good idea to encrypt existing localStorage data when it's already there instead of logging out all users of my app?
Also, my Teams app is completely broken now after the update, I've tried relogging both in Teams app and in browser version of Teams - still the auth doesn't work. I will investigate further and possible create another issue.

@hectormmg
Copy link
Member

@gsadrija is this behavior happening every time you reload or just after the first time since upgrading the library? The cache is expected to be invalidated when the user first uses the app with the new version of MSAL.

@hectormmg
Copy link
Member

@gsadrija can you please also share Trace level logs as described in the issue template?

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs: Author Feedback Awaiting response from issue author and removed Needs: Attention 👋 Awaiting response from the MSAL.js team labels Jan 27, 2025
@gsadrija gsadrija closed this as not planned Won't fix, can't repro, duplicate, stale Jan 28, 2025
@microsoft-github-policy-service microsoft-github-policy-service bot removed the Needs: Author Feedback Awaiting response from issue author label Jan 28, 2025
@gsadrija
Copy link
Author

gsadrija commented Jan 28, 2025

Hi @hectormmg,

it happens every time I refresh the page. I attached the logs below but please take a look at me AuthService first:

import { Inject, inject, Injectable } from '@angular/core';
import {
  MSAL_GUARD_CONFIG,
  MsalBroadcastService,
  MsalGuardConfiguration,
  MsalService,
} from '@azure/msal-angular';
import { InteractionStatus, RedirectRequest } from '@azure/msal-browser';
import { IdToken } from '@core/auth/id-token.type';
import { Observable } from 'rxjs';
import { filter, map, tap } from 'rxjs/operators';

export interface IAuthService {
  login(): void;
  logout(): void;
}

@Injectable({ providedIn: 'root' })
export class AuthService implements IAuthService {
  @Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration;
  private msalService: MsalService = inject(MsalService);
  private msalBroadcastService: MsalBroadcastService =
    inject(MsalBroadcastService);

  logout(): void {
    this.msalService.logout();
  }

  login(): Observable<ProfileModel> {
    return this.msalBroadcastService.inProgress$.pipe(
      filter((status: InteractionStatus) => status === InteractionStatus.None),
      tap(() => this.checkAndSetActiveAccount()),
      map(() => {

        const idToken = this.msalService.instance.getActiveAccount()
          .idTokenClaims as IdToken;

        if (idToken) {
          ....
      })
    );
  }

  private checkAndSetActiveAccount() {
    const activeAccount = this.msalService.instance.getActiveAccount();

    if (
      !activeAccount &&
      this.msalService.instance.getAllAccounts().length > 0
    ) {
      const accounts = this.msalService.instance.getAllAccounts();
      this.msalService.instance.setActiveAccount(accounts[0]);
    } else if (this.msalService.instance.getAllAccounts().length == 0) {
      if (this.msalGuardConfig.authRequest) {
        this.msalService.loginRedirect({
          ...this.msalGuardConfig.authRequest,
        } as RedirectRequest);
      } else {
        this.msalService.loginRedirect();
      }
    }
  }
}

Looking at the console, there first was an error saying that msalGuardConfig is undefined (1st log).

Then I fixed that by adding a null check for msalGuardConfig.
After that, the console threw another error saying that this.msalService.instance.getActiveAccount() is undefined (2nd log)

After fixing this too with a null check, I still have to re-authenticate every time I refresh the page with the "Select Account" page.
No console errors were thrown after this.

I hope this helps.

Application logs
localhost-1738050499980.log
localhost-1738050312128.log

MSAL Log (refreshed once)
localhost-1738051767207.log

@gsadrija gsadrija reopened this Jan 28, 2025
@tnorling
Copy link
Collaborator

The issue is that your application is invoking the interceptor before MSAL initialization is complete thus resulting in an interaction_required error. You should make use of the inProgress observable to hold off on making any and all API calls until inProgress is None to ensure MSAL has successfully completed decryption and import of the entries in localStorage.

@gsadrija
Copy link
Author

Please refer to my AuthService above. I'm doing just that. I didn't change this code at all before upgrading and it worked before.

Or am I missing something?

@alexanderzeillinger
Copy link

For me MSAL 4.x completely broke authentication, went back to 3.x for it to work again.

@tnorling
Copy link
Collaborator

Please refer to my AuthService above. I'm doing just that. I didn't change this code at all before upgrading and it worked before.

Or am I missing something?

The AuthService does not show where your API calls, that will invoke the interceptor, are being made. The logs you shared show the interceptor is invoked before initialize, tracking down where this is happening will help you debug this. It may have worked in v3 because the cache did not need to be decrypted and thus this race didn't present an issue, but it was still incorrect usage regardless.

@alexanderzeillinger Please open a new issue with your specific blockers so we can help you get back up and running with v4.

@vvolodin
Copy link

I can confirm - in my case I was calling this.authService.instance.getAllAccounts() too early, which caused the library to not find anything in memory cache and clear the msal.account.keys.

@gsadrija
Copy link
Author

gsadrija commented Feb 3, 2025

Is there any working example of this showing how it should be implemented when using no login display? In our case, the user is redirected to authenticate if no account is logged in. I'm not able to get it to work even with the standalone sample provided here on GitHub.

@vkt-kmd
Copy link

vkt-kmd commented Feb 4, 2025

Is there any working example of this showing how it should be implemented when using no login display? In our case, the user is redirected to authenticate if no account is logged in. I'm not able to get it to work even with the standalone sample provided here on GitHub.

for me this helped:

const authorityHost = new URL(authority).hostname;
...
    auth: {
      clientId: clientId,
      authority: authority,
      redirectUri: '/',
      postLogoutRedirectUri: '/',
      knownAuthorities: [authorityHost],
      OIDCOptions: {
        defaultScopes: []
      }
    },

setting defaultScopes and knownAuthorities. My server didn't respond with offline_access claim

@gsadrija
Copy link
Author

gsadrija commented Feb 6, 2025

Apparently my issue is that I'm loading local language data into my app before the interaction is complete.

But then, why doesn't the

protectedResourceMap: [
...
        ['/public/i18n/*.json', null],
...
      ],

take care of that?

Also, even when using navigateToLoginRequestUrl I'm not being redirected to the URL I pasted into the browser. I always get redirected to the front page of the app after authenticating.

@kamilnajaigt
Copy link

The same problem here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug-unconfirmed A reported bug that needs to be investigated and confirmed msal-angular Related to @azure/msal-angular package msal-browser Related to msal-browser package public-client Issues regarding PublicClientApplications question Customer is asking for a clarification, use case or information.
Projects
None yet
Development

No branches or pull requests

7 participants