60

What is correct way to write a ProtectedRoute with new version 6 of react-router? I wrote this one, but it's not a route

const PrivateRoute = ({ component: Component, ...props }) => {   
  if (!Component) return null;

  return props.isAuthenticated
    ? <Component />
    : <Navigate to={props.redirectLink} /> }

export default PrivateRoute;
Victor
  • 745
  • 2
  • 7
  • 16
  • Well, there is no such thing as you said this is not a route. I believe you're doing it the right way. There is no direct thing in React-Router for this. You need to write a wrapper like this. However, I'm not sure what `Navigate` is in your code. – Deepak Jun 15 '20 at 08:42
  • "If you prefer to use a declarative API for navigation (ala v5's Redirect component), v6 provides a Navigate component." You can find more info here https://github.com/ReactTraining/react-router/blob/dev/docs/advanced-guides/migrating-5-to-6.md – Victor Jun 15 '20 at 09:16
  • Perhaps a helpful walkthrough: https://www.robinwieruch.de/react-router-authentication/ – Robin Wieruch Jan 26 '22 at 11:16

17 Answers17

117

Here is my working example for implementing private routes by using useRoutes.

App.js

import routes from './routes';
import { useRoutes } from 'react-router-dom';

function App() {
  const { isLoggedIn } = useSelector((state) => state.auth);

  const routing = useRoutes(routes(isLoggedIn));

  return (
    <>
      {routing}
    </>
  );
}

routes.js

import { Navigate,Outlet } from 'react-router-dom';

const routes = (isLoggedIn) => [
  {
    path: '/app',
    element: isLoggedIn ? <DashboardLayout /> : <Navigate to="/login" />,
    children: [
      { path: '/dashboard', element: <Dashboard /> },
      { path: '/account', element: <Account /> },
      { path: '/', element: <Navigate to="/app/dashboard" /> },
      {
        path: 'member',
        element: <Outlet />,
        children: [
          { path: '/', element: <MemberGrid /> },
          { path: '/add', element: <AddMember /> },
        ],
      },
    ],
  },
  {
    path: '/',
    element: !isLoggedIn ? <MainLayout /> : <Navigate to="/app/dashboard" />,
    children: [
      { path: 'login', element: <Login /> },
      { path: '/', element: <Navigate to="/login" /> },
    ],
  },
];

export default routes;
Andrii Abramov
  • 10,019
  • 9
  • 74
  • 96
vignesh
  • 2,356
  • 1
  • 14
  • 21
  • 8
    this is the only one I think that makes sense here... – fmsthird Nov 21 '20 at 13:27
  • 1
    @fmsthird ...sure if you already use redux. – Cris69 Feb 23 '21 at 13:03
  • 4
    i get this errror! Error: useRoutes() may be used only in the context of a component. i have wrapped with Router – Mohammad Sadman Oct 06 '21 at 06:58
  • 2
    This one did the trick. I was searching for the `useRoutes()` implementation. Thanks! – Asutosh Panda Oct 16 '21 at 17:46
  • 1
    Thank you so much for this. Seeing examples like this one makes me understand the update to V6 even better than reading the docs :D – Sherlock Bourne Feb 07 '22 at 11:13
  • @MohammadSadman the response is here https://stackoverflow.com/a/65427285/9868383 – D4ITON Feb 12 '22 at 12:36
  • 1
    Definitely the way to go for router guarding as compared to the example provided on their website. Mainly to avoid the situation of having the route URL rapidly changing as you navigate around the site. – Tom C Apr 01 '22 at 12:04
  • You have to remove all children paths that start with `/`. For example,`/dashboard` to `dashboard`and `'/'` to `''`. Otherwise you'll get an error saying the nested path is not valid. – Abdulelah Mar 19 '23 at 17:50
68

I took this example from react-router-dom: https://github.com/remix-run/react-router/blob/main/examples/auth/README.md

Then modify into this https://stackblitz.com/edit/github-5kknft?file=src%2FApp.tsx

