SAFELY STORING PASSWORDS IN MONGODB USING BCRYPT AND A MONGOOSE MIDDLEWARE
Introduction
Hey there. Maybe you landed here mistakenly, or you're genuinely interested in figuring out how to safely hash user passwords and store them in your database — either way, you're in the right place!
I’ll keep this as concise as possible, because, let’s face it, these things can get out of hand real quick.
Aim
The goal here is to use document middleware from Mongoose to perform a hashing operation on the password
field before saving it in MongoDB.
Mongoose provides 4 types of middleware, and here we’ll use the document middleware — specifically, the save
hook.
⚠️ I’m assuming you already have a basic MongoDB/Mongoose and Express setup running.
If not, you can follow these guides:
1. Installing Bcrypt
Install bcryptjs
via npm:
npm install bcryptjs
Then require it in your schema file:
const bcrypt = require('bcryptjs')
2. Defining the Mongoose Schema with Middleware
Here’s how your Mongoose schema should look with the middleware:
const mongoose = require('mongoose')
const bcrypt = require('bcryptjs')
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
})
// Document middleware: runs before .save() and hashes the password
UserSchema.pre('save', async function (next) {
if (!this.isModified('password')) return next()
try {
const salt = await bcrypt.genSalt(10)
this.password = await bcrypt.hash(this.password, salt)
next()
} catch (err) {
return next(err)
}
})
const User = mongoose.model('User', UserSchema)
module.exports = User
3. Registration Route Example
Here’s how your Express registration route might look:
const express = require('express')
const router = express.Router()
const User = require('../models/User')
router.post('/register', async (req, res) => {
const { username, email, password } = req.body
try {
const newUser = new User({ username, email, password })
await newUser.save()
res.status(201).json({ message: 'User registered successfully' })
} catch (err) {
res.status(500).json({ error: 'Registration failed' })
}
})
module.exports = router
Logic
Here’s what’s going on behind the scenes:
- When the schema is called through its model (e.g., when a user registers), the
save
middleware intercepts the request. - It checks whether the
password
field exists or has been modified. - If so, it hashes the password using Bcrypt before saving it to MongoDB.
- This also applies during password updates.
The middleware acts as a middleman between the request and the database operation.
Further Reading
If you're curious about the internals of either Bcrypt or Mongoose middleware:
That’s it! 🎉 Now you’re securely hashing and storing user passwords like a pro.
Stay safe. Hash smart. 💻🔐