How to use BCrypt with Sequelize models

Updated: December 29, 2023 By: Guest Contributor Post a comment

Introduction

Securing user data is a fundamental aspect of web development, particularly when it comes to storing passwords. A common approach is to hash passwords before they are saved to a database, and BCrypt is one of the most reliable algorithms for hashing passwords. In this tutorial, we’ll integrate the BCrypt hashing algorithm with Sequelize, an ORM for Node.js, to provide enhanced security for user passwords in a Node.js application. We will start with the basics of setting up Sequelize models and then move on to how to integrate BCrypt for password hashing.

Setting Up Sequelize Models

Sequelize is a promise-based ORM for Node.js. To start, you need to install Sequelize and its dependencies:

npm install sequelize
npm install --save pg pg-hstore # If using PostgreSQL

Next, configure Sequelize to connect to your database:

const Sequelize = require('sequelize');

const sequelize = new Sequelize('database', 'username', 'password', {
  host: 'localhost',
  dialect: 'postgres',
});

With the connection set up, define a User model that will include a password field:

const User = sequelize.define('user', {
  username: {
    type: Sequelize.STRING,
    unique: true,
  },
  password: {
    type: Sequelize.STRING,
    allowNull: false,
  },
});

Integrating BCrypt for Password Hashing

For hashing passwords, we’ll be using the ‘bcrypt’ library. Install it using the following command:

npm install bcrypt

Now, you can hook into Sequelize’s model lifecycle events to hash the password before a User is created or updated:

const bcrypt = require('bcrypt');
const saltRounds = 10;

User.beforeCreate((user, options) => {
  return bcrypt.hash(user.password, saltRounds)
    .then(hash => {
      user.password = hash;
    })
    .catch(err => {
      throw new Error(err);
    });
});

User.beforeUpdate((user, options) => {
  if (user.changed('password')) {
    return bcrypt.hash(user.password, saltRounds)
      .then(hash => {
        user.password = hash;
      })
      .catch(err => {
        throw new Error(err);
      });
  }
});

Advanced: Handling Authentication

With the hashing integrated, the next step is to handle authentication by comparing a login attempt’s password with the hashed password stored in the database. Below is a method that can be added to the User model to perform this verification:

User.prototype.isValidPassword = function(password) {
  return bcrypt.compare(password, this.password)
    .then(result => result)
    .catch(err => throw new Error(err));
};

To authenticate a user, you’d call this method with the submitted password:

User.findOne({ where: { username: 'someuser' } })
  .then(user => {
    if (!user) {
      // Handle user not found
    }
    return user.isValidPassword('submitted_password');
  })
  .then(isValid => {
    if (!isValid) {
      // Handle password not matching
    }
    // User is authenticated
  })
  .catch(err => {
    // Handle error
  });

Conclusion

In this tutorial, we walked through the process of integrating BCrypt with Sequelize models for secure password hashing. We started with setting up Sequelize and moved through hashing passwords on user creation and updates. We also covered authentication by validating passwords against the hashed ones in the database. By following these steps, you’ll ensure that your application is using industry-standard practices for password security, keeping your users’ information safe. Remember, security is an ongoing process, and it’s important to keep abreast of best practices and potential vulnerabilities.