I ran into an interesting behavior in TypeORM while updating a userβs password in NestJS.
Here are the two scenarios:
Scenario 1 β Password Not Hashed β
@BeforeInsert()
@BeforeUpdate()
hashPassword(): void {
if (this.password) {
this.password = bcrypt.hashSync(this.password, saltRounds);
}
}
async changeRootUserPassword(id: string, newPassword: string): Promise {
const user = await RootUser.findOne({ where: { id } });
if (!user) return false;
user.password = newPassword;
const savedUser = await user.save();
return !!savedUser?.id;
}
Result: The password is saved in plain text!
Why? Because TypeORM does not detect a field change, so @BeforeUpdate() never triggers.
Scenario 2 β Password Hashed β
@BeforeInsert()
@BeforeUpdate()
hashPassword(): void {
if (this.password) {
this.password = bcrypt.hashSync(this.password, saltRounds);
}
}
async changeRootUserPassword(id: string, newPassword: string): Promise {
const user = await RootUser.findOne({ where: { id } });
if (!user) return false;
user.password = newPassword;
user.updatedAt = new Date();
const savedUser = await user.save();
return !!savedUser?.id;
}
Result: Password is properly hashed β
By updating another field (updatedAt), TypeORM detects a change and triggers the @BeforeUpdate() hook.
π‘ Key Takeaway:
When relying on TypeORM entity hooks like @BeforeUpdate(), ensure at least one other field changes β otherwise, your hook may not run, and important logic (like password hashing) can fail silently.
Top comments (1)
Good discovery, thanks!