Part 29: Protected Routes & Authentication Guards
Restricting access to private pages (user dashboards, account settings, checkout) based on authentication status is a critical requirement for production web applications.
1. Creating a ProtectedRoute Wrapper
import { Navigate, useLocation, Outlet } from 'react-router-dom';
export default function ProtectedRoute({ isAuthenticated, userRole, allowedRoles }) {
const location = useLocation();
// If not authenticated, redirect to login and preserve the attempted URL
if (!isAuthenticated) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
// Optional: Role-based access control
if (allowedRoles && !allowedRoles.includes(userRole)) {
return <Navigate to="/unauthorized" replace />;
}
// Render the protected route's child elements
return <Outlet />;
}
2. Protecting Entire Route Trees
import { Routes, Route } from 'react-router-dom';
import ProtectedRoute from './ProtectedRoute';
export default function App({ user }) {
const isAuthenticated = Boolean(user);
return (
<Routes>
{/* Public Routes */}
<Route path="/" element={<HomePage />} />
<Route path="/login" element={<LoginPage />} />
{/* Protected Routes */}
<Route element={<ProtectedRoute isAuthenticated={isAuthenticated} />}>
<Route path="/dashboard" element={<DashboardPage />} />
<Route path="/profile" element={<ProfilePage />} />
</Route>
</Routes>
);
}
3. Redirecting Back After Login
Inside your LoginPage:
import { useNavigate, useLocation } from 'react-router-dom';
export default function LoginPage({ onLogin }) {
const navigate = useNavigate();
const location = useLocation();
// Return to the page the user originally tried to visit, or fallback to '/'
const from = location.state?.from?.pathname || '/dashboard';
const handleLogin = () => {
onLogin();
navigate(from, { replace: true });
};
return <button onClick={handleLogin}>Log In</button>;
}
Key Takeaways
- Wrap private views in a
ProtectedRoutecomponent that checks authentication status. - Save
locationin state to redirect users back to their intended destination after signing in. - Use
<Navigate replace />to avoid trapping users in infinite redirect loops.
In Part 30, we enter Module 5 to explore State Management Architecture: Local vs Global vs Server State!

