A full-featured, secure URL Shortener RESTful Web Application built using Node.js, Express.js, MongoDB (Mongoose), and Server-Side Rendering (EJS). The project implements strict MVC Architecture, stateless JWT Authentication (via HTTP-Only Cookies), and Role-Based Access Control (RBAC).
- 🏗️ Clean MVC Architecture: Modular structure separating Models (Schemas), Views (EJS Templates), Controllers (Business Logic), and Middlewares/Services.
- 🔐 JWT Authentication: Stateless session management using JSON Web Tokens set in secure browser cookies.
- 🛡️ Role-Based Access Control (RBAC) Middleware:
NormalUsers: Can generate short URLs, view, manage, and track click analytics for only their own generated links.AdminUsers: Possess elevated privileges to view and manage all generated URLs across the entire platform.
- 📈 Real-Time Click Analytics: Dynamic redirection tracking total visits and timestamps for each generated short URL.
- 🔒 Security & Best Practices: Middleware-level authorization checks, custom error handling, and environment-variable-ready (
.env) configuration.
- Runtime: Node.js (v18+)
- Framework: Express.js
- Template Engine: EJS (Embedded JavaScript)
- Database: MongoDB (Local Community Server & Atlas Ready)
- ODM Library: Mongoose
- Utilities: nanoid, nodemon, cookie-parser, uuid, jsonwebtoken, dotenv
- API Testing: Postman
- Version Control: Git, GitHub
- 🏗️ MVC Architecture – Clean separation of concerns with Models, Views, Controllers, Routes, and Services.
- 🔐 JWT Authentication & Cookies – Secure user signup/login system powered by JSON Web Tokens stored in HTTP-only cookies.
- 🛡️ Role-Based Access Control (RBAC) – Middleware-level authorization layer restricting routes based on user roles (
Admin,Normal). - 🖼️ Server-Side Rendering (SSR) – Clean, dynamic user interfaces rendered using the EJS templating engine.
- 🔗 Dynamic URL Shortening – Generates short, unique IDs using
nanoidfor fast link management. - 📊 Click Analytics & History – Tracks total clicks and logs visit timestamps inside MongoDB for every generated link.
- ⚙️ Centralized Environment Vault – Secure handling of sensitive keys (
MONGO_URL,JWT_SECRET,PORT) via.envintegration. - 🗄️ MongoDB & Mongoose Validation – Schema-level data validation and efficient database connectivity.
- ⚡ Developer Workflow – Instant auto-reloads during development powered by
nodemon.
| Tool / Library | Type | Purpose |
|---|---|---|
| Node.js | Runtime | JavaScript execution engine on server-side |
| Express.js | Framework | Fast, unopinionated web framework for Node.js |
| MongoDB | Database | NoSQL Document-based database |
| Mongoose | ODM Library | Schema-based modeling for MongoDB & Express |
| nodemon | Developer Tool | Automatically restarts the node application when file changes in the directory are detected |
| nanoid | Utility | Small, secure, URL-friendly unique string ID generator |
| EJS | Template Engine | Server-side rendering (SSR) of dynamic HTML templates |
| uuid | Utility | Cryptographically strong Universally Unique Identifier (UUID) generator (e.g., v4 for unique session/user IDs) |
| jsonwebtoken | Authentication | Generates and verifies digital signatures/tokens (JWT) to securely pass information between client & server |
| cookie-parser | Middleware | Express middleware to parse incoming request Cookie headers and populate req.cookies |
| dotenv | Utility | Loads environment variables from a .env file into process.env |
| Postman | API Client | Testing REST API endpoints (GET, POST, PATCH, DELETE) |
Generated: 8/2/2026, 1:35:39 PM
Root Path: workspace\Node
├── 📁 Learning
│ ├── 📁 Events
│ │ ├── 📄 main.js
│ │ └── 📄 test.txt
│ ├── 📁 Express
│ │ ├── ⚙️ .gitignore
│ │ ├── 📄 index.js
│ │ ├── ⚙️ package-lock.json
│ │ └── ⚙️ package.json
│ ├── 📁 First
│ │ ├── 📄 contacts.txt
│ │ ├── 📄 file.js
│ │ ├── 📄 file.txt
│ │ ├── 📄 math.js
│ │ ├── 📄 modules.js
│ │ ├── ⚙️ package.json
│ │ └── 📄 test.txt
│ ├── 📁 HTTP
│ │ └── 📄 http-notes.js
│ ├── 📁 RestAPI
│ │ ├── 📁 controllers
│ │ │ └── 📄 user.js
│ │ ├── 📁 logs
│ │ │ └── 📄 logs.txt
│ │ ├── 📁 middlewares
│ │ │ └── 📄 middleware.js
│ │ ├── 📁 models
│ │ │ └── 📄 user.js
│ │ ├── 📁 routes
│ │ │ └── 📄 user.js
│ │ ├── 📁 views
│ │ │ └── ⚙️ .gitkeep
│ │ ├── ⚙️ .gitignore
│ │ ├── ⚙️ MOCK_DATA.json
│ │ ├── 📄 connection.js
│ │ ├── 📄 index.js
│ │ ├── ⚙️ package-lock.json
│ │ └── ⚙️ package.json
│ ├── 📁 Server
│ │ ├── 📄 index.js
│ │ ├── 📄 log.txt
│ │ ├── ⚙️ package.json
│ │ └── 📄 url_note.js
│ └── 📁 Versions
│ └── 📄 version.js
├── 📁 Shortener_URL
│ ├── 📁 controllers
│ │ ├── 📄 static.js
│ │ ├── 📄 url.js
│ │ └── 📄 user.js
│ ├── 📁 middlewares
│ │ └── 📄 auth.js
│ ├── 📁 models
│ │ ├── 📄 url.js
│ │ └── 📄 user.js
│ ├── 📁 routes
│ │ ├── 📄 static.js
│ │ ├── 📄 url.js
│ │ └── 📄 user.js
│ ├── 📁 services
│ │ └── 📄 auth.js
│ ├── 📁 views
│ │ ├── 📄 home.ejs
│ │ ├── 📄 login.ejs
│ │ └── 📄 signup.ejs
│ ├── ⚙️ .gitignore
│ ├── 📄 app.js
│ ├── 📄 connect.js
│ ├── ⚙️ package-lock.json
│ ├── ⚙️ package.json
│ └── ⚙️ vercel.json
└── 📝 README.md
- Node.js (v16 or higher)
- npm package manager
- Basic knowledge of JavaScript
In the project directory, you can run the following commands configured in package.json:
npm startBefore deploying, ensure your database access is open to Vercel:
- Go to MongoDB Atlas.
- Navigate to Network Access under Security.
- Click Add IP Address and select Allow Access from Anywhere (
0.0.0.0/0). - Save changes.
Set up your environment variables in Vercel before or after deployment:
- In your Vercel Project Dashboard, go to Settings ➔ Environment Variables.
- Add your environment key-value pairs (e.g.,
MONGO_URL,JWT_SECRET,PORT). ⚠️ Important Requirement:- Ensure Production, Preview, and Development targets are ALL CHECKED.
- DO NOT toggle on the "Sensitive" option for
MONGO_URLto prevent variable save/sync issues.
- Push your latest code to GitHub.
- Go to vercel.com and log in.
- Click "New Project".
- Connect your GitHub repository.
- Select/Connect the exact project root folder containing
package.json(to avoid nested directory deployment issues). - Configure Build Settings:
- Vercel automatically detects Vite/Node settings.
- Toggle the "Build Command" switch and manually type
npm run buildto override it (if using a build step).
- Ensure all Environment Variables (
MONGO_URL, etc.) are added under the project settings. - Click "Deploy".
💡 Note: If you edit or update any Environment Variable after deploying, always go to the Deployments tab, click the three dots (
...) on the latest deployment, and select Redeploy to apply changes! & Make sure your project structure strictly follows the root layout:
Shortener_URL/
├── models/
├── routes/
├── middlewares/
├── views/
├── .env
├── app.js
├── connect.js
└── package.jsonDownload and install the LTS version from Node.js Official Site. Verify installation in your terminal:
node -v
npm -v- Download MongoDB Community Server from MongoDB Download Center.
- Download MongoDB Shell (
mongosh) to run CLI database operations. - Start the local server daemon:
# Verify connection using mongosh CLI
mongoshInitialize your Node project inside any project directory:
npm initpackage name: (name)
version: (1.0.0)
description: may add entry point: (index.js)
test command: just enter
git repository: (https://github.com/username/repo_name.git)
keywords: may add
author: may add
license: (ISC)
type: (commonjs) recommended module
Is this OK? (yes)
To enable modern ES6 import/export syntax instead of require(), open package.json and add "type": "module":
{
"name": "node",
"version": "1.0.0",
"bugs": {
"url": "https://github.com/username/repo/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/username/repo.git"
},
"license": "ISC",
"author": "",
"type": "commonjs",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node app.js" // add manually write "nodemon index.js" if installed
}
}
Run this command inside your project directory to install npm packages in the package.json file:
npm i express
npm i mongoose
npm i nanoid
npm i nodemon
npm i ejs
npm i cookie-parser
npm i uuid
npm i jsonwebtoken
npm i dotenvIt automatically creates package.json if not exist. Like
{
"name": "pakage name",
"version": "1.0.0",
"description": "Something",
"keywords": [
"keywords"
],
"homepage": "https://github.com/github.com/username#readme",
"bugs": {
"url": "https://github.com/github.com/username/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/github.com/username.git"
},
"license": "ISC",
"author": "Author",
"type": "module",
"main": "app.js",
"scripts": {
"start": "nodemon app.js"
},
"dependencies": {
"cookie-parser": "^1.4.7",
"dotenv": "^17.4.2",
"ejs": "^6.0.1",
"express": "^5.2.1",
"jsonwebtoken": "^9.0.3",
"mongoose": "^9.8.0",
"nanoid": "^6.0.0",
"nodemon": "^3.1.14",
"uuid": "^14.0.1"
}
}
Note: Install packages when needed
| Component / Module | Purpose |
|---|---|
index.js |
Main entry point; configures dotenv, EJS view engine, global middlewares (cookie-parser, express.json), DB connection, and routes. |
connect.js |
Handles async database connection setup using Mongoose to connect with MongoDB. |
models/url.js |
Mongoose schema for short links; stores shortId, redirectURL, visitHistory, and reference to createdBy user. |
models/user.js |
Mongoose schema for authentication; manages user details including name, email, password, and role (Normal, Admin). |
controllers/url.js |
Core URL business logic; generates unique shortIds via nanoid and logs click timestamps upon redirection. |
controllers/user.js |
Handles user authentication logic (HandleUserSignup, HandleUserLogin) and sets JWT cookies. |
services/auth.js |
Pure JWT token manager; encodes user payload on login (setUser) and decodes/verifies incoming tokens (getUser). |
middlewares/auth.js |
Security layer (AuthorizationHeaderVal, RestrictTo); extracts JWT cookies and enforces role-based access control. |
routes/url.js |
Protected URL endpoints (POST /url); restricted to authenticated roles (Normal, Admin). |
routes/static.js |
Handles SSR page rendering for home dashboard (/), signup (/signup), and login (/login) views. |
routes/user.js |
Endpoints for authentication workflows (POST /user/signup, POST /user/login). |
views/ |
Contains EJS template files (home.ejs, signup.ejs, login.ejs) for rendering the user interface. |
- Install Postman from 🌐 postman.com to test API's
💡 Note: Postman automatically manages the HTTP-only
tokencookie after login.
- Method & Route:
POST /user/signup - Body (JSON):
{
"name": "MehmoodCoder",
"email": "[email protected]",
"password": "Password123"
}- Method & Route:
POST /user/login - Body (JSON):
{
"email": "[email protected]",
"password": "Password123"
}- Response: Sets HTTP-only
tokencookie.
- Method & Route:
POST /url - Body (JSON):
{
"url": "[https://github.com/MehmoodCoder](https://github.com/MehmoodCoder)"
}- Response (201 Created):
{
"id": "8xK9p2Lm"
}- Method & Route:
GET /url/:shortId - Example:
http://localhost:4000/url/8xK9p2Lm - Response (
302 Found): Redirects to target destination & updates analytics.
If you need to clear all test documents without dropping the collection structure:
# 1. Open mongosh CLI
mongosh
# 2. Show All DB's
show dbs
# 3. Switch to project DB
use project-db-name
# 4. Show Exist DB collections
show collections
# 5. Show All Documents
db.collection.find({})
# 6. Delete all documents inside 'project-db-name' collection if wants
db.project-db-name.deleteMany({})
# 5. Exit the interactive MongoDB Shell session and return to the system terminal
.exit
# 6. And many more
- 🟢 Node.js Official Documentation – Core Node.js concepts & runtime docs
- ⚡ Express.js API Reference – Web framework, routing & middleware guides
- 🗄️ MongoDB Manual – NoSQL database features & queries
- 🍃 Mongoose Docs – ODM schemas, models, and queries
- 📦 NPM Official Registry – Package manager & dependency discovery
- 🔑 JSON Web Tokens (JWT) – Token-based authentication mechanics
- 🎨 EJS Templating Engine – Embedded JavaScript templates for SSR
- 🎲 nanoid Documentation – Unique string generator for short URLs
- 🧪 Postman Learning Center – API testing, environments & cookies
- ✅ MVC Architecture – Structuring backend apps using Models, Views, Controllers, Routes, and Services
- ✅ Authentication & JWT – Issuing, signing, and verifying JSON Web Tokens (JWT) for user authentication
- ✅ Cookie Management – Storing and parsing HTTP-only cookies safely with
cookie-parser - ✅ Role-Based Access Control (RBAC) – Restricting route access dynamically based on user roles (
Admin,Normal) - ✅ Server-Side Rendering (SSR) – Dynamic UI rendering with EJS and passing session data to views
- ✅ MongoDB & Mongoose Schema Design – Managing schemas, data types, unique constraints, and population
- ✅ Database Aggregation & Analytics – Array updates (
$push) for recording link click history and timestamps - ✅ Express Middleware Pipeline – Request body parsing (
json,urlencoded), auth state injection, and protected route guards - ✅ RESTful Endpoints & Redirection – Dynamic parameter handling (
req.params) and 302 HTTP redirects - ✅ Environment Vault & Tooling – Managing configuration variables via
.envand automated dev workflows withnodemon
MehmoodCoder
- 🔗 GitHub: github.com/MehmoodCoder
- 🌐 Portfolio: My Portfolio Link
This project is open source and available under the MIT License.
- 🔐 JWT Authentication System – Implemented user signup and login flows using JSON Web Tokens (JWT) for stateless authentication.
- 🍪 Cookie-Based Sessions – Integrated
cookie-parsermiddleware to securely pass and verify HTTP-only auth tokens. - 🛡️ Role-Based Access Control (RBAC) – Added authorization middlewares (
RestrictTo) to restrict endpoints based on user roles (Admin,Normal). - 🖼️ SSR Dashboard (EJS Integration) – Built server-side rendered views for user login, registration, and URL management dashboard.
- ⚙️ Environment Management – Centralized sensitive configurations (
PORT,MONGO_URL,JWT_SECRET) into.envfile setup.
- 🚀 Core Fundamentals – Built custom HTTP servers, learned EventEmitters, File System (
fs) operations, and NPM module handling. - 🛠️ RESTful API Architecture – Structured scalable Express servers following clean MVC (Model-View-Controller) patterns.
- ⚡ URL Shortener Microservice – Implemented
nanoidlogic to generate unique short IDs for long URLs. - 🗄️ MongoDB Integration – Connected Mongoose schemas with real-time URL redirect logic and automated visit analytics tracking.
- 🛠️ Developer Experience – Configured
nodemonfor auto-reloading during development and created custom logging middlewares.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request