Search code examples
reactjsreact-hooksreact-router-dominfinite-loopauth0

Using @auth0/auth0-react and getAccessTokenSilently in useEffect leads to infinite loop


I am following the React Authentication By Example:Using React Router 6 [1]. I am using the following dependencies:

react-router-dom 6.3.0
react 18.2 
auth0-react 2.0.1

Everything works fine until I try to call getAccessTokenSilently() inside useEffect() which causes an infinite loop. I searched all related topics but couldn’t find a solution.

Minimal code snippets for repro (following closely the tutorial above):

Auth0ProviderWithNavigate implementation:

import { Auth0Provider } from '@auth0/auth0-react';
import React, { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';

export const Auth0ProviderWithNavigate = ({ children }) => {
  const navigate = useNavigate();
  const onRedirectCallback = (appState) => {
    navigate(appState?.returnTo || window.location.pathname);
  };

  if (!(domain && clientId && redirectUri)) {
    return null;
  }

  return (
    <Auth0Provider
      domain={domain}
      clientId={clientId}
      authorizationParams={{
        audience: audience,
        redirect_uri: redirectUri
      }}
      onRedirectCallback={onRedirectCallback}
      useRefreshTokens={true}
    >
      {children}
    </Auth0Provider>
  );
};

AuthenticationGuard is included on all routes that require authentication:

import { withAuthenticationRequired } from '@auth0/auth0-react';

export const AuthenticationGuard = ({ component }) => {
  const Component = withAuthenticationRequired(component, {
    onRedirecting: () => (
      <div className="page-layout">
        Loading...
      </div>
    ),
  });

  return <Component />;
};

index.tsx implementation:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
import { Auth0ProviderWithNavigate } from './Auth0Provider';

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
  <React.Fragment>
    <BrowserRouter>
      <Auth0ProviderWithNavigate>
        <App />
      </Auth0ProviderWithNavigate>
    </BrowserRouter>
  </React.Fragment>
);

reportWebVitals();

App.tsx which I also see to be called infinitely after I check getAccessTokenSilently() in useEffect():

import * as React from 'react';
import { Routes, Route } from 'react-router-dom';
import Home from 'pages/Home';
import { AuthenticationGuard } from 'components/AuthenticationGuard';
import { AppProvider } from './context';

export default function App(): JSX.Element {
  const { isAuthenticated } = useAuth0();
  console.log('isAuthenticated: ', isAuthenticated); // <------------ this prints in infinite loop
  return (
    <React.Fragment>
      <AppProvider>
          <Routes>
            <Route path="/" element={<AuthenticationGuard component={Home} />} />
          </Routes>
        </div>
      </AppProvider>
    </React.Fragment>
  );
}

AppProvider implementation:

import React, { createContext, useReducer } from 'react';

const AppProvider = ({ children }: ProviderProps) => {
  const [state, dispatch] = useReducer(combinedReducers, initialState);
  return <AppContext.Provider value={{ state, dispatch }}>{children}</AppContext.Provider>;
};
export { AppProvider };

Home component implementation where the infinite loop happens:

import * as React from 'react';
import { useEffect } from 'react';

export default function Home(): JSX.Element {
  useEffect(() => {
    (async () => {
      const token = await getAccessTokenSilently({
        authorizationParams: {
          audience: audience
        },
      });
    console.log('token ', token); // <----------- this prints in infinite loop
    })();
  }, []);

  return (
    <div>Hello from app!</div>
  );
}

When I call getAccessTokenSilently to access my own api, I don’t experience any issues. It only happens when trying to use getAccessTokenSilently in useEffect.

Any pointers on how to resolve this or ideas about why is this happening will be much appreciated. Many thanks!!

[1] React Authentication By Example: Using React Router 6


Solution

  • I've root caused this issue to be due to the usage of withAuthenticationRequired inside < AuthenticationGuard /> on the route for Home component. However, I don't understand fully why the withAuthenticationRequired cause the infinite loop.