GitHub

Authentication Flow

Secure login, signup, and token refresh patterns. Auth state lives in Zustand — never in React Query — with JWT and protected route handling.

01

Principle

Authentication state is client state, not server state. It belongs in Zustand or Context, not React Query. The auth store manages tokens, user profile, and session status. API interceptors handle token refresh transparently.

lightbulb

Store only the minimum necessary in auth state. Token expiry, user ID, and roles. Fetch full user profile via React Query when needed.

02

Rules

  • check_circle
    Never Store Sensitive Data in StateTokens live in httpOnly cookies or secure storage — never in React state or localStorage.
  • check_circle
    Centralize InterceptorsOne Axios/fetch interceptor handles 401 responses and token refresh for all API calls.
  • check_circle
    Separate Auth from UIAuthProvider wraps the app. UI components only call useAuth() — never touch tokens directly.
  • check_circle
    Route Protection at LayoutProtect routes at the layout level, not inside individual pages.
03

Pattern

stores/useAuthStore.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

export const useAuthStore = create<AuthState>()(
  persist(
    (set) => ({
      user: null,
      isAuthenticated: false,
      login: (user) => set({ user, isAuthenticated: true }),
      logout: () => set({ user: null, isAuthenticated: false }),
    }),
    { name: 'auth-storage' },
  ),
);
04

Implementation

info

Version Compatibility

Requires React 19+ and the latest stable versions of all dependencies shown.

Use Next.js Middleware to protect routes server-side before the page renders. Check the auth cookie on every request.

middleware.ts
import { NextRequest, NextResponse } from 'next/server';

export function middleware(req: NextRequest) {
  const token = req.cookies.get('auth-token');
  const isProtected = req.nextUrl.pathname.startsWith('/dashboard');

  if (isProtected && !token) {
    return NextResponse.redirect(new URL('/login', req.url));
  }
  return NextResponse.next();
}
menu_book
React Patterns

Helping developers build robust React applications since 2025.

© 2025 React Patterns Cookbook. Built with ❤️ for the community.
react-principles