Skip to content

A complete, production-ready authentication system built with the MERN stack featuring JWT-based authentication and Google OAuth 2.0 login.

Notifications You must be signed in to change notification settings

puneetnith28/Authentication-System

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 

Repository files navigation

MERN Stack Authentication with JWT & Google OAuth

A complete, production-ready authentication system built with the MERN stack featuring JWT-based authentication, Google OAuth 2.0 login, and email/password authentication with password reset functionality.

Features

  • ✅ Email/password authentication with signup
  • Email verification (mandatory for account activation)
  • ✅ Google OAuth 2.0 authentication
  • ✅ Password reset via email (forgot password)
  • ✅ JWT access tokens (15 min) + refresh tokens (7 days)
  • ✅ Secure httpOnly cookies (NOT localStorage)
  • ✅ Protected routes on frontend and backend
  • ✅ Automatic token refresh
  • ✅ User auto-creation on first login
  • ✅ Modern React with Vite
  • ✅ Express.js best practices
  • ✅ Password hashing with bcrypt
  • ✅ Cryptographically secure verification tokens

Tech Stack

Backend

  • Node.js + Express.js
  • MongoDB with Mongoose
  • Passport.js (Google OAuth 2.0)
  • JWT (jsonwebtoken)
  • bcrypt (password hashing)
  • nodemailer (password reset emails)
  • cookie-parser

Frontend

  • React 18 (Vite)
  • React Router v6
  • Axios
  • Context API for state management

Getting Started

Prerequisites

  • Node.js (v18+)
  • MongoDB (local or Atlas)
  • Google Cloud Console project

1. Google OAuth Setup

  1. Go to Google Cloud Console
  2. Create a new project or select existing
  3. Enable Google+ API
  4. Go to CredentialsCreate CredentialsOAuth 2.0 Client ID
  5. Configure OAuth consent screen
  6. Add Authorized redirect URIs:
    http://localhost:5000/api/auth/google/callback
    
  7. Copy Client ID and Client Secret

2. Backend Setup

cd server

# Install dependencies
npm install

# Create .env file
cp .env.example .env

# Edit .env with your credentials:
# - MONGODB_URI
# - GOOGLE_CLIENT_ID
# - GOOGLE_CLIENT_SECRET
# - JWT_ACCESS_SECRET (use strong random string)
# - JWT_REFRESH_SECRET (use strong random string)

# Start development server
npm run dev

Server runs on http://localhost:5000

3. Frontend Setup

cd client

# Install dependencies
npm install

# Create .env file
cp .env.example .env

# Edit .env if needed (default: http://localhost:5000/api)

# Start development server
npm run dev

Client runs on http://localhost:5173

4. MongoDB Setup

Option A: Local MongoDB

# Install MongoDB locally and start service
mongod

Option B: MongoDB Atlas (Cloud)

  1. Create free cluster at MongoDB Atlas
  2. Get connection string
  3. Update MONGODB_URI in server/.env

JWT Authentication Flow

Login Flow

1. User clicks "Login with Google"
2. Frontend redirects to: /api/auth/google
3. Backend redirects to Google consent screen
4. User approves → Google redirects to: /api/auth/google/callback
5. Backend:
   - Gets user profile from Google
   - Finds or creates user in MongoDB
   - Generates access token (15 min) + refresh token (7 days)
   - Sets tokens in httpOnly cookies
   - Redirects to frontend /dashboard
6. Frontend:
   - Reads cookies automatically
   - Fetches user data from /api/auth/me
   - Stores user in Context

Protected API Request Flow

1. Frontend makes request with credentials (cookies auto-sent)
2. Backend auth middleware:
   - Checks access token in cookies
   - If valid → proceed
   - If expired → check refresh token
   - If refresh valid → issue new access token
   - If both invalid → return 401
3. Frontend receives response or redirects to login

Logout Flow

1. User clicks "Logout"
2. Frontend calls /api/auth/logout
3. Backend clears cookies
4. Frontend clears user state
5. Redirect to /login

API Endpoints

Authentication Routes

Method Endpoint Access Description
GET /api/auth/google Public Initiate Google OAuth
GET /api/auth/google/callback Public OAuth callback
GET /api/auth/me Protected Get current user
POST /api/auth/logout Protected Logout user
GET /api/auth/status Public Check auth status

Security Features

httpOnly Cookies - Prevents XSS attacks (tokens not accessible via JavaScript)
SameSite Cookies - CSRF protection
Secure Cookies - HTTPS only in production
Short-lived Access Tokens - Limits damage if compromised
Refresh Token Rotation - New access token from refresh
Environment Variables - Secrets never in code
CORS Configuration - Only allow trusted origins

Testing the Application

Test Authentication Flow

  1. Navigate to http://localhost:5173
  2. Click "Continue with Google"
  3. Login with Google account
  4. Should redirect to Dashboard
  5. Verify user info displays
  6. Click "Logout"
  7. Should redirect to Login page

Test Protected Routes

  1. While logged out, try accessing: http://localhost:5173/dashboard
  2. Should redirect to /login
  3. Login again
  4. Try accessing /login while authenticated
  5. Should redirect to /dashboard

Test Token Refresh

  1. Login and open DevTools → Application → Cookies
  2. Note the accessToken (expires in 15 min)
  3. Wait 15+ minutes or manually delete accessToken
  4. Make a request (refresh page)
  5. New accessToken should be issued via refreshToken

