-
Notifications
You must be signed in to change notification settings - Fork 2.7k
useIsAuthenticated
hook potentially may return false
even if user is actually authenticated
#6918
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I am getting the opposite isAuthenticated when there are no accounts so my pages are blowing up even though they are wrapped under AuthenticatedTemplate |
Can you please raise a PR so we can review and apply the suggested change it if approved? The guidelines to contribute are here |
@sameerag ok, I will create PR |
I believe I just ran into this issue. It surfaced after upgrading to react 18. Overall flow is that this issue happens for freshly created accounts that get redirected back to my app. My code looks like:
Render 1: Render 2 is the problem, where the hook is returning that the user is not authenticated even though there is an account. If I revert to React 17 that doesn't happen. |
@sameerag Did this get completed? I'm not seeing any associated release notes or pull request |
… user is authenticated (#7057) Addresses #6918 The current `useIsAuthenticated` has an unnecessary `useEffect`, which causes it to briefly return `false` in some cases even when an account is present. See https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state and https://react.dev/learn/you-might-not-need-an-effect#caching-expensive-calculations This PR switches to use the `useMemo` recommendation I added a unit test that passes now, but fails with the old implementation: ``` FAIL test/hooks/useIsAuthenticated.spec.tsx ● withMsal tests › useAuthenticated always returns true if user has an account expect(jest.fn()).toHaveBeenCalledTimes(expected) Expected number of calls: 0 Received number of calls: 1 78 | expect(await screen.findByText("Has accounts")).toBeInTheDocument(); 79 | expect(await screen.findByText("Is authed")).toBeInTheDocument(); > 80 | expect(invalidAuthStateCallback).toHaveBeenCalledTimes(0); | ^ 81 | }); 82 | }); 83 | at Object.<anonymous> (test/hooks/useIsAuthenticated.spec.tsx:80:42) ``` I also had to tweak some act / await / async code in other tests, presumably because now it takes fewer renders for the hook to start returning the correct value. Without the tweaks a couple tests were failing, and others printed warning about updating state outside of an `act(...)`. --------- Co-authored-by: Thomas Norling <[email protected]> Co-authored-by: Jo Arroyo <[email protected]>
Core Library
MSAL.js (@azure/msal-browser)
Wrapper Library
MSAL React (@azure/msal-react)
Public or Confidential Client?
Public
Description
Here is the current implementation of the
useIsAuthenticated
hook (https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/msal-react-v2.0.12/lib/msal-react/src/hooks/useIsAuthenticated.ts#L32):If you look carefully at the implementation, you may notice that there is a chance that on subsequent renders (all renders except the initial) that hook may return
false
even if user is authenticated and there are actually presented accounts in msal instance (isAuthenticated(allAccounts, matchAccount) === true
). It happens because on each render we return the value (hasAuthenticated
) calculated at the previous render (to be precise calculated right after the previous render, inuseEffect
hook).That behavior may cause problems, for example, lately, I had a scenario where
UnauthenticatedTemplate
component (which usesuseIsAuthenticated
under the hood) was rendering its content (children
props) even when the user was actually authenticated (so the account was presented in msal instance).Below you can see pseudo-code to demonstrate that scenario:
In my case,
DoLoginRedirect
was rendered for a short time after completing authentication (after redirecting from authentication server to be precise) and as a result, one more redundant login redirect step/loop happened.After some time of debugging, I suspect that the implementation of
useIsAuthenticated
is the culprit of my problems. To be precise, I think that on render, the value returned byuseIsAuthenticated
hook is stale cause it was calculated before the actual render (it was calculated after the previous render in theuseEffect
hook).Taking into account everything mentioned above, I would suggest to change implementation of
useIsAuthenticated
hook to something like that:I know that the suggested implementation does not look very elegant and may be improved but the main point is that new implementation solves an issue with returned stale value and it also prevents redundant re-render (because we don't update any state (
useState
) anymore).Please let me know your opinion on that matter and correct me if something is wrong with my suggestions and considerations. Thank you in advance
Source
External (Customer)
The text was updated successfully, but these errors were encountered: