Back to Blog
Lesson 19 of the Intermediate React: Hooks, State & Data Patterns course
ReactJune 26, 20263 min read

Protected Routes for Authenticated Views in React

Learn to implement protected routes in your React application. We'll show you how to guard dashboard pages and redirect unauthenticated users securely.

reactreact-routerauthenticationsecurityweb-developmentjavascriptfrontend

Previously in this course, we covered Introduction to React Router: Building Multi-Page SPAs and established a robust way of Handling Authentication State with React Context API. Now, we need to bridge these two concepts.

Even if your UI hides navigation links for logged-out users, a determined user can still type a URL directly into their browser to reach a private dashboard. To ensure real security, we need to implement protected routes—a pattern that acts as a gatekeeper for your component tree.

The Protected Route Pattern

From first principles, a protected route is simply a higher-order wrapper component. Instead of rendering your private components (like Dashboard or Settings) directly in your router configuration, you pass them through a "guard" component that checks the authentication state.

If the user is authenticated, the guard renders the requested page. If not, it redirects the user to the login screen.

Creating the Guard Component

We will create a ProtectedRoute component that consumes our AuthContext. This component will leverage the Navigate component provided by react-router-dom to handle the redirect logic.

JSX
import { Navigate, useLocation } from CE9178">'react-router-dom';
import { useAuth } from CE9178">'./AuthProvider'; // Our custom hook from previous lessons

const ProtectedRoute = ({ children }) => {
  const { isAuthenticated, isLoading } = useAuth();
  const location = useLocation();

  // 1. Handle loading state to prevent flickering
  if (isLoading) {
    return <div>Loading authentication...</div>;
  }

  // 2. Redirect if not authenticated
  if (!isAuthenticated) {
    // We pass the current location so we can redirect back after login
    return <Navigate to="/login" state={{ from: location }} replace />;
  }

  // 3. Render the child component if authenticated
  return children;
};

Implementing in the Router

Now that we have our guard, we integrate it into our main routing configuration. Following the principles from Nested Routes and Layouts: Mastering React Router UI Design, we can wrap entire sections of our app.

JSX
import { BrowserRouter, Routes, Route } from CE9178">'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/login" element={<Login />} />
        
        {/* Protected routes wrapped in the guard */}
        <Route 
          path="/dashboard/*" 
          element={
            <ProtectedRoute>
              <DashboardLayout />
            </ProtectedRoute>
          } 
        />
      </Routes>
    </BrowserRouter>
  );
}

Hands-on Exercise

  1. Create the file: Create a new file named ProtectedRoute.jsx.
  2. Logic Implementation: Implement the ProtectedRoute component shown above.
  3. Integrate: Update your App.js router to wrap your Dashboard route with this component.
  4. Verification: Log out of your application, attempt to navigate to /dashboard/settings, and verify that you are redirected to /login.

Common Pitfalls

  • Forgetting the Loading State: If your AuthContext checks a server or local storage asynchronously, the isAuthenticated flag might be false for a split second on page load. If you don't check for an isLoading state, your app will flicker and redirect users to the login page even when they are properly signed in.
  • Infinite Redirects: Ensure your Login route is not wrapped in a ProtectedRoute. If it is, the app will try to redirect the login page to the login page, creating an infinite loop.
  • Client-side vs. Server-side: Remember that client-side protection is for user experience. Always enforce authentication on your API endpoints as well. Never trust the client to be the sole source of truth for security.

By implementing these protected routes, you prevent unauthorized access to your dashboard views and ensure a consistent, secure flow for your users. This pattern is the standard way to handle private areas in a React single-page application.

Up next, we will explore Programmatic Navigation to handle redirects after login and logout events.

Similar Posts