sequelize-bcrypt
v2.0.0
Published
Sequelize helper plugin to hash/compare fields
Maintainers
Readme
sequelize-bcrypt
Automatic bcrypt hashing and password comparison for Sequelize 6 models.
Requirements
- Node.js 24 or newer
- Sequelize 6
bcryptjs3
Installation
npm install sequelize-bcrypt bcryptjs sequelizesequelize is a peer dependency because the application must use the same Sequelize instance and version as the model. bcryptjs is installed as a runtime dependency.
Usage
import { DataTypes, Sequelize } from "sequelize";
import useBcrypt from "sequelize-bcrypt";
const sequelize = new Sequelize("sqlite::memory:");
const User = sequelize.define("User", {
email: { type: DataTypes.STRING, allowNull: false },
password: { type: DataTypes.STRING, allowNull: false },
});
useBcrypt(User);
const user = await User.create({
email: "[email protected]",
password: "correct horse battery staple",
});
user.authenticate("correct horse battery staple"); // true
user.authenticate("wrong password"); // falseCommonJS
const { DataTypes, Sequelize } = require("sequelize");
const { useBcrypt } = require("sequelize-bcrypt");
const sequelize = new Sequelize("sqlite::memory:");
const User = sequelize.define("User", {
password: { type: DataTypes.STRING, allowNull: false },
});
useBcrypt(User);Configuration
useBcrypt(User, {
field: "password",
rounds: 12,
compare: "authenticate",
});field: model attribute to hash. Defaults topassword.rounds: bcrypt cost factor from 4 to 31. Defaults to12.compare: instance method name. Defaults toauthenticate.
Multiple fields are supported. Calling useBcrypt repeatedly for the same model and field is idempotent; registering the same field with a different cost factor throws an error.
useBcrypt(User, {
field: "recoveryPassword",
compare: "authenticateRecoveryPassword",
rounds: 12,
});How It Works
useBcrypt validates the configured field and adds a Sequelize beforeSave hook. The hook:
- Runs for both new records and updates.
- Hashes only when the configured field has changed.
- Leaves
nullandundefinedvalues untouched. - Rejects non-string values before persistence.
- Stores the hash only after bcrypt completes successfully.
The comparison method reads the current field value and calls bcrypt.compareSync. It returns false when the record has no valid hash or the plain value is not a string.
The plugin does not validate password strength, enforce a required field, or choose a password policy. Use Sequelize validators or application-level validation for those concerns.
Error Handling
Invalid configuration throws synchronously:
TypeErrorfor a missing model, empty names, or an undefined model field.RangeErrorwhenroundsis not an integer between 4 and 31.Errorwhen a comparison method already exists or a field is registered with a different cost factor.
Hashing failures are reported as BcryptError. The original bcrypt error is available through its cause property.
import useBcrypt, { BcryptError } from "sequelize-bcrypt";
try {
useBcrypt(User, { rounds: 12 });
await User.create({ password: "secret" });
} catch (error) {
if (error instanceof BcryptError) {
console.error("Password hashing failed", error.cause);
}
}API
interface BcryptOptions {
field?: string;
rounds?: number;
compare?: string;
}
type BcryptCompareMethod = (plainValue: string) => boolean;
type BcryptModelStatic<T extends Model = Model> = ModelStatic<T> & {
prototype: T & Record<string, BcryptCompareMethod>;
};
class BcryptError extends Error {}
function useBcrypt(model: ModelStatic<Model>, options?: BcryptOptions): void;Migration Notes
Existing users can keep calling useBcrypt(Model, options) with the same options. The current implementation registers one idempotent beforeSave hook instead of separate create/save hooks, preventing double hashing during creation. It also compares against the current hash after a password update.
When upgrading, check that:
- the configured field exists on the model;
- the comparison method name is not already defined;
- password fields contain strings before saving;
- tests do not rely on comparing against a previous password hash.
Development
npm install
npm run check
npm run test:coverage
npm run buildThe package publishes ESM, CommonJS, source maps, and TypeScript declarations from dist/. prepublishOnly runs checks, coverage, and build.
License
MIT © Mattia Malonni
Automatic bcrypt hashing and password comparison for Sequelize 6 models.
Requirements
- Node.js 24 or newer
- Sequelize 6
bcryptjs3
Installation
npm install sequelize-bcrypt bcryptjs sequelizeUsage
import { DataTypes, Sequelize } from "sequelize";
import useBcrypt from "sequelize-bcrypt";
const sequelize = new Sequelize("sqlite::memory:");
const User = sequelize.define("User", {
email: { type: DataTypes.STRING, allowNull: false },
password: { type: DataTypes.STRING, allowNull: false },
});
useBcrypt(User);
const user = await User.create({
email: "[email protected]",
password: "correct horse battery staple",
});
user.authenticate("correct horse battery staple"); // true
user.authenticate("wrong password"); // falseuseBcrypt registers one beforeSave hook. A password is hashed only when its field changes, so creation and updates are both covered without double hashing. Comparisons always use the current field value.
Configuration
useBcrypt(User, {
field: "password",
rounds: 12,
compare: "authenticate",
});field: model attribute to hash. Defaults topassword.rounds: bcrypt cost factor from 4 to 31. Defaults to12.compare: instance method name. Defaults toauthenticate.
Multiple fields are supported. Calling useBcrypt repeatedly for the same model and field is idempotent; registering the same field with a different cost factor throws an error.
useBcrypt(User, {
field: "recoveryPassword",
compare: "authenticateRecoveryPassword",
rounds: 12,
});Nullish values are left untouched. Non-string values fail before persistence. Password strength and required-field validation should be enforced by the application or another Sequelize validation layer.
API
interface BcryptOptions {
field?: string;
rounds?: number;
compare?: string;
}
type BcryptCompareMethod = (plainValue: string) => boolean;
type BcryptModelStatic<T extends Model = Model> = ModelStatic<T> & {
prototype: T & Record<string, BcryptCompareMethod>;
};
class BcryptError extends Error {}
function useBcrypt(model: ModelStatic<Model>, options?: BcryptOptions): void;Hash failures are reported as BcryptError with the original error available as cause.
Development
npm install
npm run check
npm run test:coverage
npm run buildThe package publishes ESM, CommonJS, source maps, and TypeScript declarations from dist/. prepublishOnly runs checks, coverage, and build.
License
MIT © Mattia Malonni
