Protected Routes
Protected routes restrict access to certain pages based on authentication or authorization.
Basic Protected Route
jsx
1import { Navigate, useLocation } from 'react-router-dom'
2
3function ProtectedRoute({ children }) {
4 const { user, loading } = useAuth()
5 const location = useLocation()
6
7 if (loading) {
8 return <LoadingSpinner />
9 }
10
11 if (!user) {
12 // Redirect to login, preserving intended destination
13 return <Navigate to="/login" state={{ from: location }} replace />
14 }
15
16 return children
17}
18
19// Usage
20<Routes>
21 <Route path="/login" element={<Login />} />
22 <Route
23 path="/dashboard"
24 element={
25 <ProtectedRoute>
26 <Dashboard />
27 </ProtectedRoute>
28 }
29 />
30</Routes>Layout-Based Protection
jsx
1function ProtectedLayout() {
2 const { user, loading } = useAuth()
3 const location = useLocation()
4
5 if (loading) {
6 return <LoadingSpinner />
7 }
8
9 if (!user) {
10 return <Navigate to="/login" state={{ from: location }} replace />
11 }
12
13 return (
14 <div>
15 <DashboardNav />
16 <Outlet />
17 </div>
18 )
19}
20
21// Routes
22<Routes>
23 {/* Public routes */}
24 <Route path="/" element={<Home />} />
25 <Route path="/login" element={<Login />} />
26
27 {/* Protected routes */}
28 <Route element={<ProtectedLayout />}>
29 <Route path="/dashboard" element={<Dashboard />} />
30 <Route path="/settings" element={<Settings />} />
31 <Route path="/profile" element={<Profile />} />
32 </Route>
33</Routes>Role-Based Access
jsx
1function RoleProtectedRoute({ children, allowedRoles }) {
2 const { user } = useAuth()
3 const location = useLocation()
4
5 if (!user) {
6 return <Navigate to="/login" state={{ from: location }} replace />
7 }
8
9 if (!allowedRoles.includes(user.role)) {
10 return <Navigate to="/unauthorized" replace />
11 }
12
13 return children
14}
15
16// Usage
17<Routes>
18 <Route
19 path="/admin"
20 element={
21 <RoleProtectedRoute allowedRoles={['admin']}>
22 <AdminPanel />
23 </RoleProtectedRoute>
24 }
25 />
26
27 <Route
28 path="/manager"
29 element={
30 <RoleProtectedRoute allowedRoles={['admin', 'manager']}>
31 <ManagerDashboard />
32 </RoleProtectedRoute>
33 }
34 />
35</Routes>Redirect After Login
jsx
1function Login() {
2 const navigate = useNavigate()
3 const location = useLocation()
4 const { login } = useAuth()
5
6 // Get the page user tried to visit before being redirected to login
7 const from = location.state?.from?.pathname || '/dashboard'
8
9 const handleSubmit = async (e) => {
10 e.preventDefault()
11 try {
12 await login(email, password)
13 navigate(from, { replace: true }) // Go to intended page
14 } catch (error) {
15 setError('Login failed')
16 }
17 }
18
19 return (
20 <form onSubmit={handleSubmit}>
21 {/* Login form */}
22 </form>
23 )
24}Auth Context
jsx
1import { createContext, useContext, useState, useEffect } from 'react'
2
3const AuthContext = createContext(null)
4
5export function AuthProvider({ children }) {
6 const [user, setUser] = useState(null)
7 const [loading, setLoading] = useState(true)
8
9 useEffect(() => {
10 // Check for existing session
11 const checkAuth = async () => {
12 try {
13 const token = localStorage.getItem('token')
14 if (token) {
15 const response = await fetch('/api/auth/me', {
16 headers: { Authorization: `Bearer ${token}` }
17 })
18 if (response.ok) {
19 const userData = await response.json()
20 setUser(userData)
21 }
22 }
23 } catch (error) {
24 console.error('Auth check failed:', error)
25 } finally {
26 setLoading(false)
27 }
28 }
29
30 checkAuth()
31 }, [])
32
33 const login = async (email, password) => {
34 const response = await fetch('/api/auth/login', {
35 method: 'POST',
36 headers: { 'Content-Type': 'application/json' },
37 body: JSON.stringify({ email, password })
38 })
39
40 if (!response.ok) throw new Error('Login failed')
41
42 const { user, token } = await response.json()
43 localStorage.setItem('token', token)
44 setUser(user)
45 return user
46 }
47
48 const logout = () => {
49 localStorage.removeItem('token')
50 setUser(null)
51 }
52
53 return (
54 <AuthContext.Provider value={{ user, loading, login, logout }}>
55 {children}
56 </AuthContext.Provider>
57 )
58}
59
60export function useAuth() {
61 const context = useContext(AuthContext)
62 if (!context) {
63 throw new Error('useAuth must be used within AuthProvider')
64 }
65 return context
66}Complete Example
jsx
1// App.jsx
2import { BrowserRouter, Routes, Route } from 'react-router-dom'
3import { AuthProvider } from './contexts/AuthContext'
4
5function App() {
6 return (
7 <BrowserRouter>
8 <AuthProvider>
9 <Routes>
10 {/* Public */}
11 <Route path="/" element={<Home />} />
12 <Route path="/login" element={<Login />} />
13 <Route path="/register" element={<Register />} />
14
15 {/* Protected */}
16 <Route element={<ProtectedLayout />}>
17 <Route path="/dashboard" element={<Dashboard />} />
18 <Route path="/profile" element={<Profile />} />
19
20 {/* Admin only */}
21 <Route element={<AdminLayout />}>
22 <Route path="/admin" element={<AdminPanel />} />
23 <Route path="/admin/users" element={<UserManagement />} />
24 </Route>
25 </Route>
26
27 {/* Error pages */}
28 <Route path="/unauthorized" element={<Unauthorized />} />
29 <Route path="*" element={<NotFound />} />
30 </Routes>
31 </AuthProvider>
32 </BrowserRouter>
33 )
34}
35
36// AdminLayout.jsx
37function AdminLayout() {
38 const { user } = useAuth()
39
40 if (user?.role !== 'admin') {
41 return <Navigate to="/unauthorized" replace />
42 }
43
44 return <Outlet />
45}Protected routes keep your application secure!
