Full Authentication Flow using MongoDB, Bcrypt, JWT & Cookies


A beginner-friendly, explanation of how authentication works using MongoDB, JWT, Bcrypt, and Cookies — with a little code so you can copy-paste and test it easily.
🧍 1. User Signup (Registration)
When a new user signs up:
They enter their email and password.
We never store passwords directly. Instead, we use
bcrypt
to hash it:
const bcrypt = require("bcryptjs");
const hashedPassword = await bcrypt.hash(password, 10); // 10 = salt rounds
- The hashed password is saved to MongoDB, not the plain text one.
Example:
const newUser = await User.create({
email: email,
password: hashedPassword,
isVerified: false
});
This keeps your database secure, even if it gets hacked.
📧 2. Email Verification (Optional but Good Practice)
After signup, we send an email verification link.
The link contains a JWT token that expires in 24 hours.
const jwt = require("jsonwebtoken");
const verifyToken = jwt.sign({ id: newUser._id }, "emailSecretKey", { expiresIn: "1d" });
- The user clicks the link → token is sent to backend → verified → we set:
user.isVerified = true;
await user.save();
This ensures only real users can log in.
🔓 3. User Login
User logs in by entering email & password.
Backend checks:
✅ Is the email present?
✅ Is the password correct?
✅ Is the user verified?
const isMatch = await bcrypt.compare(inputPassword, user.password);
If all checks pass, we generate a JWT token:
const token = jwt.sign({ id: user._id }, "mySecretKey", { expiresIn: "1h" });
This token will prove who the user is in the next requests.
🎫 4. What is JWT?
JWT = JSON Web Token. It's a small string like:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEyMyIsImlhdCI6MTY5...signature
It has 3 parts:
Header – Type & algorithm
Payload – User data (like ID)
Signature – Used to verify token wasn’t modified
It’s stateless, so we don’t need to store session in DB. Just verify token.
🍪 5. Storing JWT in Cookies
We don’t send the token in the frontend manually. We store it in a cookie:
res.cookie("authToken", token, {
httpOnly: true,
secure: true, // HTTPS only (for production)
maxAge: 3600000 // 1 hour
});
Cookies are sent automatically with every request. Easy!
🔐 6. Accessing Protected Data
Now when the user visits a dashboard or profile page, we:
Check the cookie.
Verify the JWT token.
If it's valid, give access.
Here's a sample middleware to protect any route:
const auth = (req, res, next) => {
const token = req.cookies.authToken;
if (!token) return res.status(401).send("Not authenticated");
try {
const decoded = jwt.verify(token, "mySecretKey");
req.user = decoded;
next();
} catch (err) {
res.status(403).send("Invalid or expired token");
}
};
Use it like:
app.get("/dashboard", auth, (req, res) => {
res.send("Welcome to your dashboard");
});
🧼 7. Logout
Just clear the cookie:
res.clearCookie("authToken").send("Logged out");
That’s it. You’re logged out.
✨ Done! You now understand how modern authentication works like a pro. Even your grandma can follow this.
Subscribe to my newsletter
Read articles from surya nag directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
