skip to Main Content

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


  1. Check if you’ve defined route correctly

    Login or Signup to reply.
  2. 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 the token check and unconditionally render routesForNotAuthenticatedOnly routes and create a "protected route component" that does the inverse of ProtectedRoute to protect these routes from authenticated users.

    Example:

    import { Navigate, Outlet } from "react-router-dom";
    import { useAuth } from "../provider/authProvider";
    
    export const AnonymousRoute = () => {
      const { token } = useAuth();
    
      // Check if the user is authenticated
      if (!token) {
        // If not authenticated, render the child routes
        return <Outlet />;
      }
    
      // If authenticated, redirect to safe page
      return <Navigate to="/" />;
    };
    
    import { RouterProvider, createBrowserRouter } from "react-router-dom";
    import { useAuth } from "../provider/authProvider";
    import { ProtectedRoute } from "./ProtectedRoute";
    import { AnonymousRoute } from "./ProtectedRoute";
    import Login from "../pages/Login";
    import Logout from "../pages/Logout";
    
    const Routes = () => {
      // Define public routes accessible to all users
      const routesForPublic = [
        {
          path: "/",
          element: <div>User Home Page</div>,
        },  
        {
          path: "/service",
          element: <div>Service Page</div>,
        },
        {
          path: "/about-us",
          element: <div>About Us</div>,
        },
      ];
    
      // Define routes accessible only to authenticated users
      const routesForAuthenticatedOnly = [
        {
          element: <ProtectedRoute />,
          children: [
            {
              path: "/profile",
              element: <div>User Profile</div>,
            },
            {
              path: "/logout",
              element: <Logout />,
            },
          ],
        },
      ];
    
      // Define routes accessible only to non-authenticated users
      const routesForNotAuthenticatedOnly = [
        {
          element: <AnonymousRoute />,
          children: [
            {
              path: "/login",
              element: <Login />,
            },
          ],
        },
      ];
    
      // Combine and conditionally include routes based on authentication status
      const router = createBrowserRouter([
        ...routesForPublic,
        ...routesForNotAuthenticatedOnly),
        ...routesForAuthenticatedOnly,
      ]);
    
      // Provide the router configuration using RouterProvider
      return <RouterProvider router={router} />;
    };
    
    export default Routes;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search