Auth Provider
Complete authentication state management with Zustand, JWT handling, and React Router integration.
Overview
This template provides:
- Global auth state with Zustand
- JWT token management (access + refresh)
- Automatic token refresh
- Protected route component
- Login/logout functionality
- Persistent auth across page reloads
Dependencies
npm install zustand jwt-decode
npm install react-router-dom # if using React RouterCode
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { tokenService } from './tokenService';
export interface User {
id: string;
email: string;
name: string;
avatar?: string;
role: 'admin' | 'user';
}
interface AuthState {
user: User | null;
isAuthenticated: boolean;
isLoading: boolean;
error: string | null;
// Actions
setUser: (user: User | null) => void;
setLoading: (loading: boolean) => void;
setError: (error: string | null) => void;
logout: () => void;
initialize: () => Promise<void>;
}
export const useAuthStore = create<AuthState>()(
persist(
(set, get) => ({
user: null,
isAuthenticated: false,
isLoading: true,
error: null,
setUser: (user) =>
set({
user,
isAuthenticated: !!user,
error: null,
}),
setLoading: (isLoading) => set({ isLoading }),
setError: (error) => set({ error, isLoading: false }),
logout: () => {
tokenService.clearTokens();
set({
user: null,
isAuthenticated: false,
error: null,
});
},
initialize: async () => {
const token = tokenService.getAccessToken();
if (!token) {
set({ isLoading: false });
return;
}
if (tokenService.isTokenExpired(token)) {
try {
await tokenService.refreshAccessToken();
} catch {
get().logout();
return;
}
}
try {
const response = await fetch('/api/auth/me', {
headers: {
Authorization: `Bearer ${tokenService.getAccessToken()}`,
},
});
if (response.ok) {
const user = await response.json();
set({ user, isAuthenticated: true, isLoading: false });
} else {
get().logout();
}
} catch {
get().logout();
}
},
}),
{
name: 'auth-storage',
partialize: (state) => ({
user: state.user,
isAuthenticated: state.isAuthenticated,
}),
}
)
);Setup
Initialize Auth on App Load
// App.tsx or main.tsx
import { useEffect } from 'react';
import { useAuthStore } from '@/features/auth/stores/authStore';
function App() {
const initialize = useAuthStore((state) => state.initialize);
useEffect(() => {
initialize();
}, [initialize]);
return <AppRouter />;
}Configure API Client with Auto-Refresh
// lib/apiClient.ts
import { tokenService } from '@/features/auth/services/tokenService';
const apiClient = {
async fetch(url: string, options: RequestInit = {}): Promise<Response> {
let token = tokenService.getAccessToken();
if (token && tokenService.isTokenExpired(token)) {
try {
token = await tokenService.refreshAccessToken();
} catch {
window.location.href = '/login';
throw new Error('Session expired');
}
}
const headers = new Headers(options.headers);
if (token) {
headers.set('Authorization', `Bearer ${token}`);
}
return fetch(url, { ...options, headers });
},
};
export default apiClient;Set Up Routes
// app/router/AppRouter.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { ProtectedRoute } from './ProtectedRoute';
import { LoginPage } from '@/pages/LoginPage';
import { DashboardPage } from '@/pages/DashboardPage';
export function AppRouter() {
return (
<BrowserRouter>
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route
path="/dashboard"
element={
<ProtectedRoute>
<DashboardPage />
</ProtectedRoute>
}
/>
</Routes>
</BrowserRouter>
);
}File Structure
features/auth/
├── components/
│ ├── LoginForm.tsx
│ ├── SignupForm.tsx
│ └── index.ts
├── hooks/
│ ├── useAuth.ts
│ └── index.ts
├── services/
│ ├── authService.ts
│ ├── tokenService.ts
│ └── index.ts
├── stores/
│ └── authStore.ts
├── types/
│ └── auth.types.ts
└── index.tsSecurity Considerations
⚠️
Never store sensitive data in localStorage in production. Consider using httpOnly cookies for refresh tokens.
- Use HTTPS in production
- Implement CSRF protection
- Set appropriate token expiration times
- Validate tokens on the server side
- Consider using httpOnly cookies for refresh tokens
Related
- Login Form - Login form component
- Signup Form - Registration form
- Project Structure - Feature organization