Introduction
Protected Routes are used in React applications to restrict certain pages to authenticated users. For example, a dashboard or profile page may only be available after login. React Router can work with authentication state to decide whether a user should see a page or be redirected to a login page. In this chapter, we will solve practical Protected Route questions using React Router, authentication state, Navigate, Context API, and loading states. React js Protected Routes Practice Questions with Solutions to help you understand the concepts.
1. What are Protected Routes in React?
A Protected Route is a route that checks whether a user is allowed to access a particular page.
For example:
User
↓
Dashboard Route
↓
Is user authenticated?
├── Yes → Show Dashboard
└── No → Go to Login
A simple protected route can look like this:
import { Navigate } from "react-router-dom";
function ProtectedRoute({ isLoggedIn, children }) {
if (!isLoggedIn) {
return <Navigate to="/login" replace />;
}
return children;
}
export default ProtectedRoute;
If isLoggedIn is false, the user is redirected to /login.
If it is true, the protected content is displayed.
2. Create a Basic Protected Route
Let’s create a simple application with Login and Dashboard pages.
import {
BrowserRouter,
Routes,
Route,
Navigate
} from "react-router-dom";
function Login() {
return <h2>Login Page</h2>;
}
function Dashboard() {
return <h2>Dashboard Page</h2>;
}
function ProtectedRoute({ isLoggedIn, children }) {
if (!isLoggedIn) {
return <Navigate to="/login" replace />;
}
return children;
}
function App() {
const isLoggedIn = false;
return (
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route
path="/dashboard"
element={
<ProtectedRoute isLoggedIn={isLoggedIn}>
<Dashboard />
</ProtectedRoute>
}
/>
</Routes>
</BrowserRouter>
);
}
export default App;
When:
const isLoggedIn = false;
the user visiting /dashboard is redirected to:
/login
When:
const isLoggedIn = true;
the Dashboard is displayed.
3. Use Navigate for Redirecting Unauthenticated Users
React Router provides the Navigate component for declarative navigation.
import { Navigate } from "react-router-dom";
function ProtectedRoute({ isLoggedIn, children }) {
if (!isLoggedIn) {
return <Navigate to="/login" replace />;
}
return children;
}
The important part is:
<Navigate to="/login" replace />
This tells React Router to navigate to the login page.
The replace option replaces the current history entry instead of adding another one.
This can help prevent the browser Back button from immediately returning to the blocked route.
4. Create a Protected Route Using Authentication Context
If many components need authentication information, Context API can provide it.
import {
createContext,
useContext,
useState
} from "react";
const AuthContext = createContext(null);
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
function login() {
setUser({
name: "Rahul"
});
}
function logout() {
setUser(null);
}
return (
<AuthContext.Provider
value={{ user, login, logout }}
>
{children}
</AuthContext.Provider>
);
}
function useAuth() {
return useContext(AuthContext);
}
Now we can create a protected route:
import { Navigate } from "react-router-dom";
function ProtectedRoute({ children }) {
const { user } = useAuth();
if (!user) {
return <Navigate to="/login" replace />;
}
return children;
}
The route does not need an isLoggedIn prop.
Instead, it reads the current authentication state from Context.
5. Redirect to Login When the User Is Not Authenticated
Let’s create a complete route example.
import {
BrowserRouter,
Routes,
Route,
Navigate
} from "react-router-dom";
function Login() {
return <h2>Login Page</h2>;
}
function Dashboard() {
return <h2>Dashboard</h2>;
}
function ProtectedRoute({ isLoggedIn, children }) {
if (!isLoggedIn) {
return <Navigate to="/login" replace />;
}
return children;
}
function App() {
const isLoggedIn = false;
return (
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route
path="/dashboard"
element={
<ProtectedRoute isLoggedIn={isLoggedIn}>
<Dashboard />
</ProtectedRoute>
}
/>
<Route
path="*"
element={<Navigate to="/dashboard" replace />}
/>
</Routes>
</BrowserRouter>
);
}
export default App;
Now:
/dashboard
↓
ProtectedRoute
↓
Not logged in
↓
/login
The protected route decides whether the user can continue.
6. Protect Multiple Routes with One Protected Route Component
The same ProtectedRoute component can protect multiple pages.
<Routes>
<Route path="/login" element={<Login />} />
<Route
path="/dashboard"
element={
<ProtectedRoute isLoggedIn={isLoggedIn}>
<Dashboard />
</ProtectedRoute>
}
/>
<Route
path="/profile"
element={
<ProtectedRoute isLoggedIn={isLoggedIn}>
<Profile />
</ProtectedRoute>
}
/>
<Route
path="/settings"
element={
<ProtectedRoute isLoggedIn={isLoggedIn}>
<Settings />
</ProtectedRoute>
}
/>
</Routes>
Now all three pages require authentication:
/dashboard
/profile
/settings
This avoids repeating authentication-checking logic inside every page component.
7. Protect Nested Routes with an Outlet
For multiple protected child routes, Outlet can make the structure cleaner.
import {
Navigate,
Outlet
} from "react-router-dom";
function ProtectedLayout({ isLoggedIn }) {
if (!isLoggedIn) {
return <Navigate to="/login" replace />;
}
return <Outlet />;
}
Routes:
<Routes>
<Route path="/login" element={<Login />} />
<Route
element={
<ProtectedLayout isLoggedIn={true} />
}
>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
<Route path="/settings" element={<Settings />} />
</Route>
</Routes>
Here, ProtectedLayout checks authentication once.
The <Outlet /> renders whichever protected child route matches.
This is especially useful when an application has many protected routes.
8. Add a Loading State Before Checking Authentication
Sometimes authentication status is not immediately known.
For example, an application may need to check an existing session with a backend.
We should not immediately redirect the user before that check finishes.
import {
Navigate,
Outlet
} from "react-router-dom";
function ProtectedLayout({
user,
loading
}) {
if (loading) {
return <h2>Checking authentication...</h2>;
}
if (!user) {
return <Navigate to="/login" replace />;
}
return <Outlet />;
}
There are now three states:
Loading
↓
Checking session
↓
┌───────────────┐
↓ ↓
Authenticated Not Authenticated
↓ ↓
App Login
The loading state prevents an incorrect redirect while authentication information is still being checked.
9. Redirect the User Back to the Original Page After Login
Sometimes a user visits a protected page directly.
For example:
/dashboard
They are redirected to:
/login
After successful login, it can be useful to send them back to /dashboard.
React Router allows location information to be passed during navigation.
import {
Navigate,
useLocation
} from "react-router-dom";
function ProtectedRoute({ isLoggedIn, children }) {
const location = useLocation();
if (!isLoggedIn) {
return (
<Navigate
to="/login"
replace
state={{ from: location }}
/>
);
}
return children;
}
The login page can read that location:
import {
useLocation,
useNavigate
} from "react-router-dom";
function Login() {
const location = useLocation();
const navigate = useNavigate();
function handleLogin() {
const destination =
location.state?.from?.pathname || "/dashboard";
navigate(destination, { replace: true });
}
return (
<button onClick={handleLogin}>
Login
</button>
);
}
Now the flow can be:
User visits /dashboard
↓
Not authenticated
↓
Redirect to /login
↓
User logs in
↓
Return to /dashboard
This provides a better user experience.
10. Build a Practical Protected Dashboard
Let’s combine authentication state, React Router, login, logout, and protected routes.
import { useState } from "react";
import {
BrowserRouter,
Routes,
Route,
Navigate,
Link
} from "react-router-dom";
function Login({ onLogin }) {
return (
<div>
<h2>Login</h2>
<button onClick={onLogin}>
Login
</button>
</div>
);
}
function Dashboard({ onLogout }) {
return (
<div>
<h2>Dashboard</h2>
<p>Welcome to your private dashboard.</p>
<Link to="/profile">
Profile
</Link>
<br />
<button onClick={onLogout}>
Logout
</button>
</div>
);
}
function Profile() {
return (
<div>
<h2>Profile</h2>
<p>This page is protected.</p>
</div>
);
}
function ProtectedRoute({ isLoggedIn, children }) {
if (!isLoggedIn) {
return <Navigate to="/login" replace />;
}
return children;
}
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
function login() {
setIsLoggedIn(true);
}
function logout() {
setIsLoggedIn(false);
}
return (
<BrowserRouter>
<Routes>
<Route
path="/login"
element={
isLoggedIn ? (
<Navigate to="/dashboard" replace />
) : (
<Login onLogin={login} />
)
}
/>
<Route
path="/dashboard"
element={
<ProtectedRoute isLoggedIn={isLoggedIn}>
<Dashboard onLogout={logout} />
</ProtectedRoute>
}
/>
<Route
path="/profile"
element={
<ProtectedRoute isLoggedIn={isLoggedIn}>
<Profile />
</ProtectedRoute>
}
/>
<Route
path="*"
element={
<Navigate to="/dashboard" replace />
}
/>
</Routes>
</BrowserRouter>
);
}
export default App;
How it works
- The application starts with
isLoggedInasfalse. - The user sees the Login page.
- Clicking Login changes the authentication state.
- The user can access
/dashboard. - The user can also access
/profile. - If an unauthenticated user directly visits
/dashboard,ProtectedRouteredirects them to/login. - Clicking Logout changes
isLoggedInback tofalse. - Protected pages become inaccessible again.
This example demonstrates the routing pattern. In a production application, authentication should be connected to a trusted backend or authentication service. A client-side boolean alone must not be used as the security boundary for private data or operations.
Key Takeaways
- Protected Routes restrict access to certain pages based on authentication or authorization state.
Navigatecan redirect unauthenticated users to a login page.replacecan prevent the blocked URL from remaining as a normal history entry.- A reusable
ProtectedRoutecomponent avoids duplicating route protection logic. Outletis useful for protecting multiple nested routes with one layout component.- Authentication loading state is important when the application must verify an existing session.
useLocation()can help remember the page the user originally wanted to visit.useNavigate()can redirect the user after successful login.- Protected Routes are a UI/navigation pattern; they do not replace server-side authorization.
- Private API data and sensitive operations must still be protected by the backend.
FAQs
1. What are Protected Routes in React?
Protected Routes are routes that check whether a user is allowed to access a page. If the required authentication condition is not satisfied, the user can be redirected to another page such as Login.
2. How do I create a Protected Route in React Router?
You can create a wrapper component that checks authentication and returns either the protected content or <Navigate>.
function ProtectedRoute({ isLoggedIn, children }) {
if (!isLoggedIn) {
return <Navigate to="/login" replace />;
}
return children;
}
3. What is Navigate used for in Protected Routes?
Navigate performs declarative navigation. It can redirect an unauthenticated user from a protected page to a login page.
4. Can I protect multiple React Router routes?
Yes. You can wrap multiple routes with the same Protected Route component, or use a parent route with Outlet to protect a group of nested routes.
5. Should Protected Routes be used for security?
Protected Routes help control what the user sees and where the frontend allows navigation, but they are not a complete security mechanism. The backend must independently verify authentication and authorization before returning private data or performing protected operations.
6. Why do Protected Routes need an authentication loading state?
If the application is still checking an existing session, immediately treating the user as logged out can cause an incorrect redirect. A loading state allows the application to wait until the authentication status is known.
7. What is the difference between Authentication and Protected Routes?
Authentication verifies or represents whether a user is signed in. Protected Routes use that authentication information to control access to frontend routes. Authorization can further determine whether an authenticated user has permission to access a particular resource.
Written by Shubhranshu Shekhar, who has trained 20000+ students in coding.
