microsoft-authentication-library-for-js: Initial login failing with state mismatch error
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:
- Chrome version latest
- Firefox version latest
- IE version latest
- 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
- Clear browser cache or open a private session
- Navigate to the app
- Enter credentials after redirect to login page
- Observe that you are redirected to the app and immediately returned to the login page with the State Mismatch error in the console.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 1
- Comments: 27 (11 by maintainers)
@jarodsmk Can you please try
msal@1.3.0-beta.1
and let us know if you still have that error?@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?
Seems to be good for me too, I upgraded to
msal@1.3.0-beta.1
andmsal-angular@1.0.0-beta.4
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 forBroadcastService
andMsalService
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 !
@jasonnutter we updated to 1.0.0beta4, seems to resolve the issue.
Update package to msal@1.3.0-beta.1 fixed the issue, thanks.