Microsoft-authentication-library-for-js: Initial login failing with state mismatch error

Created on 7 Oct 2019  路  27Comments  路  Source: AzureAD/microsoft-authentication-library-for-js

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Other... Please describe:

Browser:

  • [x] Chrome version latest
  • [x] Firefox version latest
  • [x] IE version latest
  • [x] Edge version latest
  • [ ] Safari version XX

Library version


Library version: msal-angular v0.1.4

Current behavior


On the initial load, a user is redirected to the login page, and after a successful login they are redirected back to the app, which throws a Error State Mismatch.Expected State: null,Actual State: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX error, and then are redirected back to the login page. After logging in again, the app works as expected.

The MSAL module is initialized in an AuthModule with the following config:



export const protectedResourceMap: [string, string[]][] = [
  [environment.apiUri, [environment.azureB2C.apiScope]],
  ['https://graph.microsoft.com/v1.0/me', ['user.read']]];

const isInternetExplorerOrEdge = window.navigator.userAgent.indexOf('MSIE') > -1
                              || window.navigator.userAgent.indexOf('Trident/') > -1
                              || window.navigator.userAgent.indexOf('Edge') > -1;

@NgModule({
  ...
  imports: [
    ...
    MsalModule.forRoot({
      loadFrameTimeout: 10000,
      clientID: environment.azureB2C.clientId,
      protectedResourceMap: protectedResourceMap,
      authority: environment.azureB2C.signInAuthority,
      consentScopes: [environment.azureB2C.uiScope],
      validateAuthority: false,
      cacheLocation: 'sessionStorage',
      redirectUri: environment.azureB2C.redirectUri,
      navigateToLoginRequestUrl: false,
      storeAuthStateInCookie: isInternetExplorerOrEdge,
      logger: loggerCallback
    })
  ]
})
export class AuthModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: AuthModule,
      providers: [
        AuthService,
        AuthGuard,
        { provide: HTTP_INTERCEPTORS, useClass: MsalInterceptor, multi: true }
      ],
    };
  }
}

The signInAuthority here is an Azure B2C Sign in v2 user flow.

I'm using the provided MsalInterceptor and MsalGuard, and I have the MsalGuard on each route in the app. All other auth handling is in an Auth Service file:


@Injectable()
export class AuthService extends BaseService implements OnDestroy {
   constructor(protected http: HttpClient,
              protected router: Router,
              protected ngZone: NgZone,
              protected snackbar: ZomSnackbarService,
              private msalService: MsalService,
              private broadcastService: BroadcastService,
              protected logger: NGXLogger,
              private store: Store,
              private appInsightsService: AppInsightsService) {
    super(http, snackbar, logger, ngZone, router);

    this.subscription = this.broadcastService.subscribe('msal:loginFailure', (payload) => {
      this.logger.debug(`AuthService: msal:loginFailure`, payload);
      if (payload._errorDesc === 'User login is required') {
        this.redirectToLogin();
      }
      if (payload._errorDesc && payload.errorDesc.indexOf('AADB2C90118') === 0) {
        this.msalService.authority = environment.azureB2C.passwordResetAuthority;
        this.redirectToLogin();
      }
    });

    this.subscription.add(this.broadcastService.subscribe('msal:loginSuccess', (payload) => {
      this.logger.debug(`AuthService: msal:loginSuccess`, payload);
      this.store.dispatch(new LoginAction());
    }));

    this.subscription.add(this.broadcastService.subscribe('msal:acquireTokenSuccess', (payload) => 
    {
      this.logger.debug(`AuthService: msal:acquireTokenSuccess`, payload);
    }));

    this.subscription.add(this.broadcastService.subscribe('msal:acquireTokenFailure', (payload) => {
      this.logger.debug(`AuthService: msal:acquireTokenFailure`, payload);
      this.snackbar.info('Your session has expired. Please log in again.');
      this.redirectToLogin();
    }));

    this.subscription.add(this.broadcastService.subscribe('msal:stateMismatch', (payload) => {
      this.logger.error(`AuthService: msal:stateMismatch`, payload);
      this.redirectIfNoUser();
    }));
  }

  getAuthenticatedUserEmail(): string {
    const user = this.msalService.getUser();
    if (user && user.idToken && user.idToken['emails'] && user.idToken['emails'].length) {
      return user.idToken['emails'][0];
    }
    this.redirectToLogin();
    return null;
  }

  redirectIfNoUser() {
    if (!this.msalService.getUser() && !this.msalService.loginInProgress()) {
      this.msalService.loginRedirect([environment.azureB2C.uiScope]);
    }
  }

  redirectToLogin() {
    if (!this.msalService.loginInProgress()) {
      this.msalService.loginRedirect([environment.azureB2C.uiScope]);
    }
  }
  ...
}

Any help would be appreciated!

Expected behavior


Login credentials should only have to be entered once.

Minimal reproduction of the problem with instructions

  1. Clear browser cache or open a private session
  2. Navigate to the app
  3. Enter credentials after redirect to login page
  4. Observe that you are redirected to the app and immediately returned to the login page with the State Mismatch error in the console.
Issue Triage msal-angular

Most helpful comment

@jarodsmk Can you please try [email protected] and let us know if you still have that error?

Session state is not persisted resulting in a mismatch.

@ryandegruyter Can you clarify what you mean by that? Not persisting in local storage? And which version of Edge? And are they using InPrivate by chance?

All 27 comments

Any update for this?

Hi @rvdhooft, this issue was something that we pushed a fix for in MSAL core, but has not been updated in angular. We are currently working on updating the angular wrapper to use the latest version of the core library, which should then fix this issue in the Angular wrapper. @jasonnutter will update when he has more info.

