I’m trying to implement JWT in my project and an article provides a nice solution:
https://dev.to/sanjayttg/jwt-authentication-in-react-with-react-router-1d03.
Routes.jsx
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { useAuth } from "../provider/authProvider";
import { ProtectedRoute } from "./ProtectedRoute";
import Login from "../pages/Login";
import Logout from "../pages/Logout";
const Routes = () => {
const { token } = useAuth();
// Define public routes accessible to all users
const routesForPublic = [
{
path: "/service",
element: <div>Service Page</div>,
},
{
path: "/about-us",
element: <div>About Us</div>,
},
];
// Define routes accessible only to authenticated users
const routesForAuthenticatedOnly = [
{
path: "/",
element: <ProtectedRoute />, // Wrap the component in ProtectedRoute
children: [
{
path: "",
element: <div>User Home Page</div>,
},
{
path: "/profile",
element: <div>User Profile</div>,
},
{
path: "/logout",
element: <Logout/>,
},
],
},
];
// Define routes accessible only to non-authenticated users
const routesForNotAuthenticatedOnly = [
{
path: "/",
element: <div>Home Page</div>,
},
{
path: "/login",
element: <Login/>,
},
];
// Combine and conditionally include routes based on authentication status
const router = createBrowserRouter([
...routesForPublic,
...(!token ? routesForNotAuthenticatedOnly : []),
...routesForAuthenticatedOnly,
]);
// Provide the router configuration using RouterProvider
return <RouterProvider router={router} />;
};
export default Routes;
ProtectedRoute.jsx
import { Navigate, Outlet } from "react-router-dom";
import { useAuth } from "../provider/authProvider";
export const ProtectedRoute = () => {
const { token } = useAuth();
// Check if the user is authenticated
if (!token) {
// If not authenticated, redirect to the login page
return <Navigate to="/login" />;
}
// If authenticated, render the child routes
return <Outlet />;
};
Github:
https://github.com/sanjay-arya/react-auth-demo
I basically created aa Auth context providing token information to all routes and allows access to routes on whether the user has a token or not. It also has a login and logout system removing/creating tokens.
The code provided works fine as it is. The problem arises when I want to redirect the user to the "/login"
page instead of the "/"
page after logging out. e.g. I changed navigate("/", { replace: true })
to navigate("/login", { replace: true });
in Logout.jsx.
I get this error:
react-router-dom.js?v=7652cf65:202 Uncaught Error: Could not find a matching route for errors on route IDs: 2
at invariant (react-router-dom.js?v=7652cf65:202:11)
at _renderMatches (react-router-dom.js?v=7652cf65:3167:33)
at useRoutesImpl (react-router-dom.js?v=7652cf65:3033:25)
at DataRoutes (react-router-dom.js?v=7652cf65:3422:10)
at renderWithHooks (react-dom_client.js?v=7652cf65:12171:26)
at updateFunctionComponent (react-dom_client.js?v=7652cf65:14577:28)
at beginWork (react-dom_client.js?v=7652cf65:15912:22)
at HTMLUnknownElement.callCallback2 (react-dom_client.js?v=7652cf65:3674:22)
at Object.invokeGuardedCallbackDev (react-dom_client.js?v=7652cf65:3699:24)
at invokeGuardedCallback (react-dom_client.js?v=7652cf65:3733:39)
Show 19 more frames
console.js:213 The above error occurred in the <DataRoutes> component:
at DataRoutes (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=7652cf65:3419:5)
at Router (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=7652cf65:3491:15)
at RouterProvider (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=7652cf65:3375:5)
at Routes (http://localhost:5173/src/routes/index.jsx?t=1712483351401:26:7)
at AuthProvider (http://localhost:5173/src/provider/authProvider.jsx:21:3)
at App
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
It’s an uncaught error but even when adding errorElement to the routes the errors still persist. Even then, I still do not know why there would be an error. I’ve been trying to figure out the issue for hours but no success.
2
Answers
Check if you’ve defined route correctly
The general issue is that you are conditionally rendering your routes, so when the authentication condition based on the
token
changes, some routes you want to navigate to are not mounted and rendered yet. The solution is to unconditionally render the routes.Update
Routes
to remove thetoken
check and unconditionally renderroutesForNotAuthenticatedOnly
routes and create a "protected route component" that does the inverse ofProtectedRoute
to protect these routes from authenticated users.Example: