In my eight years of developing React applications, one of the most frequent tasks I’ve faced is managing user access.
Whether it is a private dashboard for a US-based fintech app or a secure medical portal, you need a way to keep unauthorized users out.
In this tutorial, I will show you exactly how I built a ProtectedRoute component. We will cover the modern way to do it using React Router v6.
I’ll also share a few different methods I’ve used in production environments to ensure data stays secure.
Why You Need Protected Routes
In a standard web application, some pages are public, like your “Login” or “About Us” page.
However, pages like “User Profile” or “Settings” should only be visible to someone who has logged in.
A Protected Route acts as a digital bouncer. It checks if the user is authenticated before letting them see the content.
Method 1: The Standard Wrapper Component Pattern
This is my go-to method for most projects. It involves creating a wrapper component that checks for an authentication token.
If the token exists, we render the child components. If not, we redirect the user to the login page.
Below is a complete example. I’ve used a mock authentication hook to simulate a real-world US banking dashboard scenario.
import React, { useState, createContext, useContext } from 'react';
import {
BrowserRouter as Router,
Routes,
Route,
Navigate,
Link,
useLocation
} from 'react-router-dom';
// 1. Create a Simple Auth Context
const AuthContext = createContext(null);
const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const login = () => setUser({ name: "Alex", role: "admin" });
const logout = () => setUser(null);
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
};
const useAuth = () => useContext(AuthContext);
// 2. The ProtectedRoute Component
const ProtectedRoute = ({ children }) => {
const { user } = useAuth();
const location = useLocation();
if (!user) {
// Redirect them to the /login page, but save the current location they were
// trying to go to. This allows us to send them back after they login.
return <Navigate to="/login" state={{ from: location }} replace />;
}
return children;
};
// 3. Application Components
const Navigation = () => {
const { user, logout } = useAuth();
return (
<nav style={{ padding: '10px', borderBottom: '1px solid #ccc' }}>
<Link to="/">Home</Link> |
<Link to="/dashboard"> Wealth Dashboard</Link> |
{user ? (
<button onClick={logout} style={{ marginLeft: '10px' }}>Sign Out</button>
) : (
<Link to="/login" style={{ marginLeft: '10px' }}>Sign In</Link>
)}
</nav>
);
};
const Home = () => <h2>Welcome to NYC Federal Credit Union</h2>;
const Login = () => {
const { login } = useAuth();
return (
<div>
<h2>Secure Login</h2>
<button onClick={login}>Log in to view your accounts</button>
</div>
);
};
const Dashboard = () => (
<div>
<h2>Your Wealth Dashboard</h2>
<p>Savings Account: $45,230.12</p>
<p>401(k) Balance: $120,450.00</p>
</div>
);
// 4. Main App Setup
export default function App() {
return (
<AuthProvider>
<Router>
<Navigation />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
{/* Wrap the protected component */}
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
</Routes>
</Router>
</AuthProvider>
);
}I executed the above example code and added the screenshot below.

I use the useLocation hook to remember where the user was trying to go. This is a professional touch that US users expect; nobody likes being kicked back to the homepage after logging in.
The replace prop in the Maps component ensures the login page isn’t saved in the browser history, preventing back-button loops.
Method 2: Use the “Outlet” Pattern for Nested Routes
In larger React applications, I often prefer using an Outlet. This is cleaner when you have many protected pages.
Instead of wrapping every single route, you create a parent layout that handles the security check for all its children.
Here is how I set up a secure layout for a California-based Real Estate Management tool.
import React from 'react';
import {
BrowserRouter as Router,
Routes,
Route,
Navigate,
Outlet
} from 'react-router-dom';
// Simulated Auth Hook
const useAuth = () => {
// In a real app, check localStorage or a cookie here
const token = localStorage.getItem("sf_property_token");
return { isAuthenticated: !!token };
};
const ProtectedLayout = () => {
const { isAuthenticated } = useAuth();
if (!isAuthenticated) {
return <Navigate to="/auth" replace />;
}
return (
<div className="dashboard-container">
<aside>Sidebar Navigation</aside>
<main>
{/* Outlet renders the child routes */}
<Outlet />
</main>
</div>
);
};
const PropertyList = () => <h2>San Francisco Property Listings</h2>;
const RevenueReport = () => <h2>Quarterly Revenue - Q3 2026</h2>;
export default function RealEstateApp() {
return (
<Router>
<Routes>
<Route path="/auth" element={<div>Please Login</div>} />
{/* Protected Group */}
<Route element={<ProtectedLayout />}>
<Route path="/properties" element={<PropertyList />} />
<Route path="/reports" element={<RevenueReport />} />
</Route>
<Route path="*" element={<h2>404 - Not Found</h2>} />
</Routes>
</Router>
);
}I executed the above example code and added the screenshot below.

In my experience, this is much easier to maintain as your app grows from 5 routes to 50. You only have one place to manage your protection logic, making the code much more “DRY” (Don’t Repeat Yourself).
It also makes it simple to add common UI elements, like a sidebar or a header, only for authorized users.
Method 3: Role-Based Access Control (RBAC)
Sometimes just being “logged in” isn’t enough. You might have “Users” and “Admins.”
In many US corporate applications, an HR manager needs different access than a standard employee.
This example demonstrates how to check for specific roles before granting access.
import React from 'react';
import { Navigate, Outlet } from 'react-router-dom';
const RoleProtectedRoute = ({ allowedRoles }) => {
// Mocking a user with a specific role
const user = {
name: "Jordan",
role: "manager" // This would normally come from your Global State
};
const isAuthorized = allowedRoles.includes(user.role);
if (!user) {
return <Navigate to="/login" replace />;
}
if (!isAuthorized) {
return <Navigate to="/unauthorized" replace />;
}
return <Outlet />;
};
// Usage in App.js
// <Route element={<RoleProtectedRoute allowedRoles={['admin', 'manager']} />}>
// <Route path="/payroll" element={<PayrollData />} />
// </Route>Handle Unauthorized Access
I always recommend redirecting to a specific “Unauthorized” page rather than back to Login.
This prevents user confusion when they are logged in but simply don’t have the right permissions.
It is a small detail that significantly improves the user experience in professional software.
Important Things to Consider
While client-side protected routes are great for UX, they are not a replacement for backend security.
A savvy user can always modify the React state in their browser to “see” a component.
Always ensure your API endpoints are also protected with JWT tokens or session cookies.
Testing Your Protected Routes
I always suggest testing two main scenarios during development.
First, try to manually type the URL of a protected page in your browser while logged out.
Second, log in, then click the back button to see if you are redirected incorrectly.
Building a robust ProtectedRoute component is a foundational skill for any React developer.
Whether you use the wrapper pattern or the layout pattern, the goal is always to provide a seamless and secure experience for your users.
I hope you found this tutorial helpful! If you’re building an app for users in the US or anywhere else, these patterns will serve you well.
You may also like to read:
- Custom Component Mapping in React Markdown
- Mantine React Component Library
- React Toggle Switch Component
- How to Use Await in React Components

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.