How to Secure React Router in React

Securing routes in a React application is essential for protecting sensitive data and ensuring that only authorized users can access specific pages. This article provides a direct, step-by-step guide on how to secure React Router (v6) by implementing a reusable Protected Route component, handling authentication states, and setting up role-based access control.

1. Understanding the Protected Route Pattern

React Router does not have built-in security features. Instead, securing routes relies on a pattern called Protected Routes. This involves creating a wrapper component that checks the user’s authentication status. If the user is authenticated, the component renders the requested page; if not, it redirects them to a login page.

2. Creating a Protected Route Component

Using React Router v6, you can create a ProtectedRoute component using the <Navigate /> component and the <Outlet /> layout component.

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

const ProtectedRoute = ({ isAuthenticated }) => {
  if (!isAuthenticated) {
    // Redirect unauthorized users to the login page
    return <Navigate to="/login" replace />;
  }

  // Render child routes if authenticated
  return <Outlet />;
};

export default ProtectedRoute;

In this component: * isAuthenticated is a boolean passed from your application’s authentication state (e.g., Context, Redux, or a custom hook). * <Navigate to="/login" replace /> redirects the user while replacing the current entry in the history stack, preventing them from clicking “back” into a secured page. * <Outlet /> renders the child routes defined inside this route path.

3. Implementing Protected Routes in Your App Router

Once the ProtectedRoute component is created, wrap your private routes with it in your main router configuration.

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { useState } from 'react';
import ProtectedRoute from './ProtectedRoute';
import Home from './pages/Home';
import Login from './pages/Login';
import Dashboard from './pages/Dashboard';
import Settings from './pages/Settings';

function App() {
  // Replace this with your actual authentication state/context hook
  const [isAuthenticated, setIsAuthenticated] = useState(false);

  return (
    <Router>
      <Routes>
        {/* Public Routes */}
        <Route path="/" element={<Home />} />
        <Route path="/login" element={<Login />} />

        {/* Secured Routes */}
        <Route element={<ProtectedRoute isAuthenticated={isAuthenticated} />}>
          <Route path="/dashboard" element={<Dashboard />} />
          <Route path="/settings" element={<Settings />} />
        </Route>
      </Routes>
    </Router>
  );
}

export default App;

By nesting the /dashboard and /settings routes inside the ProtectedRoute route, they are automatically shielded by the authentication check.

4. Implementing Role-Based Access Control (RBAC)

If your application has different user permissions (e.g., Admin vs. User), you can expand the protected route component to check for user roles.

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

const RoleProtectedRoute = ({ isAuthenticated, userRole, allowedRoles }) => {
  if (!isAuthenticated) {
    return <Navigate to="/login" replace />;
  }

  if (!allowedRoles.includes(userRole)) {
    return <Navigate to="/unauthorized" replace />;
  }

  return <Outlet />;
};

export default RoleProtectedRoute;

You can then apply this in your router like this:

<Route 
  element={
    <RoleProtectedRoute 
      isAuthenticated={isAuthenticated} 
      userRole={userRole} 
      allowedRoles={['admin']} 
    />
  }
>
  <Route path="/admin-panel" element={<AdminPanel />} />
</Route>

A Crucial Security Reminder

Client-side routing protection is entirely for user experience (UX). It prevents users from seeing UI components they shouldn’t access. However, because client-side JavaScript can be manipulated, true security must always be enforced on your backend server. Ensure all API endpoints requested by your React application validate session tokens or JWTs before returning sensitive data.