-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Closed
Labels
bugA problem that needs to be fixed for the feature to function as intended.A problem that needs to be fixed for the feature to function as intended.msal-browserRelated to msal-browser packageRelated to msal-browser package
Description
Please follow the issue template below. Failure to do so will result in a delay in answering your question.
Library
- [ x]
"@azure/msal-browser": "^2.0.0-beta.3"
Framework
Description
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.
Error Message
Security
- Is this issue security related?
Regression
- Did this behavior work before?
Version:
MSAL Configuration
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')
);Reproduction steps
- start app.
- page will show a
loginbutton. - click
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.
- click the
loginbutton 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.
Expected behavior
Should login without error.
Browsers/Environment
- [x ] Chrome
- [x ] Edge
Metadata
Metadata
Assignees
Labels
bugA problem that needs to be fixed for the feature to function as intended.A problem that needs to be fixed for the feature to function as intended.msal-browserRelated to msal-browser packageRelated to msal-browser package