Thanks for the update. Hoping that release comes soon!

Is there any workaround for this issue that could be implemented meanwhile we wait for the updated wrapper?

@pkanher617 is there a specific branch of the core lib that contains the fix for state mismatch?

Fixes for this bug have been merged into dev and are available on 1.2.0-beta.5. Please try that version and let us know if there are still issues. Closing (unless we here there are more bugs related to this).

Sorry, I will clarify that those fixes were merged for msal, but are not yet in @azure/msal-angular. Will keep this open until Angular is updated with latest version of MSAL for tracking.

MSAL Angular has now been updated with the latest version of MSAL, upgrade guide available here: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev-angular-1.0-protectedresources/lib/msal-angular/docs/0.x-1.x-upgrade-guide.md

Please let me know if this is still an issue after upgrading, thanks!

Hey @jasonnutter!

I got this exact error with:

  • msal: 1.2.2-beta.0
  • msal-angular: 1.0.0-beta.3

(Took these from the Angular 9 example directory, although I am running Angular 8)

We are experiencing this issue with a select few users.
Session state is not persisted resulting in a mismatch.

"@azure/msal-angular": "0.1.4",

Microsoft Edge

Any idea's what the cause might be?

@jarodsmk Can you please try [email protected] and let us know if you still have that error?

Session state is not persisted resulting in a mismatch.

@ryandegruyter Can you clarify what you mean by that? Not persisting in local storage? And which version of Edge? And are they using InPrivate by chance?

@jasonnutter Sure thing 馃憣 Will bump it and see what happens in the upcoming days!

How I've been handling it for now is catching the exception and forcing the user to login again, resulting in a double login at times but atleast didn't leave them hanging

Update package to [email protected] fixed the issue, thanks.

@jasonnutter we updated to 1.0.0beta4, seems to resolve the issue.

Great, thanks for the updates!

Seems to be good for me too, I upgraded to [email protected] and [email protected] from the suggestions above 馃槑 I'll test it out on our different environments in the upcoming weeks and see if there's any changes.

I noticed that when bumping to the newer 1.0.0-beta.5 the imports for BroadcastService and MsalService couldn't be resolved anymore, I created a seperate ticket to track it through.

https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/1502

Thanks @jasonnutter !

After upgrading my React app to [email protected] I'm still experiencing the error.

Firefox Private tab,

State Mismatch.Expected State: null,Actual State: eyJpZCI6IlJFREFDVEVEX0lEIiwidHMiOjE1ODc1NTgzMTMsIm1ldGhvZCI6InJlZGlyZWN0SW50ZXJhY3Rpb24ifQ==

Decoded:

"{\"id\":\"REDACTED_ID\",\"ts\":1587558313,\"method\":\"redirectInteraction\"}"

I've also tried msal-core from dev branch, still no luck.

UPD: I've tried to replicate my issue with react-sample-app demo project but it works just as expected. I'll post more if I'll pinpoint the reason why it fails in my app.

Here you go, you can easily reproduce this bug by changing two lines in the react-sample-app project, setting useRedirectFlow to true and changing cacheLocation to localStorage.

image

diff --git a/samples/react-sample-app/src/AuthProvider.js b/samples/react-sample-app/src/AuthProvider.js
index 8ebeed33..c54ed009 100644
--- a/samples/react-sample-app/src/AuthProvider.js
+++ b/samples/react-sample-app/src/AuthProvider.js
@@ -10,8 +10,8 @@ import {
 } from "./auth-utils";

 // If you support IE, our recommendation is that you sign-in using Redirect APIs
-const useRedirectFlow = isIE();
-// const useRedirectFlow = true;
+// const useRedirectFlow = isIE();
+ const useRedirectFlow = true;

 export default C =>
     class AuthProvider extends Component {
diff --git a/samples/react-sample-app/src/auth-utils.js b/samples/react-sample-app/src/auth-utils.js
index f0aa495f..866e13b5 100644
--- a/samples/react-sample-app/src/auth-utils.js
+++ b/samples/react-sample-app/src/auth-utils.js
@@ -67,7 +67,7 @@ export const msalApp = new UserAgentApplication({
         navigateToLoginRequestUrl: false
     },
     cache: {
-        cacheLocation: "sessionStorage",
+        cacheLocation: "localStorage",
         storeAuthStateInCookie: isIE()
     },
     system: {

@Lomand I was only able to reproduce that behavior in Firefox Private Browsing. I believe this may be because Firefox will clear local storage in this scenario. Setting storeAuthStateInCookie to true for Firefox Private Browsing should fix the behavior you are seeing.

I am having the same error in firefox, new edge, I already set
cacheLocation: "localStorage"
storeAuthStateInCookie: true

"msal": "^1.2.2"

@zhaozhongming Please try [email protected] and let me know if it still an issue.

@jasonnutter we've got this issue with [email protected]. Strangely enough, only when the app is deployed. Works with localhost though.

Sorry, bad timing... The CI picked up 1.2.2 and locally it was already 1.3.0. It's fixed in 1.3.0 for us.

@MaximBalaganskiy Great, thanks for the update!

We expect [email protected] to fix this issue, please let us know if not, thanks!

I'm experiencing this exact issue with the 2.0.0-beta.2 version of @azure/msal-browser. Any solutions to this?

@thj-dk Please open a new issue, thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lecaillon picture lecaillon  路  3Comments

ed-ilyin picture ed-ilyin  路  4Comments

Calamari picture Calamari  路  3Comments

spottedmahn picture spottedmahn  路  3Comments

ArneMancofi picture ArneMancofi  路  3Comments