Skip to content

Repository files navigation

🛡️ AuthForge - Production-Ready Authentication System

Clone. Configure. Deploy. A complete authentication system you can use in your production applications right now.

Node.js PostgreSQL Redis Docker React

⚡ Use This For Your Production Authentication

Stop building auth from scratch. This template includes everything you need:

  • Secure by default - bcrypt, JWT, httpOnly cookies, rate limiting
  • One-command setup - Just run docker-compose up
  • Beautiful UI included - Login, Register, Dashboard ready to use
  • Easy to customize - Clean code, well-documented, modular design
  • Battle-tested patterns - Token rotation, MFA, audit logs

📚 Table of Contents

  1. Quick Start
  2. What You'll Learn
  3. System Architecture
  4. Security Concepts Explained
  5. API Reference
  6. Project Structure
  7. Configuration
  8. Deployment

🚀 Quick Start

Prerequisites

3 Steps to Run

# 1. Clone the repository
git clone https://github.com/YOUR_USERNAME/authforge.git
cd authforge

# 2. Start everything with Docker
docker-compose up -d --build

# 3. Open the app
# Frontend: http://localhost:5173
# API: http://localhost:3000
# Emails: http://localhost:8025

That's it! 🎉 No Node.js installation needed. Everything runs in Docker.


🛡️ What This System Includes

This is a complete, production-ready authentication system with:

Feature What It Does
Password Security bcrypt hashing + unique salt per user prevents rainbow table attacks
JWT Access Tokens Stateless 15-min tokens that don't require database lookups
Refresh Token Rotation 7-day tokens with automatic theft detection
OAuth 2.0 "Login with Google" using industry-standard OAuth flow
Email MFA Optional 2-factor authentication via email OTP
Rate Limiting Blocks brute force attacks (5 attempts/15 min)
Account Lockout Locks account after 5 failed login attempts
Session Management View and revoke active sessions from any device
Audit Logging Every security event recorded in the database
Role-Based Access USER, MODERATOR, ADMIN, SUPER_ADMIN roles

🏗️ System Architecture

