Skip to content
Rishan Solutions
Rishan Solutions
  • PowerApps
  • SharePoint online
    • Uncategorized
    • Uncategorized
  • PowerAutomate
Rishan Solutions
Latest Posts
  • Agentic AI: The Dawn of Autonomous Intelligence Revolutionizing 2025 June 24, 2025
  • Recursive Queries in T-SQL May 7, 2025
  • Generating Test Data with CROSS JOIN May 7, 2025
  • Working with Hierarchical Data May 7, 2025
  • Using TRY_CAST vs CAST May 7, 2025
  • Dynamic SQL Execution with sp_executesql May 7, 2025

Handling private routes incorrectly

Posted on April 2, 2025April 2, 2025 by Rishan Solutions

Loading

Proper Implementation of Private Routes in React Router

A common security and UX issue in React applications is the incorrect implementation of private routes, which should protect authenticated-only content. Here’s how to properly handle authentication and route protection.

The Core Problem

Typical incorrect implementations:

// ❌ Insecure: Just hiding the link doesn't protect the route
{isLoggedIn && <Link to="/dashboard">Dashboard</Link>}

// ❌ Incomplete: Only checking on initial render
function PrivateRoute() {
  const [isAuth] = useState(checkAuth());
  return isAuth ? <Outlet /> : <Navigate to="/login" />;
}

Correct Implementation (React Router v6)

1. Basic Private Route Component

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

function PrivateRoute() {
  const { currentUser } = useAuth(); // Your auth context/hook

  return currentUser ? <Outlet /> : <Navigate to="/login" replace />;
}

2. Usage in Route Configuration

<Routes>
  <Route path="/" element={<PublicLayout />}>
    <Route index element={<HomePage />} />
    <Route path="login" element={<LoginPage />} />
  </Route>

  <Route element={<PrivateRoute />}> {/* Wrap protected routes */}
    <Route path="dashboard" element={<Dashboard />} />
    <Route path="profile" element={<UserProfile />} />
  </Route>
</Routes>

Key Features of a Secure Private Route

  1. Authentication Check: Verifies user is logged in
  2. Redirect: Sends unauthorized users to login
  3. State Preservation: Remembers where user came from
  4. Route Protection: Guards both UI and data layers

Advanced Patterns

1. Route-Specific Permissions

function AdminRoute() {
  const { currentUser } = useAuth();

  if (!currentUser) {
    return <Navigate to="/login" replace state={{ from: location }} />;
  }

  if (!currentUser.isAdmin) {
    return <Navigate to="/unauthorized" replace />;
  }

  return <Outlet />;
}

2. Persistent Session Check

function PrivateRoute() {
  const { currentUser, isLoading } = useAuth();
  const location = useLocation();

  if (isLoading) {
    return <LoadingSpinner />;
  }

  if (!currentUser) {
    return <Navigate to="/login" replace state={{ from: location }} />;
  }

  return <Outlet />;
}

3. Protected Data Fetching

function Dashboard() {
  const { data, error } = useProtectedQuery('/api/dashboard');

  if (error?.status === 401) {
    return <Navigate to="/login" replace />;
  }

  // Render dashboard
}

Common Mistakes to Avoid

❌ Client-Side Only Protection

// ❌ Server still returns data if API is unprotected
function PrivateComponent() {
  if (!user) return <Navigate to="/login" />;
  return <SecretData />;
}

✅ Fix: Protect both client and server

// Client
<Route element={<PrivateRoute />}>
  <Route path="secret" element={<SecretData />} />
</Route>

// Server
router.get('/api/secret', authenticate, (req, res) => {
  // Return data only if authenticated
});

❌ Not Persisting Return URL

<Navigate to="/login" /> {/* ❌ Loses original location */}

✅ Fix: Preserve navigation state

<Navigate 
  to="/login" 
  replace 
  state={{ from: location }} 
/>

❌ Blocking Render During Auth Check

function PrivateRoute() {
  const { user } = useAuth(); // Synchronous check

  // ❌ Fails if auth requires async verification
  return user ? <Outlet /> : <Navigate to="/login" />;
}

✅ Fix: Handle loading state

