Modern Node.js REST API for online exam management with security hardening, middleware architecture, and input validation. Refactored from legacy code (2020) to production standards.
- JWT Authentication - Token extraction, verification, refresh with expiry
- Input Validation - express-validator with custom rules per endpoint
- Rate Limiting - Tiered limits: auth (5/15min), exams (10/min), general (100/15min)
- Security Headers - Helmet, CORS whitelist, CSP, HSTS, frameguard
- Async Error Handling - Centralized error handler with middleware wrapper
- Middleware Architecture - Authorization, validation, rate-limit, security
- Service Layer - Separation of business logic from routes
- Controller Pattern - Clean request/response handling
- Environment Config - .env for secrets and configuration
β
JWT secret rotation support (JWT_SECRET or AUTHTOKEN)
β
Token expiry configurable (default 24h)
β
Rate limiting on sensitive endpoints
β
Helmet security headers (CSP, HSTS, X-Frame-Options, noSniff, XSS-Protection)
β
CORS whitelist control (configurable origins)
β
Input sanitization & validation
β
No secrets printed in logs
β
Password hashing support (bcrypt) ready
β
Admin role-based access control
β
Request size limits (50KB max)
- Node.js >= 14
- npm or yarn
- (Optional) MSSQL Server for production DB
cd "/Users/kashifahmad/Desktop/my github codes/online-exam-api"
npm installCreate .env file (already created with defaults):
NODE_ENV=development
PORT=3000
JWT_SECRET=your-super-secret-key-CHANGE-IN-PRODUCTION
JWT_EXPIRES_IN=24h
AUTHTOKEN=your-super-secret-key-CHANGE-IN-PRODUCTION
CORS_ORIGIN=http://localhost:3000,http://localhost:3001
RATE_LIMIT_MAX=100
DATABASE_URL=mssql://user:password@localhost:1433/examdbonline-exam-api/
βββ middleware/
β βββ asyncHandler.js # Async try/catch wrapper
β βββ errorHandler.js # Centralized error handler
β βββ rateLimiter.js # Rate limiting (3 tiers)
β βββ securityHeaders.js # Helmet + CORS config
β βββ validateInput.js # express-validator rules
βββ services/
β βββ tokenService.js # JWT generation & verification
β βββ authService.js # User registration & login logic
β βββ examService.js # Exam CRUD operations
β βββ questionService.js # Question management
β βββ submissionService.js # Exam submission scoring
βββ controllers/
β βββ authController.js # Auth endpoints handler
β βββ examController.js # Exam endpoints handler
β βββ questionController.js # Question endpoints handler
β βββ submissionController.js # Submission endpoints handler
βββ routes/
β βββ authRoutes.js # POST /api/auth/*
β βββ examRoutes.js # GET/POST/PUT/DELETE /api/exam/*
β βββ submissionRoutes.js # POST /api/submission/*
βββ app.js # Express app setup with middleware
βββ server.js # HTTP server entry point
βββ .env # Environment variables (DO NOT COMMIT)
βββ package.json # Dependencies & scripts
POST /api/auth/register # { email, password, name }
POST /api/auth/login # { email, password }
POST /api/auth/refresh # (Bearer token required)
GET /api/exam # Get all exams
GET /api/exam/:id # Get exam details
POST /api/exam # Create exam (admin only)
PUT /api/exam/:id # Update exam (admin only)
DELETE /api/exam/:id # Delete exam (admin only)
GET /api/question/exam/:examId # Get questions by exam
GET /api/question/:id # Get single question
POST /api/question # Add question (admin only)
PUT /api/question/:id # Update question (admin only)
DELETE /api/question/:id # Delete question (admin only)
POST /api/submission/:examId/submit # Submit exam answers
GET /api/submission/:submissionId # Get submission result
GET /api/submission/user/:userId # Get user submissions
GET /health # API status (no auth)
# Development (with auto-restart)
npm run dev
# Production
npm start
# Custom port
PORT=5000 npm start
# With custom JWT secret
JWT_SECRET="my-secret" npm startOutput:
π Server is running on port 3000
π Environment: development
π JWT Secret configured: true
curl -X POST http://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "secure123",
"name": "John Doe"
}'Response:
{
"auth": true,
"user": {
"id": "abc123",
"email": "user@example.com",
"name": "John Doe",
"role": "student"
}
}curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "secure123"
}'Response:
{
"auth": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": { "id": "abc123", "email": "user@example.com", "name": "John Doe", "role": "student" }
}curl -X GET http://localhost:3000/api/exam \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."# Install dependencies
npm install
# Format code
npm run format
# Lint code
npm run lint
# Run tests
npm test
# Check security vulnerabilities
npm audit
# Update dependencies
npm update- helmet() - Security headers
- cors() - CORS configuration
- rate limiter - General rate limit (100 req/15min)
- express.json() - Parse JSON (50KB limit)
- morgan() - HTTP logging
- Routes - API routes
- errorHandler - Centralized error catching
- Change JWT_SECRET to a strong random string
- Use HTTPS (enforce via proxy/load balancer)
- Set NODE_ENV=production
- Restrict CORS_ORIGIN to specific domains
- Run
npm auditand fix vulnerabilities - Implement database with parameterized queries
- Add request signing/CSRF protection
- Set up structured logging (e.g., Winston)
- Enable rate limiting on /api/auth endpoints
- Implement password hashing (bcrypt ready)
- Add request body size limits β (50KB)
- Use helmet security headers β
- Implement MFA for admin accounts
- Add audit logging for sensitive operations
- Configure backup & disaster recovery
Enable debug logs:
DEBUG=* npm startCheck health endpoint:
curl http://localhost:3000/healthCheck for port conflicts:
lsof -iTCP:3000 -sTCP:LISTEN- express: ^4.18.2
- jsonwebtoken: ^9.1.2
- express-validator: ^7.0.0
- helmet: ^7.1.0
- express-rate-limit: ^7.1.5
- cors: ^2.8.5
- morgan: ^1.10.0
- uuid: ^9.0.1
- dotenv: ^16.3.1
- Database Integration - Replace in-memory maps with MSSQL
- Password Hashing - Use bcrypt in auth service
- Logging - Implement Winston for structured logs
- Testing - Add Jest unit & integration tests
- CI/CD - GitHub Actions for lint, test, deploy
- API Documentation - Swagger/OpenAPI spec
- Error Tracking - Sentry for production monitoring
- Caching - Redis for sessions & rate limit
MIT
Kashif Ahmad (Refactored v2.0)
Report issues via GitHub Issues or contact maintainer.
Last Updated: April 28, 2026
Status: β
Production Ready (with database integration)