microsoft-authentication-library-for-js
microsoft-authentication-library-for-js copied to clipboard
useMsalAuthentication hook is not working after upgrading to msal-react 1.5.1
Core Library
MSAL.js v2 (@azure/msal-browser)
Core Library Version
2.32.1
Wrapper Library
MSAL React (@azure/msal-react)
Wrapper Library Version
1.5.1
Public or Confidential Client?
Public
Description
We are facing an issue with the useMsalAuthentication hook when upgrading to msal-react 1.5.1 in the following PR. We are not receiving any response (accessToken, error) from the hook if we wrap our components with React.StrictMode. I believe it is related to an update we made in msal-react 1.5.0. If we remove the strict mode or downgrade to msal-react 1.4.10 the application works as expected.
Error Message
No error message.
Msal Logs
[Thu, 08 Dec 2022 19:11:11 GMT] : @azure/[email protected] : Info - Emitting event: msal:initializeStart authConfig.js:40 [Thu, 08 Dec 2022 19:11:11 GMT] : @azure/[email protected] : Info - Emitting event: msal:initializeEnd authConfig.js:40 [Thu, 08 Dec 2022 19:11:11 GMT] : @azure/[email protected] : Info - initialize has already been called, exiting early. authConfig.js:40 [Thu, 08 Dec 2022 19:11:11 GMT] : @azure/[email protected] : Info - Emitting event: msal:handleRedirectStart authConfig.js:40 [Thu, 08 Dec 2022 19:11:11 GMT] : [3abf3b22-d2c0-4832-b960-ac399ba94351] : [email protected] : Info - handleRedirectPromise called but there is no interaction in progress, returning null. authConfig.js:40 [Thu, 08 Dec 2022 19:11:11 GMT] : @azure/[email protected] : Info - Emitting event: msal:handleRedirectEnd authConfig.js:40 [Thu, 08 Dec 2022 19:11:11 GMT] : @azure/[email protected] : Info - MsalProvider - msal:handleRedirectStart results in setting inProgress from startup to handleRedirect authConfig.js:40 [Thu, 08 Dec 2022 19:11:11 GMT] : @azure/[email protected] : Info - MsalProvider - msal:handleRedirectEnd results in setting inProgress from handleRedirect to none authConfig.js:40 [Thu, 08 Dec 2022 19:11:11 GMT] : @azure/[email protected] : Info - MsalProvider - msal:handleRedirectStart results in setting inProgress from startup to handleRedirect authConfig.js:40 [Thu, 08 Dec 2022 19:11:11 GMT] : @azure/[email protected] : Info - MsalProvider - msal:handleRedirectEnd results in setting inProgress from handleRedirect to none authConfig.js:40 [Thu, 08 Dec 2022 19:11:11 GMT] : @azure/[email protected] : Info - useMsalAuthentication - User is authenticated, attempting to acquire token authConfig.js:40 [Thu, 08 Dec 2022 19:11:11 GMT] : @azure/[email protected] : Info - Emitting event: msal:acquireTokenStart authConfig.js:40 [Thu, 08 Dec 2022 19:11:12 GMT] : @azure/[email protected] : Info - Emitting event: msal:acquireTokenSuccess
MSAL Configuration
export const msalConfig = {
auth: {
clientId: 'Enter_the_Application_Id_Here', // This is the ONLY mandatory field that you need to supply.
authority: 'https://login.microsoftonline.com/Enter_the_Tenant_Info_Here', // Defaults to "https://login.microsoftonline.com/common"
redirectUri: '/', // Points to window.location.origin. You must register this URI on Azure Portal/App Registration.
postLogoutRedirectUri: '/', // Indicates the page to navigate after logout.
clientCapabilities: ['CP1'], // this lets the resource owner know that this client is capable of handling claims challenge.
},
cache: {
cacheLocation: 'localStorage', // Configures cache location. "sessionStorage" is more secure, but "localStorage" gives you SSO between tabs.
storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
},
system: {
/**
* Below you can configure MSAL.js logs. For more information, visit:
* https://docs.microsoft.com/azure/active-directory/develop/msal-logging-js
*/
loggerOptions: {
loggerCallback: (level, message, containsPii) => {
if (containsPii) {
return;
}
switch (level) {
case LogLevel.Error:
console.error(message);
return;
case LogLevel.Info:
console.info(message);
return;
case LogLevel.Verbose:
console.debug(message);
return;
case LogLevel.Warning:
console.warn(message);
return;
}
},
},
},
};
Relevant Code Snippets
export const Profile = () => {
const { instance } = useMsal();
const account = instance.getActiveAccount();
const [graphData, setGraphData] = useState(null);
const request = {
scopes: protectedResources.graphMe.scopes,
account: account,
};
const { login, result, error } = useMsalAuthentication(InteractionType.Popup, {
...request,
redirectUri: '/redirect.html',
});
useEffect(() => {
if (!!graphData) {
return;
}
if (!!error) {
// in case popup is blocked, use redirect instead
if (error.errorCode === 'popup_window_error' || error.errorCode === 'empty_window_error') {
login(InteractionType.Redirect, request);
}
console.log(error);
return;
}
if (result) {
let accessToken = result.accessToken;
getGraphClient(accessToken)
.api('/me')
.responseType(ResponseType.RAW)
.get()
}
}, [graphData, result, error, login]);
if (error) {
return <div>Error: {error.message}</div>;
}
return <>{graphData ? <ProfileData response={result} graphData={graphData} /> : null}</>;
};
Reproduction Steps
- Clone https://github.com/Azure-Samples/ms-identity-javascript-react-tutorial.git
- cd 2-Authorization-I\1-call-graph\SPA.
- Checkout branch update-msal-packages.
- Configure application.
- sign-in and navigate to profile page.
Expected Behavior
Expect the result (accessToken) or an error from the useMsalAuthentication
hook.
Identity Provider
Azure AD / MSA
Browsers Affected (Select all that apply)
Chrome
Regression
@azure/msal-react 1.4.10
Source
Internal (Microsoft)
This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @jo-arroyo please follow up.
Thanks for raising this. I've determined this is due to a change to StrictMode in React 18, specifically in development mode. What's happening is that React is mounting, unmounting then remounting the component but instead of starting with a clean slate on each mount it is preserving state and refs which results in the finalizer for the token acquisition thinking the component is not mounted and not setting state.
More discussion in this issue in the React repo.
This could be resolved by resetting the value of the ref we use to track whether or not the component is mounted in a useEffect, though it's not clear to me yet if that would cause any unintended consequences or if this is even something we should be responsible for. For now the workarounds seem to be:
- Don't use StrictMode until the React team addresses this gap
- Serve the app in production mode which does not perform the new behavior
- Downgrade to React 17
I'll mark this as a bug but I'm not committing to fixing it on our end quite yet.
Thanks @tnorling. I will update our samples accordingly.
I'll mark this as a bug but I'm not committing to fixing it on our end quite yet.
@tnorling Any decision on whether this is or is not a bug? Ran into it today. Appreciated the workaround - I failed to connect this issue with React's strict mode until I saw your response here.
@tnorling Hi Thomas!
As i found this bug this week and had difficulties finding out where does it come from, i looked after the different opinions on this subject. It seems React team doesn't want to change their way of thinking around that, as they made a whole doc page about this subject : React page about it
I can't conceive that the solution is either loosing StrictMode, either loosing React Development mode, either coming back to older version of MSAL or than React 18 which is already kinda "old".
taking account that time has passed by since the last comments on this, can we hope that you could take it on your side? (as it seems to be the main road for all the dependent libraries).
considering MSAL is one of the best, or the best library around authentication right now, i hope solving this point, even if i understand it's a pain you don't need, could be a thing for the community.
Regards,
@FCazabon-EM The issue isn't about the effect running twice or even the component mounting twice (which is what the doc you linked discusses), this has always been the case in StrictMode and we do handle this gracefully. The issue here is that in React 18 they changed the behavior to preserve state between the two mounts of the component which runs counter to the traditional understanding that mounting a component starts over with its initial state.
There's a long thread about this in React's repo I linked in my previous comment, I'd recommend sharing your experience with this change there. Until we get confirmation from the React team that this is both intended behavior and won't be addressed (ideally with an official recommendation about how to handle this) I'm treating this as a bug on React.
Hi @tnorling. I'm wondering how other vendors are approaching this new React behavior. It's been months since the release and maybe some assumptions can be made. What are your thoughs?
Just adding my voice to this. I've wasted two whole days on this issue on a brand new Next.js project. Based on previous experience and available documentation with MSAL, I could not have imagined that StrictMode was causing this errant behavior. There's no hint from the function where to look. All I could tell was that it was always returning an undefined result. I had to spend hours injecting log messages into useFetchWithMsal and useMsalAuthentication with countless app restarts just to get to the point where I finally broke down and checked here for this very issue.
Being stubborn about whose bug it is and doing nothing is a disservice. Even if you won't find a way to fix this on your end, please inject an obvious warning so people like me don't waste our lives chasing this down. Please add something like, "You seem to be using React 18+ with new StrictMode behavior. MSAL will not work correctly in this configuration. Please disable StrictMode for this version of MSAL. For more information, visit https://whatever."
It's pretty clear by now that this is intended functionality in React (https://github.com/reactjs/react.dev/issues/6123). I know the docs haven't been great up until recently, but asking users of a library this popular to disable React quality checks for a feature to work correctly isn't acceptable.
Are you working on this?