function PrivateRoute() {
  const { user, isLoading } = useAuth();

  if (isLoading) return <LoadingScreen />;
  return user ? <Outlet /> : <Navigate to="/login" />;
}

Complete Authentication Flow

// App.js
function App() {
  return (
    <AuthProvider>
      <Router>
        <Routes>
          <Route path="/login" element={<LoginPage />} />
          <Route element={<PrivateRoute />}>
            <Route path="/dashboard" element={<Dashboard />} />
          </Route>
        </Routes>
      </Router>
    </AuthProvider>
  );
}

// PrivateRoute.js
function PrivateRoute() {
  const { user, loading } = useAuth();
  const location = useLocation();

  if (loading) return <LoadingSpinner />;

  if (!user) {
    return (
      <Navigate 
        to="/login" 
        replace 
        state={{ 
          from: location,
          message: "Please log in to continue"
        }} 
      />
    );
  }

  return <Outlet />;
}

// LoginPage.js
function LoginPage() {
  const { login } = useAuth();
  const location = useLocation();
  const from = location.state?.from?.pathname || "/";

  const handleSubmit = async () => {
    await login(credentials);
    // After login, redirect to where user came from
    navigate(from, { replace: true });
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* Login form */}
    </form>
  );
}

Security Best Practices

  1. Server-Side Validation: Never trust client-side checks alone
  2. Secure Cookies: Use HttpOnly, SameSite, and Secure flags
  3. Token Expiration: Implement JWT expiration and refresh
  4. Rate Limiting: Protect authentication endpoints
  5. CSRF Protection: Especially for cookie-based auth

Key Takeaways

  1. Use <PrivateRoute> wrapper for protected route hierarchies
  2. Preserve navigation state for post-login redirects
  3. Protect both UI and API layers
  4. Handle loading states during auth verification
  5. Implement proper error handling for expired sessions

Proper private route implementation is essential for both security and user experience in React applications. Following these patterns ensures authenticated users access protected content while unauthorized users are redirected appropriately.

Posted Under ReactJSAuthentication Authorization client-side routing login flow navigation security private routes React react best practices React Router v6 Role-Based Access route guards Route Management routing errors Secure Routes

Post navigation

Preventing XSS attacks in jQuery
$(‘#input’).val() returning undefined – Check if the input element exists.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • Agentic AI: The Dawn of Autonomous Intelligence Revolutionizing 2025
  • Recursive Queries in T-SQL
  • Generating Test Data with CROSS JOIN
  • Working with Hierarchical Data
  • Using TRY_CAST vs CAST

Recent Comments

  1. Michael Francis on Search , Filter and Lookup in power apps
  2. A WordPress Commenter on Hello world!

Archives

  • June 2025
  • May 2025
  • April 2025
  • March 2025
  • February 2025
  • March 2024
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • June 2023
  • May 2023
  • April 2023
  • February 2023
  • January 2023
  • December 2022
  • November 2022
  • October 2022
  • January 2022

Categories

  • Active Directory
  • AI
  • AngularJS
  • Blockchain
  • Button
  • Buttons
  • Choice Column
  • Cloud
  • Cloud Computing
  • Data Science
  • Distribution List
  • DotNet
  • Dynamics365
  • Excel Desktop
  • Extended Reality (XR) – AR, VR, MR
  • Gallery
  • Icons
  • IoT
  • Java
  • Java Script
  • jQuery
  • Microsoft Teams
  • ML
  • MS Excel
  • MS Office 365
  • MS Word
  • Office 365
  • Outlook
  • PDF File
  • PNP PowerShell
  • Power BI
  • Power Pages
  • Power Platform
  • Power Virtual Agent
  • PowerApps
  • PowerAutomate
  • PowerPoint Desktop
  • PVA
  • Python
  • Quantum Computing
  • Radio button
  • ReactJS
  • Security Groups
  • SharePoint Document library
  • SharePoint online
  • SharePoint onpremise
  • SQL
  • SQL Server
  • Template
  • Uncategorized
  • Variable
  • Visio
  • Visual Studio code
  • Windows
© Rishan Solutions 2025 | Designed by PixaHive.com.
  • Rishan Solutions