Build a Complete Full-Stack Authentication System using Node.js, Express, MongoDB, and JWT
In this tutorial, you will learn how to build a complete Full Stack Authentication System using modern backend technologies like Node.js, Express, MongoDB, and JWT. This project is widely used in real-world applications such as dashboards, SaaS apps, and e-commerce platforms.
📌 Project Overview
Authentication is one of the most important parts of any web application. It ensures that only authorized users can access protected resources. In this project, we will build a secure authentication system with the following features:
- User registration (Signup)
- User login system
- Password hashing using bcrypt
- JWT token-based authentication
- Protected routes using middleware
- Logout functionality
We will also connect a frontend using HTML and JavaScript Fetch API to interact with backend APIs.
⚙️ Step 1: Project Setup (Node.js Initialization)
First, create a new folder and initialize Node.js project.
mkdir auth-system
cd auth-system
npm init -y
Install required dependencies:
npm install express mongoose bcryptjs jsonwebtoken cors dotenv
These packages help us build a secure backend system.
🚀 Step 2: Creating Express Server
Now create a file called server.js and set up a basic Express server.
const express = require("express");
const app = express();
const cors = require("cors");
app.use(express.json());
app.use(cors());
app.get("/", (req, res) => {
res.send("Server is running...");
});
app.listen(5000, () => {
console.log("Server started on port 5000");
});
At this point, your backend server is ready.
🗄️ Step 3: Connecting MongoDB Database
We will use MongoDB to store user data securely.
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost:27017/authDB")
.then(() => console.log("MongoDB Connected"))
.catch(err => console.log(err));
Make sure MongoDB is installed and running on your system.
👤 Step 4: Creating User Schema
We define how user data will be stored in the database.
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
username: String,
email: String,
password: String
});
module.exports = mongoose.model("User", userSchema);
🔐 Step 5: Password Hashing using bcrypt
We never store plain passwords. Instead, we hash them using bcrypt.
const bcrypt = require("bcryptjs");
const hashedPassword = await bcrypt.hash(password, 10);
This makes your system much more secure.
🔑 Step 6: JWT Authentication System
JWT (JSON Web Token) is used to securely transfer user authentication data.
const jwt = require("jsonwebtoken");
function createToken(user) {
return jwt.sign({ id: user._id }, "secretKey", { expiresIn: "1h" });
}
📝 Step 7: Signup API Route
app.post("/signup", async (req, res) => {
const { username, email, password } = req.body;
const hashedPassword = await bcrypt.hash(password, 10);
const user = new User({
username,
email,
password: hashedPassword
});
await user.save();
res.send("User Registered Successfully");
});
🔓 Step 8: Login API Route
app.post("/login", async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user) return res.send("User not found");
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.send("Invalid credentials");
const token = jwt.sign({ id: user._id }, "secretKey", { expiresIn: "1h" });
res.json({ token });
});
🛡️ Step 9: Middleware for Protected Routes
Middleware checks if user is authenticated before accessing protected routes.
function verifyToken(req, res, next) {
const token = req.headers["authorization"];
if (!token) return res.send("Access denied");
try {
jwt.verify(token, "secretKey");
next();
} catch {
res.send("Invalid token");
}
}
🌐 Step 10: Frontend Integration (HTML + Fetch API)
fetch("http://localhost:5000/login", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
email: "test@gmail.com",
password: "123456"
})
})
.then(res => res.json())
.then(data => {
localStorage.setItem("token", data.token);
});
⏳ Step 11: Token Expiry Handling
We set token expiration time to improve security.
jwt.sign({ id: user._id }, "secretKey", { expiresIn: "1h" });
After 1 hour, the user must login again.
🚪 Step 12: Logout System
function logout() {
localStorage.removeItem("token");
window.location.href = "/login.html";
}
🌍 Real-World Applications
- E-commerce websites
- Admin dashboards
- Online learning platforms
- SaaS applications
- Banking systems
⚠️ Common Mistakes
- Storing passwords without hashing
- Not using HTTPS
- Hardcoding secret keys
- Not validating user input
❓ FAQs
1. What is JWT?
JWT is a token-based authentication system used to securely transmit user data.
2. Why use bcrypt?
Bcrypt is used to securely hash passwords before storing them in the database.
3. Is this system production-ready?
Yes, but you should add advanced security features for production use.
4. Can I use SQL instead of MongoDB?
Yes, you can use MySQL or PostgreSQL as alternatives.
5. What is middleware?
Middleware is a function that runs before accessing protected routes.
🎯 Conclusion
In this tutorial, you learned how to build a complete full-stack authentication system using Node.js, Express, MongoDB, and JWT.
This project is a strong foundation for real-world web development and backend engineering.
Keep practicing and integrate this system into larger applications to improve your skills.

Join the conversation