skip to Main Content

I am trying to implement a private route towards my application, and while it correctly reaches the private route when authenticated, it redirects it to the login page rather than the children. I’ve tried every solution on stackoverflow but they don’t seem to work. It’s strange because it reaches the right path (I print to console whenever I reach the private route) but it’s not able to redirect the page correctly.

PrivateRoute

import { useState, useEffect } from 'react';
import { useRef } from 'react';
import { Outlet, Navigate, useLocation } from 'react-router-dom';
import Axios from "axios";
import Cookies from "universal-cookie";

export default function ProtectedRoute({ children }) {
  const [isAuthenticated, setIsAuthenticated] = useState();
  // add loading state, initially true for initial render
  const [isLoading, setIsLoading] = useState(true);
  const checkAuth = async () => {
    const cookie = new Cookies(); 
    setIsLoading(true); // <-- set true when starting auth check
    try {
      if (cookie.get("stytch_session") == null) {
        console.log("no cookies!")
        setIsAuthenticated(false);
      } else {
        Axios.post(
          "http://localhost:5001/test",
          {},
          { headers: { sessiontoken: cookie.get("stytch_session") } }
        )
          .then((response) => {
            console.log("reaching private route!")
            setIsAuthenticated(true);
          })
          .catch((err) => {
            console.log(err)
            setIsAuthenticated(false);
          });
      }
    } finally {
      setIsLoading(false); // <-- clear loading state when completed
    }
  };

  useEffect(() => {
    checkAuth();
  }, []);

  if (isLoading) {
    return <div className="">Loading...</div>;
  }

  return isAuthenticated ? children : <Navigate to={"/login"} />;

}

And here is the code snippet that’s called in app.js

<Route
  path="/scroll"
  element={(
    <ProtectedRoute>
      <Scroll /> 
    </ProtectedRoute>
  }
/> 

3

Answers


  1. Could you try using Outlet if your private route is child of ProtectedRoute component? Like following.

    return isAuthenticated ? <Outlet />: <Navigate to={"/login"} />;
    
    Login or Signup to reply.
  2. Try removing the finally and putting in

    useEffect(()=>{
       if(isAuthenticated !== null){
       setIsLoading(false);
       }
    },[isAuthenticated])
    

    What it looks like to me is that your state updates are being batched or resolving in the wrong order. This will ensure that isLoading remains true until isAuthenticated has a real value.

    Login or Signup to reply.
  3. The axios.post starts an asynchronous Promise chain that the synchronous code around it doesn’t wait for. The finally block is executed prior to the POST request resolving.

    The code should await the Promise to resolve.

    export default function ProtectedRoute() {
      const [isAuthenticated, setIsAuthenticated] = useState();
    
      // add loading state, initially true for initial render
      const [isLoading, setIsLoading] = useState(true);
    
      const checkAuth = async () => {
        const cookie = new Cookies(); 
        setIsLoading(true);
    
        try {
          if (cookie.get("stytch_session") == null) {
            console.log("no cookies!")
            setIsAuthenticated(false);
          } else {
            await Axios.post(
              "http://localhost:5001/test",
              {},
              { headers: { sessiontoken: cookie.get("stytch_session") } }
            );
            console.log("reaching private route!")
            setIsAuthenticated(true);
        } catch(err) {
          console.log(err);
          setIsAuthenticated(false);
        } finally {
          setIsLoading(false);
        }
      };
    
      useEffect(() => {
        checkAuth();
      }, []);
    
      if (isLoading) {
        return <div className="">Loading...</div>;
      }
    
      return isAuthenticated ? <Outlet /> : <Navigate to="/login" replace />;
    }
    
    <Route element={<ProtectedRoute />}>
      <Route path="/scroll" element={<Scroll />} />
      ... other protected routes ...
    </Route>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search