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>
}
/>
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>