This is a basic full stack website wherein I’ll create a basic webpage in which users can sign up using an email and password, store the email and password in MongoDB database, login in to the user account dashboard using the same credentials and logout. This way you can learn the foundations to create a full stack website/app.
Table of Contents
Step 1 (Initialization)
Create a project folder and open it in your code editor (VS Code etc.). Initialize the NodeJS project using the terminal command :
npm init -y
This creates a package.json
file.
Step 2 (Install required packages)
Install Required Packages and dependencies as shown below :
npm install express mongoose dotenv bcryptjs jsonwebtoken cors
express
→ Web framework for Node.jsmongoose
→ ODM (Object Data Modeling) for MongoDBdotenv
→ Loads environment variables from a.env
filebcryptjs
→ Hashes passwords for securityjsonwebtoken
→ Generates JWT tokens for authenticationcors
→ Allows cross-origin requests (needed when frontend interacts with backend)
Also, install nodemon (for development) to restart the server automatically when files change:
npm install --save-dev nodemon
Step 3 (Create server)
Set up the server by creating a new server.js file and add the following:
require("dotenv").config();
const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
// Initialize Express app
const app = express();
// Middleware
app.use(express.json());
app.use(cors());
// Connect to MongoDB
mongoose
.connect(process.env.MONGO_URI)
.then(() => console.log("MongoDB connected"))
.catch((err) => console.log(err));
// Simple Route
app.get("/", (req, res) => {
res.send("Backend is running...");
});
// Start Server
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Step 4 (Create environment variable)
Set up the environment variables by creating a .env
file in the root of your project and add:
PORT=5000
MONGO_URI=your_mongodb_connection_string
JWT_SECRET=your_secret_key
Replace your_mongodb_connection_string
with your MongoDB URI (you can get this from MongoDB Atlas) and choose a random JWT_SECRET
for signing tokens.
Step 5 (Start server)
Start your server with:
npx nodemon server.js
If everything is set up correctly, you should see:
MongoDB connected
Server running on port 5000
Step 6 (Models and Schema)
Create a new folder models
and inside it, create a file User.js
:
const mongoose = require("mongoose");
const UserSchema = new mongoose.Schema({
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
profile: {
name: { type: String, default: "" },
age: { type: Number, default: null },
bio: { type: String, default: "" }
}
}, { timestamps: true });
module.exports = mongoose.model("User", UserSchema);
The Schema above stores email and passwords, includes a profile with optional fields and uses timestamps.
Step 7 (Authentication)
We’ll now create authentication routes.
Create a new folder routes
and inside it, create a file auth.js
. Add the following authentication logic:
const express = require("express");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const User = require("../models/User");
const router = express.Router();
// Signup Route
router.post("/signup", async (req, res) => {
try {
const { email, password } = req.body;
// Check if user already exists
let user = await User.findOne({ email });
if (user) return res.status(400).json({ message: "User already exists" });
// Hash password
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
// Create new user
user = new User({ email, password: hashedPassword });
await user.save();
res.status(201).json({ message: "User created successfully" });
} catch (err) {
res.status(500).json({ message: "Server error" });
}
});
// Login Route
router.post("/login", async (req, res) => {
try {
const { email, password } = req.body;
// Check if user exists
let user = await User.findOne({ email });
if (!user) return res.status(400).json({ message: "Invalid credentials" });
// Compare passwords
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(400).json({ message: "Invalid credentials" });
// Generate JWT Token
const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { expiresIn: "1h" });
res.json({ token, userId: user._id });
} catch (err) {
res.status(500).json({ message: "Server error" });
}
});
module.exports = router;
Step 8 (add auth. route)
Open server.js
and add this line before the /
route:
app.use("/api/auth", require("./routes/auth"));
Step 9 (Testing in postman)
Test Authentication with Postman:
Sign Up Request
- Method:
POST
- URL:
http://localhost:5000/api/auth/signup
- Body (JSON):
{
"email": "test@example.com",
"password": "password123"
}
- Expected Response:
{
"message": "User created successfully"
}
Login Request
- Method:
POST
- URL:
http://localhost:5000/api/auth/login
- Body (JSON):
{
"email": "test@example.com",
"password": "password123"
}
- Expected Response:
{
"token": "your_generated_jwt_token",
"userId": "user_mongo_id"
}
Step 10 (middleware)
We’ll now head towards middleware and authentication.
Create a new folder middleware
and inside it, create a file authMiddleware.js
. Now, add the following code :
const jwt = require("jsonwebtoken");
const authMiddleware = (req, res, next) => {
const token = req.header("Authorization");
if (!token) {
return res.status(401).json({ message: "Access denied. No token provided." });
}
try {
const decoded = jwt.verify(token.replace("Bearer ", ""), process.env.JWT_SECRET);
req.user = decoded.userId;
next();
} catch (err) {
res.status(401).json({ message: "Invalid token." });
}
};
module.exports = authMiddleware;
This middleware checks for a valid token in the Authorization
header. If valid, it allows the request to proceed; otherwise, it denies access.
Step 11 (fetch/update user)
Create a new file inside routes
folder named user.js
and add the following code:
const express = require("express");
const authMiddleware = require("../middleware/authMiddleware");
const User = require("../models/User");
const router = express.Router();
// Get User Profile (Protected Route)
router.get("/profile", authMiddleware, async (req, res) => {
try {
const user = await User.findById(req.user).select("-password"); // Exclude password
if (!user) return res.status(404).json({ message: "User not found" });
res.json(user);
} catch (err) {
res.status(500).json({ message: "Server error" });
}
});
// Update User Profile (Protected Route)
router.put("/profile", authMiddleware, async (req, res) => {
try {
const { name, age, bio } = req.body;
const updatedUser = await User.findByIdAndUpdate(req.user, {
$set: { "profile.name": name, "profile.age": age, "profile.bio": bio }
}, { new: true }).select("-password");
res.json(updatedUser);
} catch (err) {
res.status(500).json({ message: "Server error" });
}
});
module.exports = router;
GET /profile
→ Fetches user profile (protected) and PUT /profile
→ Updates user profile (protected).
Step 12 (add user route)
Open server.js
and add this line before the /
route:
app.use("/api/user", require("./routes/user"));
Step 13 (Final testing)
Test with Postman :
Fetch Profile (GET)
- Method:
GET
- URL:
http://localhost:5000/api/user/profile
- Headers:
Authorization: Bearer your_jwt_token
- Expected Response:
{
"_id": "user_mongo_id",
"email": "test@example.com",
"profile": {
"name": "",
"age": null,
"bio": ""
},
"createdAt": "2025-02-11T10:00:00.000Z",
"updatedAt": "2025-02-11T10:00:00.000Z"
}
Update Profile (PUT)
- Method:
PUT
- URL:
http://localhost:5000/api/user/profile
- Headers:
Authorization: Bearer your_jwt_token
- Body (JSON):
{
"name": "John Doe",
"age": 25,
"bio": "Full Stack Developer"
}
- Expected Response:
{
"_id": "user_mongo_id",
"email": "test@example.com",
"profile": {
"name": "John Doe",
"age": 25,
"bio": "Full Stack Developer"
},
"createdAt": "2025-02-11T10:00:00.000Z",
"updatedAt": "2025-02-11T10:10:00.000Z"
}
Step 14 (Frontend)
Now we’ll move on to the frontend section.
Create a frontend folder inside your project and create three files index.html, login.html and dashboard.html.
Step 15 (Homepage)
Create index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Signup</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h2>Signup</h2>
<form id="signup-form">
<input type="email" id="email" placeholder="Email" required>
<input type="password" id="password" placeholder="Password" required>
<button type="submit">Signup</button>
</form>
<p>Already have an account? <a href="login.html">Login</a></p>
<script>
document.getElementById("signup-form").addEventListener("submit", async (e) => {
e.preventDefault();
const email = document.getElementById("email").value;
const password = document.getElementById("password").value;
const res = await fetch("http://localhost:5000/api/auth/signup", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password })
});
const data = await res.json();
if (res.ok) {
alert("Signup successful! Please login.");
window.location.href = "login.html";
} else {
alert(data.message);
}
});
</script>
</body>
</html>
Step 16 (Login page)
Create login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h2>Login</h2>
<form id="login-form">
<input type="email" id="email" placeholder="Email" required>
<input type="password" id="password" placeholder="Password" required>
<button type="submit">Login</button>
</form>
<p>Don't have an account? <a href="index.html">Sign up</a></p>
<script>
document.getElementById("login-form").addEventListener("submit", async (e) => {
e.preventDefault();
const email = document.getElementById("email").value;
const password = document.getElementById("password").value;
const res = await fetch("http://localhost:5000/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password })
});
const data = await res.json();
if (res.ok) {
localStorage.setItem("token", data.token);
alert("Login successful!");
window.location.href = "dashboard.html";
} else {
alert(data.message);
}
});
</script>
</body>
</html>
Step 17 (Dashboard)
Create dashboard.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h2>Welcome to your Dashboard</h2>
<div id="profile"></div>
<button onclick="logout()">Logout</button>
<script>
async function fetchProfile() {
const token = localStorage.getItem("token");
if (!token) {
window.location.href = "login.html";
return;
}
const res = await fetch("http://localhost:5000/api/user/profile", {
method: "GET",
headers: { "Authorization": "Bearer " + token }
});
const data = await res.json();
if (res.ok) {
document.getElementById("profile").innerHTML = `
<p>Email: ${data.email}</p>
<p>Name: ${data.profile.name || "Not set"}</p>
<p>Age: ${data.profile.age || "Not set"}</p>
<p>Bio: ${data.profile.bio || "Not set"}</p>
`;
} else {
alert("Session expired. Please login again.");
localStorage.removeItem("token");
window.location.href = "login.html";
}
}
function logout() {
localStorage.removeItem("token");
window.location.href = "login.html";
}
fetchProfile();
</script>
</body>
</html>
Step 18 (The End)
Now start the server again and open index.html in your browser and test the signup, login, view dashboard and logout functionality. It should work now if you sign up using an email id and password. You can also see the dashboard and logout option. If you go to the MongoDB backend you should also see the email and password being saved inside your database which you’ve just created.