← Back to React Course | Chapter 8: Routing | Lesson 8 of 10

Protected/Private Routes

A protected route is like a bouncer at a club door — it checks if you're allowed in before letting you see what's inside, and sends you elsewhere if not.

Building a RequireAuth Wrapper

A RequireAuth component checks whether the user is authenticated, and either renders its children (the protected page) or redirects elsewhere. Wrapping a Route's element in this component blocks direct URL access to protected pages, not just hiding a link to them.

Note: Keep the auth check itself (isLoggedIn) in a single shared place, like a Context, so RequireAuth and the rest of the app agree on the current status.

Warning: Hiding a nav link to a protected page isn't real protection — anyone can still type the URL directly unless the route itself checks auth.

Example: Building a RequireAuth Wrapper

markup
// Run in your local React project (npm install required)
import { Navigate } from 'react-router-dom';

function RequireAuth({ isLoggedIn, children }) {
  if (!isLoggedIn) return <Navigate to="/login" replace />;
  return children;
}

⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.

Using Navigate for Declarative Redirects

The Navigate component performs a redirect as part of what it renders, rather than calling an imperative function like useNavigate(). Rendering <Navigate to='/login' /> immediately redirects the browser to /login — useful inside conditional JSX like the RequireAuth wrapper.

Note: Use the replace prop on Navigate for redirects (like auth checks) that shouldn't leave a phantom entry in browser history.

Warning: Navigate causes a redirect on every render where its condition is true — make sure the surrounding condition only renders it when actually needed.

Example: Using Navigate for Declarative Redirects

markup
// Run in your local React project (npm install required)
import { Routes, Route, Navigate } from 'react-router-dom';

function Dashboard({ isLoggedIn }) {
  if (!isLoggedIn) return <Navigate to="/login" />;
  return <p>Welcome to your dashboard</p>;
}

⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.

Wrapping a Protected Route in the Route Tree

Combining RequireAuth with your route definitions means wrapping a protected page's element in <RequireAuth>...</RequireAuth> right in the Route declaration. This keeps the auth check colocated with the routing configuration, easy to see at a glance which routes are protected.

Note: For many protected routes, consider wrapping a whole group of them under one parent RequireAuth route using nested routes, instead of repeating the wrapper on every single one.

Warning: isLoggedIn must come from real, verified state (like a token check), not just a client-side flag that could be trivially spoofed.

Example: Wrapping a Protected Route in the Route Tree

markup
// Run in your local React project (npm install required)
import { Routes, Route } from 'react-router-dom';

function RequireAuth({ isLoggedIn, children }) {
  return isLoggedIn ? children : <p>Redirecting to login...</p>;
}
function Dashboard() { return <p>Protected dashboard content</p>; }

function AppRoutes({ isLoggedIn }) {
  return (
    <Routes>
      <Route path="/dashboard" element={<RequireAuth isLoggedIn={isLoggedIn}><Dashboard /></RequireAuth>} />
    </Routes>
  );
}

⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.

Common Mistakes
  1. Only hiding the link to a protected page, without actually blocking direct URL access to it.
  2. Checking authentication status after the protected content has already briefly rendered, causing a flash of private content.
  3. Forgetting to preserve the originally-requested URL so the user lands back there after logging in.
Chapter Summary
  • A protected route wraps its element in a check that redirects unauthenticated users elsewhere.
  • This is commonly built as a small wrapper component checking a boolean (like isLoggedIn) before rendering its children.
  • The Navigate component performs a redirect declaratively, as part of what a component renders.
  • True security still requires server-side checks — client-side route protection only controls the UI.
Browser Support

Requires npm install react-router-dom — not available via CDN in this sandbox.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.