Environment Variables

Server (.env)

PORT=5000
MONGODB_URI=mongodb://localhost:27017/mern-auth
JWT_ACCESS_SECRET=<strong-random-string>
JWT_REFRESH_SECRET=<strong-random-string>
GOOGLE_CLIENT_ID=<your-client-id>
GOOGLE_CLIENT_SECRET=<your-client-secret>
CLIENT_URL=http://localhost:5173
NODE_ENV=development

Client (.env)

VITE_API_URL=http://localhost:5000/api

Production Deployment

Backend (Render, Railway, Heroku)

  1. Set environment variables in hosting platform
  2. Update GOOGLE_CLIENT_ID redirect URI to production URL
  3. Set NODE_ENV=production
  4. Update CLIENT_URL to production frontend URL

Frontend (Vercel, Netlify)

  1. Set VITE_API_URL to production backend URL
  2. Build: npm run build
  3. Deploy dist/ folder

Security Checklist

  • ✅ Use strong JWT secrets
  • ✅ Enable HTTPS (secure cookies)
  • ✅ Update CORS origins
  • ✅ Use MongoDB Atlas or secure database
  • ✅ Add rate limiting
  • ✅ Implement request validation

Troubleshooting

"Redirect URI mismatch"

  • Ensure Google Console redirect URI matches exactly: http://localhost:5000/api/auth/google/callback

"MongoDB connection failed"

  • Check MongoDB is running: mongod
  • Verify MONGODB_URI in .env

Cookies not being set

  • Check CORS credentials: true in backend
  • Frontend axios must use withCredentials: true
  • Same origin or proper CORS headers

"401 Unauthorized" on protected routes

  • Check cookies are being sent with request
  • Verify JWT secrets match in .env
  • Check token expiry

Key Concepts

Why httpOnly Cookies?

  • localStorage is vulnerable to XSS attacks
  • httpOnly cookies cannot be accessed by JavaScript
  • Browser automatically sends cookies with requests

Access vs Refresh Tokens

  • Access Token: Short-lived (15 min), used for API requests
  • Refresh Token: Long-lived (7 days), used to get new access token
  • Reduces risk: compromised access token expires quickly

Passport.js vs Manual OAuth

  • Passport simplifies OAuth flow
  • Handles strategy pattern for multiple providers
  • Standardized interface for authentication

Email Verification System

Overview

This application implements mandatory email verification for all email/password registrations. Users cannot login until they verify their email address by clicking a link sent to their inbox.

Registration Flow

  1. User signs up with email and password
  2. Account created with isVerified: false
  3. Verification token generated:
    • 32-byte cryptographically secure random token
    • SHA-256 hashed before storing in database
    • Expires in 30 minutes
  4. Email sent with verification link
  5. User clicks link → account activated → auto-login
  6. Token invalidated after single use

Security Features

Token Security

  • Random generation: Uses crypto.randomBytes(32) for unpredictability
  • Hashed storage: SHA-256 hash stored in DB, not plaintext token
  • Time-limited: 30-minute expiration window
  • Single-use: Token deleted after successful verification

Login Protection

  • Login attempts with unverified accounts return 403 Forbidden
  • Clear error message: "Please verify your email before logging in"
  • Prevents access to protected resources

Google OAuth Users

  • Google OAuth users are auto-verified (Google already verified the email)
  • No verification email sent for OAuth registrations

Email Configuration

Development Mode

NODE_ENV=development
  • Uses Ethereal Email (fake SMTP for testing)
  • Verification link printed to console
  • No real emails sent

Production Mode

NODE_ENV=production
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
EMAIL_FROM=noreply@yourapp.com

Recommended SMTP Providers:

  • Gmail SMTP (development, low volume)
  • SendGrid (production, high deliverability)
  • Mailgun (production, developer-friendly)
  • AWS SES (production, cost-effective)

Gmail Setup (Development)

  1. Enable 2-Factor Authentication
  2. Generate App Password: https://myaccount.google.com/apppasswords
  3. Use app password in SMTP_PASS

Database Schema

{
  isVerified: { type: Boolean, default: false },
  verificationToken: { type: String, select: false },
  verificationTokenExpires: { type: Date, select: false }
}

API Endpoints

POST /api/auth/signup

Response (Success):

{
  "success": true,
  "message": "Registration successful! Please check your email to verify your account.",
  "requiresVerification": true
}

GET /api/auth/verify-email/:token

Response (Success):

{
  "success": true,
  "message": "Email verified successfully! You are now logged in.",
  "user": { "id": "...", "isVerified": true }
}

User Experience

After Registration:

  • Shows message: "Check your email to verify your account"
  • Verification link expires in 30 minutes
  • In dev mode, link printed to server console

Login Attempt (Unverified):

  • Error: "Please verify your email before logging in"
  • User redirected to check email

Best Practices Implemented

Secure token generation (crypto.randomBytes)
Hashed token storage (SHA-256)
Time-limited tokens (30 min expiration)
Single-use tokens (deleted after verification)
No token exposure (only sent via email)
Clear error messages (user-friendly)
Auto-login after verification (seamless UX)
Production-ready email templates (HTML + plain text)

About

A complete, production-ready authentication system built with the MERN stack featuring JWT-based authentication and Google OAuth 2.0 login.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages