SyntaxStudy
Sign Up
React Protected Routes and Navigation Guards
React Beginner 1 min read

Protected Routes and Navigation Guards

A protected route is a route that redirects unauthenticated users to a login page instead of rendering the intended component. In React Router v6 the cleanest implementation is a wrapper component that checks authentication state and renders either an Outlet for authenticated users or a Navigate element that redirects to the login page. The Navigate component is the declarative counterpart to the useNavigate hook. Rendering it causes an immediate navigation as a side effect of rendering, which makes it suitable for redirect logic that must happen at the component level rather than inside an event handler. Preserving the originally requested URL in the redirect allows you to send the user back after a successful login. Pass the current location as state on the Navigate element, then read it with useLocation inside the login component and navigate to it after authentication succeeds.
Example
import {
    Navigate, Outlet, useLocation, useNavigate
} from 'react-router-dom';
import { useAuth } from './AuthContext';

// ── Guard component ────────────────────────────────────────────────────────
function RequireAuth() {
    const { user } = useAuth();
    const location = useLocation();

    if (!user) {
        // Redirect to /login, preserving the attempted URL
        return <Navigate to="/login" state={{ from: location }} replace />;
    }

    return <Outlet />;
}

// ── Route tree with protected section ─────────────────────────────────────
function App() {
    return (
        <BrowserRouter>
            <Routes>
                <Route path="/" element={<Layout />}>
                    <Route index element={<Home />} />
                    <Route path="login" element={<LoginPage />} />

                    {/* All routes inside here require auth */}
                    <Route element={<RequireAuth />}>
                        <Route path="dashboard" element={<Dashboard />} />
                        <Route path="settings"  element={<Settings />} />
                    </Route>
                </Route>
            </Routes>
        </BrowserRouter>
    );
}

// ── Login page redirects back to original URL ──────────────────────────────
function LoginPage() {
    const { login } = useAuth();
    const navigate  = useNavigate();
    const location  = useLocation();
    const from      = location.state?.from?.pathname ?? '/dashboard';

    async function handleSubmit(e) {
        e.preventDefault();
        await login({ email: e.target.email.value });
        navigate(from, { replace: true });
    }

    return (
        <form onSubmit={handleSubmit}>
            <input name="email" type="email" placeholder="Email" />
            <button type="submit">Sign in</button>
        </form>
    );
}