Full-stack authentication project built with React + Vite on the frontend and Node.js + Express + MongoDB on the backend.
It includes:
- Signup and login
- JWT authentication with HTTP-only cookies
- Email verification with OTP
- Password reset with OTP
- Protected user profile endpoint
- Overview
- Tech Stack
- Features
- Architecture
- Folder Structure
- Environment Variables
- Installation
- Running the App
- API Reference
- End-to-End Flows
- Security Notes
- Common Issues and Fixes
- Available Scripts
- Future Improvements
This project demonstrates a complete auth workflow commonly used in real web apps:
- User creates account
- Password is hashed with bcrypt
- JWT is generated and stored in cookie
- User can verify email with a one-time password
- User can reset password via OTP email
- Protected routes read JWT from cookie and authorize access
- React
- Vite
- Tailwind CSS
- React Router
- Axios
- React Toastify
- Node.js
- Express
- MongoDB + Mongoose
- JSON Web Token (jsonwebtoken)
- bcryptjs
- cookie-parser
- CORS
- Nodemailer (Brevo SMTP relay)
- Account registration and login
- Encrypted password storage
- Cookie-based session handling using JWT
- Email verification OTP generation and validation
- Password reset OTP generation and validation
- OTP expiry checks on backend
- Protected route middleware
- Auth state check endpoint for frontend session recovery
- Render auth screens and forms
- Validate user input at UI level
- Send API requests with credentials
- Display success/error toasts
- Redirect based on auth state
- Validate payloads
- Manage user data in MongoDB
- Hash and compare passwords
- Sign and verify JWTs
- Send OTP emails
- Enforce authorization on protected routes
- JWT payload includes user id
- JWT stored in HTTP-only cookie named token
- Middleware reads and verifies token
- User id is attached to request object as req.userId
Authentication-System/
backend/
config/
mongodb.js
nodemailer.js
controllers/
auth.controller.js
user.controller.js
middleware/
user.middleware.js
models/
user.model.js
routes/
auth.routes.js
user.routes.js
server.js
package.json
frontend/
src/
assets/
components/
context/
pages/
App.jsx
main.jsx
index.css
package.json
Create this file: backend/.env
PORT=4000
NODE_ENV=development
MONGO_URI=your_mongodb_connection_string
JWT_SECRET=your_super_secret_key
SMTP_USER=your_brevo_smtp_user
SMTP_PASS=your_brevo_smtp_password
SENDER_EMAIL=your_verified_sender_emailCreate this file: frontend/.env
VITE_BACKEND_URL=http://localhost:4000git clone <your-repo-url>
cd Authentication-Systemcd backend
npm installcd ../frontend
npm installStart backend in one terminal:
cd backend
npm run devStart frontend in another terminal:
cd frontend
npm run devDefault URLs:
- Frontend: http://localhost:5173
- Backend: http://localhost:4000
Base URL: http://localhost:4000
Request body:
{
"name": "John Doe",
"email": "john@example.com",
"password": "123456"
}Success response:
{
"success": true
}Request body:
{
"email": "john@example.com",
"password": "123456"
}Clears auth cookie.
Sends verification OTP to logged-in user email.
Request body:
{
"otp": "123456"
}Checks whether current cookie token is valid.
Request body:
{
"email": "john@example.com"
}Request body:
{
"email": "john@example.com",
"otp": "123456",
"newPassword": "newStrongPassword"
}Returns user profile summary.
- User submits name/email/password
- Backend hashes password and creates user
- JWT cookie is set
- Frontend updates auth state
- User clicks Verify Email
- Backend creates 6-digit OTP and expiry
- OTP email sent via SMTP
- User submits OTP
- Backend marks account as verified
- User submits email on reset screen
- Backend sends reset OTP email
- User enters OTP and new password
- Backend validates OTP + expiry
- Password is re-hashed and updated
- Passwords are stored as bcrypt hashes
- JWT token is stored in HTTP-only cookie
- OTPs are time-limited
- Protected endpoints require verified JWT
- In production, secure cookie and strict CORS config are required
Ensure frontend/.env has:
VITE_BACKEND_URL=http://localhost:4000Then restart Vite dev server after changing env.
- Confirm frontend origin is included in allowedOrigins in backend/server.js
- Use axios with credentials enabled
- Do not use wildcard origin when credentials are enabled
- Check SMTP_USER and SMTP_PASS
- Check spam folder
- Verify sender email matches SMTP provider rules
- Verify MONGO_URI
- Ensure IP/network access is allowed in MongoDB provider
- npm run dev: run backend with nodemon
- npm start: run backend with node
- npm run dev: start Vite dev server
- npm run build: production build
- npm run preview: preview production build
- npm run lint: run ESLint
- Add refresh token flow
- Add rate limiting on OTP and auth routes
- Add request validation middleware
- Add unit and integration tests
- Add Docker support
- Add account lockout after repeated failed attempts
Shaurya Singh