export default function App() {
  return (
    <AuthProvider>
      <Routes>
        <Route element={<Layout />}>
          <Route path="/" element={<PublicPage />} />
          <Route path="/public" element={<PublicPage />} />
          <Route path="/login" element={<LoginPage />} />
          <Route element={<RequireAuth />}>
            <Route path="/protected" element={<ProtectedPage />} />
            <Route path="/dashboard" element={<Dashboard />} />
          </Route>
        </Route>
        <Route path="*" element={<NotFound />} />
      </Routes>
    </AuthProvider>
  );
}
function RequireAuth() {
  let auth = useAuth();
  let location = useLocation();

  if (!auth.user) {
    // Redirect them to the /login page, but save the current location they were
    // trying to go to when they were redirected. This allows us to send them
    // along to that page after they login, which is a nicer user experience
    // than dropping them off on the home page.
    return <Navigate to="/login" state={{ from: location }} />;
  }

  return <Outlet />;
}

Zet
  • 681
  • 5
  • 5
  • 6
    this is soooo much nicer than the 'official' way of having to wrap each `element` prop with `RequireAuth` - had you any issues using this method or does it work as you expected? – andy mccullough Jan 10 '22 at 11:55
34

Here is an official guideline from React Router documentation.

Instead of creating wrappers for your <Route> elements to get the functionality you need, you should do all your own composition in the <Route element> prop.

Taking the example from above, if you wanted to protect certain routes from non-authenticated users in React Router v6, you could do something like this:

import { Routes, Route, Navigate } from "react-router-dom";

function App() {
  return (
    <Routes>
      <Route path="/public" element={<PublicPage />} />
      <Route
        path="/protected"
        element={
          // Good! Do your composition here instead of wrapping <Route>.
          // This is really just inverting the wrapping, but it's a lot
          // more clear which components expect which props.
          <RequireAuth redirectTo="/login">
            <ProtectedPage />
          </RequireAuth>
        }
      />
    </Routes>
  );
}

function RequireAuth({ children, redirectTo }) {
  let isAuthenticated = getAuth();
  return isAuthenticated ? children : <Navigate to={redirectTo} />;
}

Notice how in this example the RequireAuth component doesn't expect any of <Route>'s props. This is because it isn't trying to act like a <Route>. Instead, it's just being rendered inside a <Route>.

wonsuc
  • 3,498
  • 1
  • 27
  • 30
8

Here's my latest working implementation with react-router v6 beta. I don't know how to implement a protected routes with useRoutes though. Their documentation should add an example on how to implement protected/private routes in both ways.

ProtectedRoute component

import React from 'react';
import PropTypes from 'prop-types';
import { Route } from 'react-router-dom';
import Forbidden from '../../views/errors/Forbidden';
import { useAuth } from '../../contexts/AuthContext';

const ProtectedRoute = ({ roles, element, children, ...rest }) => {
  const { user, login } = useAuth();

  if (!user) {
    login();
    return <></>;
  }

  if (roles.length > 0) {
    const routeRoles = roles.map((role) => role.toLowerCase());
    const userRoles = (user && user.roles ? user.roles : []).map((role) => role.toLowerCase());
    if (miscUtils.intersection(routeRoles, userRoles).length === 0) {
      return <Forbidden />;
    }
  }

  return (
    <Route element={element} {...rest}>
      {children}
    </Route>
  );
};

ProtectedRoute.propTypes = {
  roles: PropTypes.arrayOf(PropTypes.string),
  element: PropTypes.element,
  children: PropTypes.node,
};

ProtectedRoute.defaultProps = {
  roles: [],
  element: null,
  children: null,
};

export default ProtectedRoute;

AppRoutes component

import React from 'react';
import { Routes, Route, Navigate, Outlet } from 'react-router-dom';
import Login from './components/oauth/Login';
import Logout from './components/oauth/Logout';
import RenewToken from './components/oauth/RenewToken';
import ProtectedRoute from './components/ProtectedRoute';
import NotFound from './views/errors/NotFound';
import Index from './views/Index';
import MainContainer from './views/MainContainer';
import ViewUserProfile from './views/user/profile/ViewUserProfile';
import CreateUserProfile from './views/user/profile/CreateUserProfile';
import UpdateUserProfile from './views/user/profile/UpdateUserProfile';
import PartnerProfile from './views/partner/profile/PartnerProfile';

const AppRoutes = () => {
  return (
    <Routes>
      {/* auth pages (important: do not place under /auth path) */}
      <Route path="oauth/login" element={<Login />} />
      <Route path="oauth/logout" element={<Logout />} />
      <Route path="oauth/renew" element={<RenewToken />} />
      <Route element={<MainContainer />}>
        <Route path="/" element={<Index />} />

        {/* protected routes */}
        <ProtectedRoute path="user" element={<Outlet />}>
          <Route path="/" element={<Navigate to="profile" replace />} />

          <Route path="profile" element={<Outlet />}>
            <Route path="/" element={<ViewUserProfile />} />
            <Route path="create" element={<CreateUserProfile />} />
            <Route path="update" element={<UpdateUserProfile />} />
          </Route>
        </ProtectedRoute>

        <ProtectedRoute path="partner" roles={['partner']} element={<Outlet />}>
          <Route path="/" element={<Navigate to="profile" replace />} />
          <Route path="profile" element={<PartnerProfile />} />
        </ProtectedRoute>
      </Route>
      <Route path="*" element={<NotFound />} />
    </Routes>
  );
};

export default AppRoutes;
sebascomeau
  • 169
  • 3
  • 13
6

You would need to write a small wrapper and use Navigate component to redirect. Also you need to render a route

const Container = ({Component, redirectLink, isAuthenticated, ...props}) => {
  if(!isAuthenticated) {
       return <Navigate to={redirectLink} />;
   }
   
   return <Component {...props} />
}
const PrivateRoute = ({ component: Component, redirectLink, isAuthenticated, path, ...props }) => {   

  return (
    <Route
        path={path}
        element={<Container redirectLink={redirectLink} isAuthenticate={isAuthenticated} Component={Component} />}
    />
)

export default PrivateRoute;

You can find the migration guidelines here on the github docs

Luiz Cieslak
  • 59
  • 1
  • 10
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
5

All good options. You can also simply render different route handling based on auth state (or any other state). You don't have to use the raw Javascript object method.

Don't forget you can use an immediately invoked anonymous inner function (() => COMPONENT)() to dynamically decide what component handles a particular <Route/>.

The examples may not yet be in the preliminary documentation for v6 because handling private <Route/>s is actually surprisingly simple.

E.g.

<Routes>
      {state.authed ?
        // Wait until we have the current user...
        currentUser ?
          <Route
            path='/'
            element={(() => {
              // Show a "no access" message if the user is NOT an App Admin doesn't have access to any schools at all (which includes not having access to anything INSIDE any school either)
              if (!currentUser.appAdministrator && currentUser.schoolIds?.length === 0) return <AdminNoAccess />
              return <Outlet />
            })()}
          >
            <Route
              path='/'
              element={(() => {
                // If the user is a super user, we return the <SuperAdmin /> component, which renders some of its own routes/nav.
                if (currentUser.appAdministrator) return <SuperAdmin />
                return <Outlet />
              })()}
            >
              <Route
                path='schools'
                element={(() => {
                  if (currentUser.schoolIds?.length === 1) {
                    return <Navigate to={`schools/schoolId`} />
                  } else {
                    return <AdminSchools />
                  }
                })()}
              />

              <Route path='users' children={<Users />} />
            </Route>

            <Route path={`schools/:schoolId`} element={<AdminSchool />} />

            <Route path='*' element={<Navigate to='schools' />} />
          </Route>
          :
          null
        :
        <>
          <Route path='login' element={<Login />} />
          <Route path='signup' element={<Signup />} />
          <Route path='forgot-password' element={<ForgotPassword />} />
          <Route path='reset-password' element={<ResetPassword />} />

          <Route path='*' element={<Navigate to='login' />} />
        </>
      }
    </Routes>
Brock Klein
  • 317
  • 4
  • 11
4

Here's a slightly more TypeScript friendly implementation that reuses RouteProps from react-router v6:

import React from 'react';
import { RouteProps } from 'react-router';
import { Route, Navigate } from 'react-router-dom';
import { useAuthState } from '../../contexts';

export interface PrivateRouteProps extends RouteProps {
  redirectPath: string;
}

export const PrivateRoute = ({ redirectPath, ...props }: PrivateRouteProps) => {
  const { user } = useAuthState();
  if (!user) {
    return <Navigate to={redirectPath} />;
  }
  return <Route {...props} />;
};

useAuthState is a hook that is able to retrieve the user if one is logged in.

This is how I use it:

<Routes>
  <Route path="/" element={<Home />} />
  <PrivateRoute path="/admin" redirectPath="/signin" element={<Admin />} />
  <Route path="*" element={<NotFound />} />
</Routes>
Naresh
  • 23,937
  • 33
  • 132
  • 204
3

This is the structure for the BrowserRouter as Router:

const AppRouter = () => {
  return (
    <Router>
      <Layout>
        <Routes>
          <Route exact path="" element={<Home />} />
          <Route exact path="login" element={<Login />} />
          <Route exact path="register" element={<Register />} />

          // These are the Private Components
          <Route
            exact
            path="/account"
            element={
              <PrivateRoute>
                <Account />
              </PrivateRoute>
            }
          />

          <Route
            exact
            path="/quizzes"
            element={
              <PrivateRoute>
                <Quizzes />
              </PrivateRoute>
            }
          />

          <Route
            exact
            path="/quizz/:quizzid"
            element={
              <PrivateRoute>
                <Quizz />
              </PrivateRoute>
            }
          />

          <Route
            exact
            path="/admin/users"
            element={
              <PrivateRoute>
                <Users />
              </PrivateRoute>
            }
          />
          <Route exact path="*" element={<NotFound />} />
        </Routes>
      </Layout>
    </Router>
  );
};

This is the PrivateRoute:

import { Navigate } from "react-router-dom";
import { useAuth } from "../auth/useAuth";

function PrivateRoute({ children }) {
  const auth = useAuth();
  return auth.user ? children : <Navigate to="/login" />;
}

export default PrivateRoute;
  • It woks but causes the route to flicker showing the children first and only correcting later. Any idea how to solve this? – Hermeneutiker Jan 15 '22 at 20:34
  • This will always happen if you are doing the auth client-side; to avoid this, you should do the authentication process in the backend with server-side render. – sebastian castaño jara Oct 02 '22 at 18:06
2

I don't know if this is the right way to do it but you don't actually need a private route component. You can just put all the private routes inside a component and render it conditionally as follows. In the below code, I put all the private routes inside the Private component and all the open routes inside the Public component.

function RootRouter() {

  return (
    <div>
      <Router>
        {isLoggedIn ? <PrivateRouter /> : <PublicRouter />}
      </Router>
    </div>
  );
}

function PrivateRouter(props) {
  return (
    <div>
      <ToastContainer autoClose={3000} hideProgressBar />
      <NavBar />
      <Routes>
        <Route path="/" exact element={<Home />} />
        <Route path="/add" element={<Add />} />
        <Route path="/update/:id" element={<Add />} />
        <Route path="/view/:id" element={<Employee />} />
      </Routes>
    </div>
  );
}

function PublicRouter() {
  return (
    <Routes>
      <Route path="/" element={<Login />} />
    </Routes>
  );
}

You can also use switch cases to allow access based on the role of the user.

Note: you dont have a create a seperate components, you can actually put all the routes in a single component and render it using same conditions.

1

By using replace attribute we prevent the user to use the Back browser button.

PrivateRoute.js

import { Navigate } from 'react-router-dom';

const PrivateRoute = ({ currentUser, children, redirectTo }) => {
  if (!currentUser) return <Navigate to={redirectTo} replace />;

  return children;
};

export default PrivateRoute;

Implementation:

<Routes>
   <Route path='signIn' element={
            <PrivateRoute currentUser={currentUser} redirectTo='/'>
              <SignInAndSignUpPage />
            </PrivateRoute>
          }
        />
<Routes/>
Hermeneutiker
  • 195
  • 1
  • 10
1

The correct way to write PrivateRoute code for version 6 of react-router-dom is as follows: The PrivateRoute.js file:

import React from "react";
import { Navigate } from "react-router-dom";
import { useAuth } from "./contexts/AuthContext";

export { PrivateRoute };

function PrivateRoute({ children }) {

const { currentUser } = useAuth();

if (!currentUser) {
    return <Navigate to="/" />
}
return children;
}

The Routing in App.js file:

import { Routes, Route, Navigate } from 'react-router-dom';

import { PrivateRoute } from '_components';
import { Home } from 'home';
import { Login } from 'login';

export { App };

function App() {
return (
    <div className="app-container bg-light">
        <div className="container pt-4 pb-4">
            <Routes>
            <Route
                    path="/"
                    element={
                        <PrivateRoute>
                            <Home />
                        </PrivateRoute>
                    }
                />
                <Route path="/login" element={<Login />} />
                <Route path="*" element={<Navigate to="/" />} />
            </Routes>
        </div>
    </div>
);
}
0

You could use auth-react-router package https://www.npmjs.com/package/auth-react-router

It provides a really simple API to define your routes and few more configurations (like redirect routes for authorized and unauthorized routes, fallback component for each of the routes)

usage:

  1. define routes
// routes.tsx

import React from 'react';
import { IRoutesConfig } from 'auth-react-router';
import LoginPage from '../pages/LoginPage.tsx';

// public lazy loaded pages
const LazyPublicPage = React.lazy(() => import('../pages/PublicPage.tsx'));

// private lazy loaded pages
const LazyPrivatePage = React.lazy(() => import('../pages/PrivatePage.tsx'));
const LazyProfilePage = React.lazy(() => import('../pages/ProfilePage.tsx'));


export const routes: IRoutesConfig = {
  publicRedirectRoute: '/profile', // redirect to `/profile` when authorized is trying to access public routes
  privateRedirectRoute: '/login', // redirect to `/login` when unauthorized user access a private route
  defaultFallback: <MyCustomSpinner />,
  public: [
    {
      path: '/public',
      component: <LazyPublicPage />,
    },
    {
      path: '/login',
      component: <LoginPage />,
    },
  ],
  private: [
    {
      path: '/private',
      component: <LazyPrivatePage />,
    },
    {
      path: '/profile',
      component: <LazyProfilePage />
    },
  ],
  common: [
    {
      path: '/',
      component: <p>common</p>,
    },
    {
      path: '*',
      component: <p>page not found 404</p>,
    },
  ],
};
  1. link them to your application
import { AppRouter, Routes } from 'auth-react-router';
import { BrowserRouter } from 'react-router-dom';
import { routes } from './routes';

export const App = () => {
  const { isAuth } = useAuthProvider();
  return (
    <BrowserRouter>
      <AppRouter isAuth={isAuth} routes={routes}>
        {/* Wrap `Routes` component into a Layout component or add Header */}
        <Routes />
      </AppRouter>
    </BrowserRouter>
  );
};
Nichita
  • 11
  • 1
  • 2
0

I tried to use all the above stated ways but don't know why nothing worked for me. Finally i solved it and here is my solution to the same:

First make one file of name AdminRoute.js in "routes" folder somewhere in src.

import { Typography } from "@mui/material";
import React, { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { Navigate } from "react-router-dom";
import { currentAdmin } from "../../functions/auth";
import LoadingToRedirect from "./LoadingToRedirect";

const AdminRoute = ({ children }) => {
  const { user } = useSelector((state) => ({
    ...state,
  }));
  const [ok, setOk] = useState(false);

  useEffect(() => {
    if (user && user.token) {
      currentAdmin(user.token)
        .then((res) => {
          console.log("CURRENT ADMIN RES", res);
          setOk(true);
        })
        .catch((err) => {
          console.log("ADMIN ROUTE ERR", err);
          setOk(false);
        });
    }
  }, [user]);
  return ok ? children : <LoadingToRedirect />;
};

export default AdminRoute;

Here you can have your own logic to decide when will user e redirected and when he will not.Like in my case i'm Checking if role of user is admin or not by making one api call.

Then make one LoadingToRedirect.js file in the same "routes" folder.

import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";

const LoadingToRedirect = () => {
  const [count, setCount] = useState(5);
  let navigate = useNavigate();

  useEffect(() => {
    const interval = setInterval(() => {
      setCount((currentCount) => --currentCount);
    }, 1000);
    // redirect once count is equal to 0
    count === 0 && navigate("/");
    // cleanup
    return () => clearInterval(interval);
  }, [count, navigate]);

  return (
    <div className="container p-5 text-center">
      <p>Redirecting you in {count} seconds</p>
    </div>
  );
};

export default LoadingToRedirect;

Now set up your App.js in your app.js:

Here when you go to '/check' url, the private route functionalities will come in action and it will check if the user is 'admin' or not.Here is the page which is to be protected and it acts as 'children' to

<Routes>
          <Route
            path="/check"
            element={
              <AdminRoute>
                <Check />
              </AdminRoute>
            }
          />

     
          <Route path="*" element={<NotFound />} />
        </Routes>

That's it You are ready to go. Cheers!!

0

This has worked for me.

const protectedPages = [
    { path: '/packages', page: <PackagesPage /> },
    { path: '/checkout', page: <CheckoutPage /> },
    { path: '/checkout/success', page: <CheckoutSuccessPage /> },
];

function App() {
    return (
        <BrowserRouter>
            <Routes>
                <Route path='/' element={<AuthPage />} />

                {/* Programmatically protect routes */}
                {protectedPages.map((p, i) => (
                    <Route
                        path={p.path}
                        element={<RequireAuth>{p.page}</RequireAuth>}
                        key={i}
                    />
                ))}

                <Route path='*' element={<PageNotFound />}></Route>
            </Routes>
        </BrowserRouter>
    );
}

const RequireAuth = ({ children }) => {
    const navigate = useNavigate();
    const { id } = useSelector(selectUser);

    React.useEffect(() => {
        if (!id) {
            navigate('/');
        }
    }, [id, navigate]);

    return children;
};

export default App;
emre-ozgun
  • 676
  • 1
  • 7
  • 17
0

if you want to remove route itself from main routes if user is not authenticated then u can use this

// dummy routes
const domainRoutes = [
  {
    index: true,
    path: "Profile",
    element: <Profile/>,
    hidden: true,
  },
  {
    path: "*",
    element: <AuthGuard />,
  },
];

// recursive function which remove routes from default which has hidden key as true, so if user tried to access routes that is not defined we can so then auth gurad or forbidden page

const Auth = ({ routes }) => {
  const removeisHiddenItems = (array) => {
    const validateHidden = (item) => {
      return item.isHidden;
    };
    return array.reduce((acc, item) => {
      // acc -> short for "accumulator" (array)
      // item -> the current array item
      if (validateHidden(item)) {
        return acc;
      } else if (item.children) {
        var children = removeisHiddenItems(item.children);
        if (children.length) acc.push(Object.assign({}, item, { children }));
      } else {
        if (!validateHidden(item)) {
          acc.push(item);
        }
      }
      return acc;
    }, []);
  };

  const filterRoutes = removeisHiddenItems(routes);
  const content = useRoutes(filterRoutes);
  return content;
};

const App = () => {
  return (
    <>
      <CssBaseline />
      <ThemeProvider theme={currentTheme}>
        <Auth routes={currentContent} />
      </ThemeProvider>
    </>
  );
};

export default App;
0

Instead of wrapping routes, you could use wrapper component like this:

index.js

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <StoreProvider>
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<App />}>
          <Route index element={<Home />} />
          <Route path="/login" element={<Login />} />
          <Route path="/register" element={<Registration />} />
          <Route path="/account" element={<Account />}>
            <Route index element={<AccountUser />} />
            <Route path="garage" element={<AccountGarage />} />
            <Route path="garage/addcar" element={<Guard component={<AddCar />} userRole="USER" />} />
            <Route path="garage/mycars" element={<Guard component={<MyCars />} userRole="USER" />} />
            <Route path="garage/addrepair" element={<Guard component={<AddRepair />} userRole="SERVICE" />} />
            <Route path="garage/myshop" element={<Guard component={<MyShop />} userRole="SERVICE" />} />
            <Route path="help" element={<AccountHelp />} />
            <Route path="settings" element={<AccountSettings />} />
          </Route>
          <Route path="/response" element={<Response />} />
          <Route path="password-reset/:token" element={<Reset />} />
          <Route path="*" element={<Navigate to="/" />} />
        </Route>
      </Routes>
    </BrowserRouter>
  </StoreProvider>

Guard.jsx

import React from 'react';
import { Navigate } from 'react-router-dom';
import { useStore } from '../utils/store';

export default function Guard({component, userRole}) {
    const [{ user: { role}},] = useStore();
    return role === userRole ? component : <Navigate to="/"/>
}
besthost
  • 759
  • 9
  • 14
0

Recently I was also faced with the problem of protecting the routes in react-router version 6. And I was using AUth0 for the user authentication process. So, I fixed that in 3 steps.

  1. Created a page of History.js and use createBrowserHistory-
import { createBrowserHistory } from "history";
export default createBrowserHistory();
  1. Then in PrivateRoute.js I checked if the use is logged in or not using "isAuthenticated"
  2. Then in App.js I used Route and Routes like this-
    <Routes>
        <Route path="/" exact element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/contact" element={<Contact />} />
        <Route path="/blog" element={<Posts />} />
        <Route element={<PrivateRoute/>}>
         <Route path="/dashboard" element={<Profile/>} />
              {/* Other Routes you want to protect */}
        </Route>
    </Routes>

Here I've documented that solution in my blog- Implementing Auth0 protected route