┌─────────────────────────────────────────────────────────────────┐
│                         FRONTEND (React)                        │
│                    http://localhost:5173                        │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────────────┐ │
│  │  Login   │  │ Register │  │  Verify  │  │    Dashboard     │ │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────────┬─────────┘ │
└───────┼─────────────┼─────────────┼─────────────────┼───────────┘
        │             │             │                 │
        └─────────────┴─────────────┴─────────────────┘
                              │
                    HTTP (JSON) + Cookies
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      BACKEND (Express.js)                       │
│                    http://localhost:3000                        │
│                                                                 │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐  │
│  │   Routes    │  │  Middleware │  │       Controllers       │  │
│  │  /auth/*    │──│ Rate Limit  │──│  Login, Register, etc   │  │
│  │  /oauth/*   │  │ JWT Verify  │  │                         │  │
│  │  /user/*    │  │ RBAC        │  │                         │  │
│  └─────────────┘  └─────────────┘  └───────────┬─────────────┘  │
│                                                │                │
│  ┌─────────────────────────────────────────────┴─────────────┐  │
│  │                       SERVICES                            │  │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐          │  │
│  │  │  Hash   │ │  Token  │ │   OTP   │ │  Email  │          │  │
│  │  │ Service │ │ Service │ │ Service │ │ Service │          │  │
│  │  └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘          │  │
│  └───────┼──────────┼───────────┼───────────┼────────────────┘  │
└──────────┼──────────┼───────────┼───────────┼───────────────────┘
           │          │           │           │
           ▼          ▼           ▼           ▼
┌──────────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│  PostgreSQL  │ │  Redis   │ │  Redis   │ │  SMTP    │
│   (Users,    │ │ (Tokens, │ │  (OTPs,  │ │ (MailHog)│
│   Sessions)  │ │  Cache)  │ │ Attempts)│ │          │
└──────────────┘ └──────────┘ └──────────┘ └──────────┘

🔐 Security Concepts Explained

1. Password Hashing with Salt

The Problem: If we store passwords as-is, a database breach exposes all passwords.

The Solution: Hash passwords with bcrypt + unique salt per user.

Password: "mypassword123"
     │
     ▼
┌─────────────────────────────────────────────┐
│  Salt: "a1b2c3d4e5f6..."  (random, unique)  │
│                                             │
│  Combined: "mypassword123" + salt           │
│                     │                       │
│                     ▼                       │
│            bcrypt(combined, 12)             │
│                     │                       │
│                     ▼                       │
│  Hash: "$2b$12$xyz..."  (stored in DB)      │
└─────────────────────────────────────────────┘

Why Salt?

  • Without salt: Same password = same hash (vulnerable to rainbow tables)
  • With unique salt: Same password = different hash (secure!)

Code Location: src/services/hashService.js


2. JWT Access Tokens

The Problem: Checking the database for every API request is slow and doesn't scale.

The Solution: Issue a self-contained token that the server can verify without database lookups.

┌──────────────────────────────────────────────────────────────────┐
│                        JWT STRUCTURE                             │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Header.Payload.Signature                                        │
│                                                                  │
│  ┌─────────────┐  ┌─────────────────┐  ┌─────────────────────┐   │
│  │   HEADER    │  │     PAYLOAD     │  │     SIGNATURE       │   │
│  │             │  │                 │  │                     │   │
│  │ {           │  │ {               │  │  HMAC-SHA256(       │   │
│  │   "alg":    │  │   "userId": 1,  │  │    header + "." +   │   │
│  │   "HS256",  │  │   "email": "x", │  │    payload,         │   │
│  │   "typ":    │  │   "role": "user"│  │    SECRET_KEY       │   │
│  │   "JWT"     │  │   "exp": 12345  │  │  )                  │   │
│  │ }           │  │ }               │  │                     │   │
│  └─────────────┘  └─────────────────┘  └─────────────────────┘   │
│        │                   │                      │              │
│        └───────────────────┴──────────────────────┘              │
│                            │                                     │
│                     Base64 Encoded                               │
│                            │                                     │
│   eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.dBjftJeZ4CVP-mB92K27uhbUJU1p1r │
└──────────────────────────────────────────────────────────────────┘

How Verification Works (No Database!):

  1. Server receives JWT
  2. Server uses SECRET_KEY to verify signature
  3. If valid → trust the payload data
  4. If invalid → reject the request

Why Short Expiry (15 min)?

  • If stolen, attacker has limited time
  • Refresh token handles getting new access tokens

Code Location: src/services/tokenService.js


3. Refresh Token Rotation

The Problem: Short-lived access tokens = user logs out frequently. Long-lived tokens = security risk.

The Solution: Two-token system with rotation.

┌─────────────────────────────────────────────────────────────────────────┐
│                     REFRESH TOKEN ROTATION FLOW                         │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  LOGIN                                                                  │
│  ─────                                                                  │
│  User → [email + password] → Server                                     │
│                                 │                                       │
│                    ┌────────────┴────────────┐                          │
│                    ▼                         ▼                          │
│            Access Token (JWT)        Refresh Token                      │
│            ├─ 15 min expiry          ├─ 7 day expiry                    │
│            ├─ Stored in memory       ├─ Stored in httpOnly cookie       │
│            └─ Used for API calls     └─ Hash stored in database         │
│                                                                         │
│  ─────────────────────────────────────────────────────────────────────  │
│                                                                         │
│  REFRESH (Token Rotation)                                               │
│  ───────────────────────                                                │
│                                                                         │
│  ┌─────────┐    Old Refresh Token    ┌─────────┐                        │
│  │ Client  │ ───────────────────────►│ Server  │                        │
│  └─────────┘                         └────┬────┘                        │
│       ▲                                   │                             │
│       │                         1. Verify hash in DB                    │
│       │                         2. INVALIDATE old token ← Key step!     │
│       │                         3. Generate NEW tokens                  │
│       │                                   │                             │
│       │   New Access + Refresh Tokens     │                             │
│       └───────────────────────────────────┘                             │
│                                                                         │
│  ─────────────────────────────────────────────────────────────────────  │
│                                                                         │
│  THEFT DETECTION                                                        │
│  ───────────────                                                        │
│                                                                         │
│  If attacker uses STOLEN refresh token:                                 │
│                                                                         │
│  1. Attacker uses stolen token → Gets new tokens → Old token invalid    │
│  2. Real user uses OLD token → Token already used! → ALERT!             │
│  3. Server revokes ALL tokens for that user → Forces re-login           │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Code Location: src/services/tokenService.jsrotateRefreshToken()


4. OTP (One-Time Password)

The Problem: Passwords can be phished or leaked. We need a second factor.

The Solution: Send a temporary code via email that expires quickly.

┌─────────────────────────────────────────────────────────────────┐
│                       OTP FLOW                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. GENERATE                                                    │
│     ─────────                                                   │
│     • Generate 6-digit code: 847293                             │
│     • Hash before storing (security!)                           │
│                                                                 │
│  2. STORE IN REDIS                                              │
│     ────────────────                                            │
│     ┌────────────────────────────────────────────┐              │
│     │  Key: "otp:user@example.com:verify_email"  │              │
│     │  Value: "hashed_847293"                    │              │
│     │  TTL: 300 seconds (5 minutes)              │ ← Auto-expire│
│     └────────────────────────────────────────────┘              │
│                                                                 │
│  3. SEND EMAIL                                                  │
│     ──────────                                                  │
│     📧 "Your code is: 847293"                                   │
│                                                                 │
│  4. VERIFY                                                      │
│     ──────                                                      │
│     User enters: 847293                                         │
│     Server: hash(847293) == stored_hash? ✓                      │
│     Delete from Redis (one-time use)                            │
│                                                                 │
│  WHY REDIS?                                                     │
│  ──────────                                                     │
│  • Auto-expiration (TTL) - no cleanup needed                    │
│  • Fast read/write - no DB overhead                             │
│  • Temporary data - perfect for in-memory cache                 │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Code Location: src/services/otpService.js


5. Google OAuth 2.0

The Problem: Users hate creating new passwords. They want "Login with Google."

The Solution: OAuth 2.0 - let Google verify the user, then create our own session.

┌─────────────────────────────────────────────────────────────────────────┐
│                      GOOGLE OAUTH 2.0 FLOW                              │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│     USER            AUTHFORGE              GOOGLE                       │
│       │                 │                     │                         │
│       │                 │                     │                         │
│  1.   │──Click "Login   │                     │                         │
│       │  with Google"──►│                     │                         │
│       │                 │                     │                         │
│  2.   │                 │──Redirect to────────►                         │
│       │                 │  Google consent     │                         │
│       │                 │  screen             │                         │
│       │                 │                     │                         │
│  3.   │◄────────────────────────────────────  │                         │
│       │  "AuthForge wants to access your      │                         │
│       │   email and profile. Allow?"          │                         │
│       │                 │                     │                         │
│  4.   │──Click "Allow"──│─────────────────────►                         │
│       │                 │                     │                         │
│  5.   │                 │◄──Redirect with ────│                         │
│       │                 │   ?code=abc123      │                         │
│       │                 │                     │                         │
│  6.   │                 │──Exchange code──────►  (Server-to-server)     │
│       │                 │  for tokens         │                         │
│       │                 │                     │                         │
│  7.   │                 │◄──{access_token, ───│                         │
│       │                 │    id_token}        │                         │
│       │                 │                     │                         │
│  8.   │                 │──Decode id_token────│                         │
│       │                 │  Get: email, name   │                         │
│       │                 │                     │                         │
│  9.   │                 │──Find/Create user ──│                         │
│       │                 │  in OUR database    │                         │
│       │                 │                     │                         │
│ 10.   │                 │──Issue OUR JWT ─────│                         │
│       │                 │  (not Google's!)    │                         │
│       │                 │                     │                         │
│ 11.   │◄──Logged in!────│                     │                         │
│       │  w/ AuthForge   │                     │                         │
│       │  session        │                     │                         │
│                                                                         │
│  KEY INSIGHT: We use Google ONLY for identity verification.            │
│  We issue OUR OWN tokens - keeping us independent of Google.           │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Code Location: src/controllers/oauthController.js


6. Rate Limiting & Account Lockout

The Problem: Attackers can try thousands of passwords per second.

The Solution: Limit attempts and lock accounts after failures.

┌─────────────────────────────────────────────────────────────────┐
│                    PROTECTION LAYERS                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  LAYER 1: IP-BASED RATE LIMITING                                │
│  ───────────────────────────────                                │
│                                                                 │
│  ┌────────────────┐                                             │
│  │ 192.168.1.100  │──► 5 login attempts / 15 min                │
│  └────────────────┘    │                                        │
│                        ├─ Attempt 1: ✓                          │
│                        ├─ Attempt 2: ✓                          │
│                        ├─ Attempt 3: ✓                          │
│                        ├─ Attempt 4: ✓                          │
│                        ├─ Attempt 5: ✓                          │
│                        └─ Attempt 6: ❌ BLOCKED (429 Error)      │
│                                                                 │
│  ─────────────────────────────────────────────────────────────  │
│                                                                 │
│  LAYER 2: ACCOUNT LOCKOUT                                       │
│  ────────────────────────                                       │
│                                                                 │
│  ┌─────────────────────┐                                        │
│  │ user@example.com    │──► Track failed attempts in Redis      │
│  └─────────────────────┘                                        │
│                                                                 │
│  Attempt 1: Wrong password → attempts: 1                        │
│  Attempt 2: Wrong password → attempts: 2                        │
│  Attempt 3: Wrong password → attempts: 3                        │
│  Attempt 4: Wrong password → attempts: 4                        │
│  Attempt 5: Wrong password → attempts: 5 → 🔒 LOCKED            │
│                                                                 │
│  Account locked for 15 minutes                                  │
│  Even correct password won't work!                              │
│                                                                 │
│  ─────────────────────────────────────────────────────────────  │
│                                                                 │
│  LAYER 3: GENERAL API RATE LIMIT                                │
│  ───────────────────────────────                                │
│                                                                 │
│  All endpoints: 100 requests / 15 min per IP                    │
│  Prevents DDoS and API abuse                                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Code Location: src/middleware/rateLimiter.js


📡 API Reference

Authentication Endpoints

Method Endpoint Description Auth Required
POST /auth/register Create new account
POST /auth/login Login with email/password
POST /auth/verify-email Verify email with OTP
POST /auth/refresh Get new access token 🍪 Cookie
POST /auth/logout Logout & revoke tokens
POST /auth/forgot-password Request password reset
POST /auth/reset-password Reset with OTP
POST /auth/change-password Change password
GET /auth/me Get current user

OAuth Endpoints

Method Endpoint Description
GET /oauth/google Start Google login
GET /oauth/google/callback Google callback

User Endpoints

Method Endpoint Description Auth Required
GET /user/profile Get profile
PATCH /user/profile Update profile
GET /user/sessions List active sessions
DELETE /user/sessions/:id Revoke a session
POST /user/mfa/enable Enable MFA
POST /user/mfa/disable Disable MFA
GET /user/activity Get activity log

📁 Project Structure

authforge/
├── docker-compose.yml      # All services configuration
├── Dockerfile              # Production API image
├── Dockerfile.dev          # Development API image
│
├── frontend/               # React UI
│   ├── src/
│   │   ├── pages/          # Login, Register, Dashboard
│   │   ├── App.jsx         # Routes & AuthContext
│   │   └── index.css       # Styling
│   └── Dockerfile
│
├── prisma/
│   └── schema.prisma       # Database schema
│
└── src/                    # Backend
    ├── app.js              # Express app
    ├── config/
    │   ├── database.js     # Prisma client
    │   ├── redis.js        # Redis client
    │   └── env.js          # Environment config
    ├── controllers/
    │   ├── authController.js    # Login, register, etc.
    │   ├── oauthController.js   # Google OAuth
    │   └── userController.js    # Profile, sessions
    ├── middleware/
    │   ├── authenticate.js      # JWT verification
    │   ├── authorize.js         # Role-based access
    │   ├── rateLimiter.js       # Rate limiting
    │   └── errorHandler.js      # Error handling
    ├── services/
    │   ├── hashService.js       # Password hashing
    │   ├── tokenService.js      # JWT management
    │   ├── otpService.js        # OTP generation
    │   ├── emailService.js      # Send emails
    │   └── auditService.js      # Audit logging
    └── routes/
        ├── auth.routes.js
        ├── oauth.routes.js
        └── user.routes.js

⚙️ Configuration

All configuration is in docker-compose.yml environment variables.

For Production, Update These:

# Generate secure secrets:
# node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"

- JWT_ACCESS_SECRET=<64-char-random-secret>
- JWT_REFRESH_SECRET=<64-char-random-secret>
- COOKIE_SECRET=<random-secret>

# Get from https://console.cloud.google.com/
- GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
- GOOGLE_CLIENT_SECRET=your-client-secret

# Use real SMTP (SendGrid, AWS SES, etc.)
- SMTP_HOST=smtp.sendgrid.net
- SMTP_PORT=587
- SMTP_USER=apikey
- SMTP_PASS=your-api-key

🚢 Deployment

Deploy to Railway/Render

  1. Push code to GitHub
  2. Connect repository to Railway/Render
  3. Set environment variables
  4. Deploy!

Deploy with Docker

# Build production images
docker-compose -f docker-compose.prod.yml build

# Run in production
docker-compose -f docker-compose.prod.yml up -d

🧪 Testing the Flow

  1. Register: http://localhost:5173/register
  2. Check email: http://localhost:8025 (MailHog)
  3. Enter OTP: Complete verification
  4. Dashboard: Explore sessions and MFA
  5. Enable MFA: Toggle 2FA
  6. Logout & Login: See MFA in action!

📄 License

MIT © Piyush Sahoo


Built with ❤️ by Piyush

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages