Please follow the issue template below. Failure to do so will result in a delay in answering your question.
"@azure/msal-browser": "^2.0.0-beta.3"This error happened during I test the Auth code flow with the latest msal2 beta library. sometimes I can login without issue, but when I logout & re-login, the error happen.
const config = {
auth: {
authority: process.env.REACT_APP_APP_AUTHORITY,
clientId: process.env.REACT_APP_APP_ID,
redirectUri: window.location.origin,
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: false,
},
};
const loginRequest = {
scopes: ['User.Read'],
};
const tokenRequest = {
scopes: ['User.Read'],
};
other codes:
this is my AuthProvider class
// import {MsalAuthProvider, LoginType} from 'react-aad-msal';
import * as msal from '@azure/msal-browser';
const config = {
auth: {
authority: process.env.REACT_APP_APP_AUTHORITY,
clientId: process.env.REACT_APP_APP_ID,
redirectUri: window.location.origin,
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: false,
},
};
const loginRequest = {
scopes: ['User.Read'],
};
const tokenRequest = {
scopes: ['User.Read'],
};
const LoginType = {
LoginRedirect: 0,
LoginPopup: 1,
};
class AuthProvider extends msal.PublicClientApplication {
constructor(logintype, config) {
super(config);
this.loginType = logintype;
}
async getToken(request, account) {
let requestAccount = account;
if (account == null) {
const accounts = await super.getAllAccounts();
if (accounts && accounts.length === 1) {
requestAccount = accounts[0];
}
}
request = {...request, account: requestAccount};
return super.acquireTokenSilent(request).catch((error) => {
if (error instanceof msal.InteractionRequiredAuthError) {
if (this.loginType === LoginType.LoginRedirect) {
return super.acquireTokenRedirect(request);
}
else {
return super.acquireTokenPopup(request);
}
}
throw error;
});
}
_handleResponse(tokenResponse) {
if (tokenResponse) {
return tokenResponse;
}
const accounts = super.getAllAccounts();
if (accounts && accounts.length === 1) {
return this.getToken(loginRequest, accounts[0]).then((response) =>
this._handleResponse(response)
)
.catch(error =>{
if(error instanceof msal.AuthError){
console.error('Error occured during getToken', error);
}
throw error;
});
}else if(accounts === null){
// this.login();
}
}
// use this promise to handle the response and error.
async handleRedirectPromise() {
return super.handleRedirectPromise()
.then((response) => this._handleResponse(response))
;
}
async login() {
if (this.loginType === LoginType.LoginPopup) {
return super.loginPopup(loginRequest);
} else if (this.loginType === LoginType.LoginRedirect) {
return super.loginRedirect(loginRequest);
}
}
async logout() {
sessionStorage.clear();
super.logout();
}
}
const authProvider = new AuthProvider(LoginType.LoginRedirect, config);
export {authProvider, tokenRequest, loginRequest};
this is my AzureAD component:
import React, { useState, useEffect, useCallback } from "react";
import {
authProvider
} from "../../utils/AuthProvider";
const AuthenticationState = {
Authenticated : "Authenticated",
UnAuthenticated: "UnAuthenticated",
InProgress: "InProgress"
};
const AzureADApp = (Component) => {
const AzureAdAppComponent = ({forceLogin, ...otherProps}) => {
const [authenticationState, setAuthenticationState] = useState(AuthenticationState.UnAuthenticated);
const [account, setAccount] = useState(null);
const [accessToken, setAccessToken] = useState(null);
const [roles, setRoles] = useState(null);
const [error, setError] = useState(null);
async function login() {
if(authenticationState !== AuthenticationState.UnAuthenticated){
return;
}
setAuthenticationState(AuthenticationState.InProgress);
authProvider.login();
}
const loginCallBack = useCallback(
() => {
if(authenticationState !== AuthenticationState.UnAuthenticated){
return;
}
setAuthenticationState(AuthenticationState.InProgress);
authProvider.login();
},
[authenticationState],
)
async function logout(){
localStorage.clear();
authProvider.logout();
}
useEffect(() =>{
function handleResponse(tokenResponse){
if(tokenResponse){
setAccount(tokenResponse.account);
setAuthenticationState(AuthenticationState.Authenticated);
if(tokenResponse.idTokenClaims){
setRoles(tokenResponse.idTokenClaims.roles)
}
setAccessToken(tokenResponse.accessToken)
}else if(forceLogin && !error && authenticationState === AuthenticationState.UnAuthenticated){
loginCallBack();
}
}
authProvider.handleRedirectPromise()
.then(handleResponse)
.catch(error => {
setAuthenticationState(AuthenticationState.UnAuthenticated);
console.log("error happened", error);
setError(error.errorMessage);
});
}, [authenticationState, error, forceLogin, loginCallBack]);
return <Component
{...otherProps}
forceLogin={forceLogin}
account={account}
roles={roles}
accessToken={accessToken}
authenticationState={authenticationState}
error={error}
login={login}
logout={logout}
/>;
}
return AzureAdAppComponent;
}
export {AuthenticationState}
export default AzureADApp;
this is my App.js component:
import React, { useState, useEffect, useRef } from 'react';
import AzureADApp, { AuthenticationState } from './components/auth/AuthADApp';
function App(props) {
if(props.error){
return <div>error: {props.error} <button onClick={props.login}>login</button></div>
}
if(props.authenticationState === AuthenticationState.Authenticated){
return <div>hello, <button onClick={props.logout}>logout</button></div>
}
if(props.authenticationState === AuthenticationState.UnAuthenticated && !props.forceLogin)
return (<div>
<button onClick={props.login}>Login</button>
</div>);
return <div>xxxxxxxxxxx</div>
}
export default AzureADApp(App);
this is the index.js:
ReactDOM.render(
<React.StrictMode>
<App forceLogin={false} />
</React.StrictMode>,
document.getElementById('root')
);
login button.login, there is an error happen, it will execute this code and show the error message: if(props.error){
return <div>error: {props.error} <button onClick={props.login}>login</button></div>
}
when I check the sessionStorage, I got :
msal.xxxxx.urlHash: "#code=......&state=.....&session_state=......", and xxxxx is my app id.
login button on the error page, then I can login successfully and see the hello message with logout button.when executing the previous step, at the first time actually step 2 works, but after I logged out, it will always fail.
Should login without error.
Same here, with Firefox on MacosX
We see an issue where state is encoded twice, can you check to see if this is the problem is happening? And are you using a personal account or an organizational account when testing?
I’m using company account for testing. What do you mean ‘state’ encoded twice?
Hi @jmckennon . I updated the code to remove the authenticationState dependency on the useCallback and useEffect, now it works. but still got the error when I do the next steps:
login button. (logout before this step)https://login.microsoftonline.com/....., I input my email address, click nexthttp://localhost:3000.state_mismatch error will throw.this is my updated code for the callback and useEffect:
const loginCallBack = useCallback(
() => {
setAuthenticationState(AuthenticationState.InProgress);
authProvider.login();
},
[],
)
useEffect(() =>{
function handleResponse(tokenResponse){
if(tokenResponse){
setAccount(tokenResponse.account);
setAuthenticationState(AuthenticationState.Authenticated);
if(tokenResponse.idTokenClaims){
setRoles(tokenResponse.idTokenClaims.roles)
}
setAccessToken(tokenResponse.accessToken)
}else if(forceLogin){
loginCallBack();
setAuthenticationState(AuthenticationState.InProgress);
}
}
authProvider.handleRedirectPromise()
.then(handleResponse)
.catch(error => {
setAuthenticationState(AuthenticationState.UnAuthenticated);
console.log("error happened", error);
setError(error.errorMessage);
});
}, [forceLogin, loginCallBack]);
I’m using company account for testing. What do you mean ‘state’ encoded twice?
We have an issue where the server is encoding the state value twice, which leads to some state errors. #1852 addresses this problem, and we think this is most likely where your issue is. This fix will be in for the next release.
Since #1852 was merged and it looks like the other problem in #1864 has been solved, I'll be closing this issue now. Please open a new issue if you have further questions. Thanks!
Most helpful comment
We have an issue where the server is encoding the
statevalue twice, which leads to some state errors. #1852 addresses this problem, and we think this is most likely where your issue is. This fix will be in for the next release.