Skip to content

Latest commit

 

History

History

README.md

Reusable Auth Module

A modular and reusable authentication feature built with React, TypeScript, Zod, React Query, and Zustand.

Features

  • ✅ User login and signup
  • ✅ Password reset functionality
  • ✅ Protected routes
  • ✅ Form validation with Zod
  • ✅ State management with Zustand
  • ✅ API integration with React Query
  • ✅ TypeScript support
  • ✅ Tailwind CSS styling
  • ✅ Fully reusable and modular

Installation

This module requires the following dependencies:

npm install @tanstack/react-query zustand zod react-hook-form @hookform/resolvers

Or with yarn:

yarn add @tanstack/react-query zustand zod react-hook-form @hookform/resolvers

Quick Start

1. Set up the Auth Provider

Wrap your app with the AuthProvider component:

import { AuthProvider } from './auth';

function App() {
  return (
    <AuthProvider>
      <YourApp />
    </AuthProvider>
  );
}

2. Create Login/Signup Pages

import { useState } from 'react';
import { LoginForm, SignupForm } from './auth';
import { useAuth } from './auth';

function AuthPage() {
  const [mode, setMode] = useState<'login' | 'signup'>('login');
  const { isAuthenticated } = useAuth();

  if (isAuthenticated) {
    return <div>Already logged in!</div>;
  }

  return (
    <div className="max-w-md mx-auto mt-8 p-6 bg-white rounded-lg shadow-md">
      {mode === 'login' ? (
        <LoginForm
          onSuccess={() => console.log('Logged in!')}
          onSwitchToSignup={() => setMode('signup')}
        />
      ) : (
        <SignupForm
          onSuccess={() => console.log('Signed up!')}
          onSwitchToLogin={() => setMode('login')}
        />
      )}
    </div>
  );
}

3. Protect Routes

import { ProtectedRoute } from './auth';

function Dashboard() {
  return (
    <ProtectedRoute>
      <div>Protected Dashboard Content</div>
    </ProtectedRoute>
  );
}

4. Use Auth State

import { useAuth, useLogout } from './auth';

function UserProfile() {
  const { user, isAuthenticated } = useAuth();
  const logoutMutation = useLogout();

  if (!isAuthenticated) return null;

  return (
    <div>
      <p>Welcome, {user?.email}!</p>
      <button onClick={() => logoutMutation.mutate()}>
        Logout
      </button>
    </div>
  );
}

API Configuration

Update the API base URL in auth/services/authService.ts:

const API_BASE_URL = import.meta.env.VITE_API_URL || '/api';

Or set it via environment variable:

VITE_API_URL=https://your-api.com

Expected API Endpoints

Your backend should implement these endpoints:

  • POST /auth/login - Login with email and password
  • POST /auth/signup - Create new user account
  • POST /auth/logout - Logout user
  • POST /auth/forgot-password - Request password reset
  • POST /auth/reset-password - Confirm password reset with token
  • POST /auth/change-password - Change password (requires auth)
  • POST /auth/refresh - Refresh authentication token
  • GET /auth/me - Get current user profile

API Response Format

All auth endpoints should return:

{
  user: {
    id: string;
    email: string;
    name?: string;
    // ... other user fields
  },
  token: string;
  refreshToken?: string;
}

Customization

Change Password Requirements

Edit auth/schemas/index.ts:

const passwordRequirements = {
  minLength: 8,
  requireUppercase: true,
  requireLowercase: true,
  requireNumber: true,
  requireSpecialChar: false, // Change to true to require special characters
};

Customize User Type

Update auth/types/index.ts to match your user model:

export interface User {
  id: string;
  email: string;
  name?: string;
  role?: string;
  // Add your custom fields
}

Customize Styling

All components use Tailwind CSS classes. You can:

  1. Override with custom classes via the className prop
  2. Modify the components directly
  3. Use Tailwind's configuration to customize the design system

Available Components

  • LoginForm - Login form with email and password
  • SignupForm - Signup form with validation
  • ForgotPasswordForm - Request password reset
  • ResetPasswordForm - Confirm password reset with token
  • ChangePasswordForm - Change password for authenticated users
  • ProtectedRoute - Route wrapper that requires authentication
  • AuthProvider - Context provider for auth state

Available Hooks

  • useAuth() - Get current auth state
  • useLogin() - Login mutation hook
  • useSignup() - Signup mutation hook
  • useLogout() - Logout mutation hook
  • useResetPassword() - Request password reset
  • useConfirmPasswordReset() - Confirm password reset
  • useChangePassword() - Change password
  • useCurrentUser() - Fetch current user
  • useRefreshAuth() - Refresh auth token

State Management

The auth state is managed with Zustand and persisted to localStorage. Access the store directly if needed:

import { useAuthStore } from './auth';

const { user, token, isAuthenticated } = useAuthStore();

Examples

Complete Auth Page Example

import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import {
  LoginForm,
  SignupForm,
  ForgotPasswordForm,
  useAuth,
} from './auth';

function AuthPage() {
  const [view, setView] = useState<'login' | 'signup' | 'forgot'>('login');
  const { isAuthenticated } = useAuth();
  const navigate = useNavigate();

  if (isAuthenticated) {
    navigate('/dashboard');
    return null;
  }

  return (
    <div className="min-h-screen flex items-center justify-center bg-gray-50">
      <div className="max-w-md w-full bg-white rounded-lg shadow-md p-8">
        {view === 'login' && (
          <LoginForm
            onSuccess={() => navigate('/dashboard')}
            onSwitchToSignup={() => setView('signup')}
            onForgotPassword={() => setView('forgot')}
          />
        )}
        {view === 'signup' && (
          <SignupForm
            onSuccess={() => navigate('/dashboard')}
            onSwitchToLogin={() => setView('login')}
          />
        )}
        {view === 'forgot' && (
          <ForgotPasswordForm
            onSuccess={() => setView('login')}
            onBackToLogin={() => setView('login')}
          />
        )}
      </div>
    </div>
  );
}

Protected Dashboard Example

import { ProtectedRoute, useAuth, useLogout } from './auth';

function Dashboard() {
  const { user } = useAuth();
  const logout = useLogout();

  return (
    <ProtectedRoute>
      <div className="p-8">
        <h1>Dashboard</h1>
        <p>Welcome, {user?.email}!</p>
        <button
          onClick={() => logout.mutate()}
          className="mt-4 px-4 py-2 bg-red-600 text-white rounded"
        >
          Logout
        </button>
      </div>
    </ProtectedRoute>
  );
}

Migration Guide

To use this auth module in a different project:

  1. Copy the entire auth folder to your new project
  2. Install required dependencies
  3. Update API endpoints in auth/services/authService.ts
  4. Customize types in auth/types/index.ts to match your backend
  5. Wrap your app with AuthProvider
  6. Start using the components and hooks!

License

This module is provided as-is for reuse in your projects.