A secure, scalable, and production-style backend system built using Node.js, Express, and MongoDB, implementing hybrid authentication (JWT + Session), role-based access control, and real-world security practices.
Most backend projects stop at:
- Basic JWT authentication
- Simple CRUD APIs
- No session management or security depth
This project goes beyond that.
It is designed to demonstrate:
β Real-world authentication architecture β Security-first backend design β Clean layered architecture β Stateful session control over stateless JWT β Production-ready backend practices
The backend is live and deployed in production:
https://production-ready-backend-api-system.onrender.com
This project is deployed on the free tier of Render, which uses a spin-down mechanism during inactivity.
- If the service is idle, it is automatically stopped
- On the next incoming request, the server boots up again
π As a result:
First request may take ~30β50 seconds (cold start)
Subsequent requests are fast and normal
This behavior is expected in free-tier environments and does not affect functionality.
- Hosting: Render
- Database: MongoDB Atlas
- Environment: Production (cloud-based)
- Server runs in a stateless cloud environment
- Filesystem is ephemeral (non-persistent)
- External dependencies (Geo DB) are handled dynamically
- Environment variables are managed via Render dashboard
Follow these steps to run the project locally.
git clone https://github.com/vijay-kumar2001/production-ready-backend-api-system.git
cd production-ready-backend-api-systemnpm installCreate a .env file in the root:
cp .env.example .envNow update values inside .env:
DB_URL=your-mongodb-connection-string
JWT_SECRET=your-secret-key
MAXMIND_LICENSE_KEY=your_license_keyThis project uses MaxMind GeoLite2 City database for IP-based location detection.
You can manually download the database:
- Visit MaxMind website
- Download
GeoLite2-City.mmdb - Place it in:
src/geo/
In production, the system:
β Automatically downloads Geo DB at runtime
β Extracts from tar.gz archive
β Stores in correct path
β Cleans temporary files
π This ensures:
β No manual setup required
β Works across deployments
β Handles missing files automatically
npm run devServer will run on:
http://localhost:3020
- Import Postman collection from
/postmanfolder - Or test manually using any API client
- Ensure MongoDB is running locally or use a cloud DB
- Do NOT commit your
.envfile - Geo database is handled automatically in production
- Admin user is auto-seeded if enabled in config
Client β Middleware β Controller β Service β Model β Database
| Layer | Responsibility |
|---|---|
| Middleware | Validation, Authentication, Authorization |
| Controller | Request/Response handling |
| Service | Business logic + security enforcement |
| Model | Database interaction |
| Utils | Stateless helpers (JWT, hashing, geo) |
This project uses a Hybrid Auth Model combining JWT + Sessions.
- Sent via
Authorization: Bearer <token> - Used for protected APIs
- Stateless but short-lived for security
- Stored in HTTP-only cookie
- Used only for token renewal
- Never exposed to frontend JS
Each login creates a session storing:
- sessionId
- userId
- IP address
- device & user-agent
- expiry timestamp
π This converts JWT from stateless β state-aware system
Login β Session Created β Tokens Generated
β
Access Token β Used for APIs
β
Expires β Refresh Token Used
β
New Tokens Issued + Session Extended
On every refresh:
- Old refresh token is deleted
- New refresh token is issued and stored
Old Token β Invalid
New Token β Active
β Prevents replay attacks β Stolen tokens become useless after one use β Ensures single-use refresh tokens
Each valid request:
session.expiresAt = now + SESSION_EXPIRES_IN
β Prevents auto logout during activity β Maintains user experience β Ensures session expires only after inactivity
π This is a sliding window session mechanism
- Refresh token rotation
- Session validation on every request
- Token type separation (access vs refresh)
- HTTP-only cookies (XSS protection)
- Role-based access control (RBAC)
- Ownership validation (resource-level security)
- Input validation & sanitization
- Centralized error handling middleware
| Attack | Protection |
|---|---|
| Replay attack | Token rotation |
| Token reuse after theft | Rotation + session |
| Token swapping | sessionId verification |
| XSS token access | httpOnly cookies |
| Privilege escalation | RBAC |
| Horizontal access abuse | owner checks |
| Invalid input injection | validation middleware |
User β Session β Refresh Token β Access Token
- Session = source of truth
- Tokens = derived credentials
The system uses a custom AppError class + global error middleware.
β Consistent error responses β Clean controller/service code β Separation of logic vs error formatting
Example:
{
"message": "Invalid token",
"status": 401
}- Register / Login
- Refresh token flow
- Logout (idempotent)
- Token rotation implemented
- Profile retrieval
- Session inspection
- Secure user data sanitization
- Get all users (admin only)
- Get user by ID (owner/admin)
- Update user roles (admin only)
- Create β register user
- Read β profile, users
- Update β role update
- Delete β logout (session + token removal)
- Centralized config object
- Type-safe env parsing
- Required/optional validation
- Feature-based config separation
This system implements dynamic dependency management:
β Not stored in repository
β Not manually uploaded
β Automatically downloaded on startup
β Always available when server runs
β Works in cloud environments
β Handles ephemeral filesystem
β Eliminates manual setup errors
β Improves reliability
/config β Environment + feature configs
/controllers β Request handling
/services β Business logic
/models β Database layer
/middlewares β Auth, validation, RBAC
/routes β API routes
/utils β JWT, bcrypt, geo
/db β DB connection
/scripts β Admin seeding
/error-lab β AppError + error middleware
Example:
JWT_SECRET=super-secret-key
JWT_ACCESS_EXPIRES_IN=5m
JWT_REFRESH_EXPIRES_IN=14d
SESSION_EXPIRES_IN=1209600000
COOKIE_HTTP_ONLY=true
- email (unique)
- password (bcrypt hashed)
- role
- sessionId
- userId
- device info
- expiresAt
- refreshToken (unique)
- sessionId (indexed)
- Token rotation deletes old entries
- Session expiry checked per request
- Logout removes session + tokens
.lean()used for optimized reads
- Validate Authorization header
- Verify access token
- Validate session from DB
- Extend session (sliding window)
- Attach
req.user
JWT alone:
β Cannot revoke β Vulnerable to misuse
This system:
β Adds session control β Enables logout & invalidation β Tracks active users
β Prevents replay attacks β Limits token lifetime even if stolen
β Improves UX β Keeps system secure & active
β Separation of concerns β Reusable business logic β Cleaner controllers
β Large size (~60MB)
β Not scalable
β Not production-friendly
β Always available
β Works across environments
β No manual intervention
β Production-grade approach
β Handles Render health checks
β Prevents unnecessary 404 logs
β Improves observability
Tested using structured Postman collection:
- Positive flows
- Negative scenarios
- Security edge cases
- DB state verification (MongoDB Atlas)
All APIs can be tested using:
BASE_URL = https://production-ready-backend-api-system.onrender.com
1. Register user
2. Login
3. Access protected routes
4. Refresh token
5. Test admin routes
β Users collection updates
β Sessions created
β Tokens rotated
β Roles updated
All routes are tested on production and follow consistent request/response patterns.
Base URL:
https://production-ready-backend-api-system.onrender.com
POST /auth/registerBody:
{
"email": "user@example.com",
"password": "your-password"
}Response:
{
"message": "User registered successfully",
"user": {
"_id": "...",
"email": "...",
"role": "user"
}
}POST /auth/loginBody:
{
"email": "user@example.com",
"password": "your-password"
}Response:
{
"message": "Login successful",
"accessToken": "...",
"user": {
"_id": "...",
"email": "...",
"role": "user"
}
}Behavior:
- Sets
refreshTokenin httpOnly cookie - Creates session in DB
- Captures device + IP + geo (if available)
POST /auth/refreshHeaders:
Cookie: refreshToken=...
Response:
{
"message": "Token refreshed",
"accessToken": "..."
}Behavior:
- Rotates refresh token
- Extends session (sliding session)
- Invalidates old refresh token
POST /auth/logoutResponse:
{
"message": "user logged out."
}Behavior:
- Deletes session
- Deletes refresh tokens
- Clears cookie
- Invalidates all authentication state
GET /profileHeaders:
Authorization: Bearer <accessToken>
Response:
{
"message": "Profile fetched",
"user": {...},
"session": {...}
}Behavior:
- Requires valid access token
- Verifies session from DB
- Extends session expiry
- Returns session metadata (device, IP, location)
β οΈ Admin credentials are not exposed publicly. Use your own seeded admin or create via controlled setup.
GET /usersHeaders:
Authorization: Bearer <adminToken>
Response:
{
"message": "Users fetched successfully",
"users": [...]
}Behavior:
- Only accessible by admin
- Returns sanitized user data
GET /users/:idHeaders:
Authorization: Bearer <accessToken>
Behavior:
- Owner β allowed
- Admin β allowed
- Others β 403 Forbidden
PUT /users/:id/<role>Headers:
Authorization: Bearer <adminToken>
Content-Type: application/json
Body:
{
}Behavior:
- Only admin allowed
- Updates role immediately in DB
- Prevents invalid role values
- Allowed roles : admin,user
DELETE /users/:idHeaders:
Authorization: Bearer <accessToken>
Behavior:
- Owner β can delete own account
- Admin β can delete any user
- Other users β 403 Forbidden
Response (Owner Self Delete):
{
"message": "Your account deleted",
"user": {
"_id": "...",
"email": "...",
"role": "user"
}
}Response (Admin Delete):
{
"message": "User deleted",
"user": {
"_id": "...",
"email": "...",
"role": "user"
}
}Internal Cleanup Performed:
1. Validate target user exists
2. Retrieve all sessions of that user
3. Extract all sessionIds
4. Delete refresh tokens linked to those sessionIds
5. Delete all sessions of that user
6. Delete the user document itself
Why this matters:
- Prevents orphaned sessions
- Prevents stale refresh token reuse
- Ensures deleted users lose future access immediately
- Maintains authentication consistency across the system
This project now implements full production-style CRUD behavior:
Create β Register User
Read β Profile, Get Users, Get User by ID
Update β Update User Role
Delete β Delete User + Logout (session/token cleanup)
Unlike basic CRUD systems, delete operations here include:
β Ownership validation
β RBAC enforcement
β Authentication cleanup
β Session invalidation
β Refresh token cleanup
This makes DELETE a security-aware operation, not just database removal.
The delete route was fully tested on the deployed production server.
β User self-delete β successful
β Admin delete another user β successful
β Unauthorized delete attempt β 403 Forbidden
β Invalid / already deleted user β 404 Not Found
β Old access after deletion β 401 Unauthorized
β Sessions removed from DB
β Refresh tokens removed from DB
- Postman (Production API)
- MongoDB Atlas (users + sessions + refreshTokens verification)
This confirms full authentication cleanup and secure lifecycle handling.
All errors follow consistent structure:
{
"message": "Error message",
"status": 400
}Register β Login β Access Protected Routes
β
Access Token Expires
β
Refresh Token Used
β
New Tokens Issued (Rotation)
β
Logout β Session + Tokens Destroyed
The system has been tested for:
β Positive flows (all routes)
β Negative cases (invalid token, missing token)
β RBAC enforcement
β Ownership validation
β Token rotation correctness
β Session lifecycle (create β extend β destroy)
β Database consistency (MongoDB Atlas)
β External dependency behavior (GeoDB)
β Stateless JWT enhanced with stateful session validation
β Token misuse prevented via rotation
β Session acts as source of truth
β Authorization enforced at multiple levels (auth + role + ownership)
β System remains consistent across local and production environments
This system has been tested end-to-end on the deployed environment.
β User registration β reflected in MongoDB Atlas
β Login β session + tokens created
β Refresh β token rotation confirmed
β Logout β session + tokens removed
β Profile β session + device + geo data returned
β Admin routes β RBAC enforced correctly
- Postman (production API testing)
- MongoDB Atlas (real-time DB verification)
π This ensures the system is not just functional locally, but behaves correctly in real-world deployment.
This is NOT:
β Basic CRUD project β Simple JWT implementation
This IS:
β Hybrid authentication system β Session-aware backend β Security-focused design β Production-style architecture β Real-world token lifecycle management β Cloud deployment + runtime dependency handling
β Deployed on cloud (Render)
β Uses managed database (MongoDB Atlas)
β Handles environment-based configuration
β Supports runtime dependency setup
β Designed for real-world infrastructure
- Node.js
- Express.js
- MongoDB + Mongoose
- JWT (jsonwebtoken)
- bcryptjs
- cookie-parser
- Axios (stream-based downloads)
- tar (archive extraction)
- MaxMind (Geo IP database)
β Difference between local vs production systems
β Handling ephemeral file systems
β Runtime dependency management
β Debugging deployment logs
β Managing external APIs securely
β Designing self-healing backend systems
This project demonstrates:
- Deep understanding of authentication systems
- Token lifecycle management
- Backend security practices
- Scalable architecture design
- Clean code organization
- Rate limiting
- CSRF protection
- Refresh token hashing
- Device/session management UI
- Logging system (Winston)
This project is not just about APIs β itβs about building a secure backend system with real-world constraints and behavior.
Give it a β and feel free to explore or suggest improvements!