React Authentication Basics
# React Authentication Basics
1. Introduction
Almost every modern web application requires some form of user authentication—verifying who a user is and granting them access to specific areas (like a user dashboard or admin panel). While actual authentication logic happens on the backend server (Node.js, PHP, Firebase), the React frontend must handle the UI: capturing login details, storing security tokens, and hiding "Protected Routes" from unauthorized guests.2. Learning Objectives
By the end of this chapter, you will be able to:- Understand the frontend authentication flow (JWT basics).
- Create a global Auth Context to track user state.
- Build a "Protected Route" component.
- Handle login and logout actions seamlessly.
3. Beginner-Friendly Explanations
The Authentication Flow
- 1. Login: The user types their email/password and hits submit.
- 2. Verify: React sends this data to the backend API.
- 3. Token: If the password is correct, the backend sends back a special string called a "Token" (often a JSON Web Token, or JWT) and user data.
- 4. Store: React saves this token in LocalStorage and updates the global Auth Context.
-
5.
Access: React now allows the user to visit
/dashboard. For any future API requests (like fetching private emails), React attaches the token to the request to prove the user is logged in.
Protected Routes
A Protected Route is a custom component that acts as a bouncer. Before it renders the page, it checks the global Auth Context. If the user is logged in, it opens the door. If not, it redirects them to the login page.4. Syntax Explanation
Step 1: The Auth Context
We use the Context API (from Chapter 20) to store the user globally.```jsx id="ch25_ex1" import { createContext, useState, useContext } from 'react';
const AuthContext = createContext();
export const AuthProvider = ({ children }) => { const [user, setUser] = useState(null); // null means logged out
const login = (userData) => setUser(userData); const logout = () => setUser(null);
return ( <AuthContext.Provider value={{ user, login, logout }}> {children} </AuthContext.Provider> ); };
export const useAuth = () => useContext(AuthContext);
jsx id="ch25_ex2" import { Navigate } from 'react-router-dom'; import { useAuth } from './AuthContext';
function ProtectedRoute({ children }) { const { user } = useAuth();
// If no user, redirect to login page! if (!user) { return <Navigate to="/login" replace />; }
// If user exists, render the protected component return children; } export default ProtectedRoute;
jsx id="ch25_ex3" import { Routes, Route } from 'react-router-dom';
function App() { return ( <Routes> {/* Public Routes */} <Route path="/" element={<Home />} /> <Route path="/login" element={<Login />} />
{/* Protected Routes (Wrapped in the Bouncer!) */} <Route path="/dashboard" element={ <ProtectedRoute> <Dashboard /> </ProtectedRoute> } /> </Routes> ); }
jsx id="ch25_proj1" // Example React component import React, { createContext, useState, useContext } from 'react'; import { BrowserRouter, Routes, Route, Link, Navigate, useNavigate } from 'react-router-dom';
// --- 1. AUTH CONTEXT --- const AuthContext = createContext();
const AuthProvider = ({ children }) => { const [user, setUser] = useState(null); // Mock login function const login = (username) => setUser({ name: username, role: 'admin' }); const logout = () => setUser(null);
return ( <AuthContext.Provider value={{ user, login, logout }}> {children} </AuthContext.Provider> ); };
// --- 2. PROTECTED ROUTE COMPONENT --- const RequireAuth = ({ children }) => { const { user } = useContext(AuthContext); return user ? children : <Navigate to="/login" />; };
// --- 3. PAGES --- const PublicHome = () => <div className="p-8 text-2xl font-bold">🌍 Public Homepage</div>;
const LoginPage = () => { const [name, setName] = useState(""); const { login } = useContext(AuthContext); const navigate = useNavigate();
const handleLogin = (e) => { e.preventDefault(); login(name || "Guest User"); navigate('/dashboard'); // Redirect to dashboard after login! };
return ( <div className="p-8 max-w-sm mx-auto mt-10 bg-white shadow-lg rounded-xl border border-gray-100"> <h2 className="text-2xl font-bold mb-4">Login</h2> <form onSubmit={handleLogin} className="flex flex-col gap-4"> <input type="text" placeholder="Enter your name" value={name} onChange={e => setName(e.target.value)} className="border p-2 rounded focus:ring-2 focus:ring-blue-500 outline-none" /> <button type="submit" className="bg-blue-600 text-white font-bold py-2 rounded hover:bg-blue-700 transition"> Log In </button> </form> </div> ); };
const PrivateDashboard = () => { const { user, logout } = useContext(AuthContext); return ( <div className="p-8 max-w-2xl mx-auto mt-10 bg-green-50 rounded-xl border border-green-200"> <h1 className="text-3xl font-black text-green-800 mb-2">🔒 Secret Dashboard</h1> <p className="text-lg mb-6">Welcome back, <strong>{user.name}</strong>!</p> <button onClick={logout} className="bg-red-500 text-white font-bold px-4 py-2 rounded shadow hover:bg-red-600 transition"> Log Out </button> </div> ); };
// --- 4. MAIN APP --- export default function App() { return ( <AuthProvider> <BrowserRouter> {/* Simple Navbar */} <nav className="bg-slate-900 text-white p-4 flex gap-6 shadow-md items-center"> <Link to="/" className="hover:text-blue-400 font-medium transition">Home</Link> <Link to="/dashboard" className="hover:text-blue-400 font-medium transition">Dashboard</Link> <Link to="/login" className="hover:text-blue-400 font-medium transition ml-auto border border-slate-600 px-4 py-1 rounded">Login</Link> </nav>
{/* Route Definitions */}
<Routes>
<Route path="/" element={<PublicHome />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/dashboard" element={
<RequireAuth>
<PrivateDashboard />
</RequireAuth>
} />
</Routes>
</BrowserRouter>
</AuthProvider>
);
}
``
11. Coding Challenges
Challenge 1: In the AuthContext, update the state to check localStorage for a user object when the app first loads, so the user stays logged in even if they refresh the page.
12. MCQs with Answers
Q1: What is the primary role of a "Protected Route" component?
A) To encrypt data.
B) To check authentication state and either render the requested page or redirect to login.
C) To protect the backend API from hackers.
*Answer: B*
Q2: Which React Router component is used to instantly redirect a user to another page?
A)
<Redirect>
B) <Navigate>
C) <Route>`
*Answer: B*
13. Interview Questions
- Q: Why isn't hiding routes in React considered "true" security? *(Answer: Because the code is fully shipped to the client's browser. True security must be enforced by the backend API validating a secure token).*
- Q: How do you persist user login state across browser refreshes?