How to Prevent Accidental Password Leaks in Your Node.js APIs ๐ก๏ธ
Source: Dev.to
The Problem
When building an authentication system, we need to guarantee that a userโs hashed password never accidentally leaks to the frontend in an API response.
The traditional way is manually stripping the password before sending the response:
delete user.password;
โ ๏ธ The issue: Itโs easy to forget this step in a new endpoint (e.g., a newly created /profile route), resulting in a massive data leak.
Secure Schema Definition (Mongoose)
If you are using Mongoose (MongoDB), you can enforce hiding the password field at the schema level:
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: true
},
password: {
type: String,
required: true,
select: false // ๐ The secret sauce!
}
});
With select: false, any standard query like User.findById(id) will automatically omit the password hash, making your code Secure by Default.
Explicitly Requesting the Password for Validation
When you need the password (e.g., during login), explicitly request it in the query:
// 1. Explicitly request the password for validation
const user = await User.findOne({ email }).select('+password');
// 2. Now you can safely compare it
const isMatch = await bcrypt.compare(inputPassword, user.password);
Only the login function includes the password field, closing the door on accidental data leaks.
Conclusion
Using select: false in your Mongoose schema provides a simple, reliable way to prevent accidental password exposure. Have you adopted this pattern, or are you still manually stripping passwords from responses? Let us know in the comments! ๐