Using Bcrypt with Ruby
Tags: ruby, security, rails
Published: 2021-01-03 03:00:06

In this blog, I will cover how to create a 'bcrypt" module for use in a Ruby on Rails project.

Bcrypt uses the MD5 algorithm and adds in a salt to it in order to hash passwords. This is important because as developers we do not want passwords to be stored as regular old strings. Believe it or not, this used to be the case. However, this is no longer safe and NOT considered to be best practice.

The code below is a module. I have called this module "Crud". The methods in this module can be easily called on from other classes or files:

```ruby
module Crud
  require 'bcrypt'
  puts "Module CRUD activated"
 
  def self.create_hash_digest(password)
    BCrypt::Password.create(password)
  end
 
  def self.verify_hash_digest(password)
    BCrypt::Password.new(password)
  end
 
  def self.create_secure_users(list_of_users)
    list_of_users.each do |user_record|
      user_record[:password] = create_hash_digest(user_record[:password])
    end
    list_of_users
  end
 
  def self.authenticate_user(username, password, list_of_users)
    list_of_users.each do |user_record|
      if user_record[:username] == username && verify_hash_digest(user_record[:password]) == password
        return user_record
      end
    end
    "Credentials were not correct"
  end
end
```
Notice the "self" keyword on the methods creating class methods to be called on in another file. Class methods do not require an instance of an object to work. They can be called on the class itself, or a module in this case...

In the file I want to use the Crud module containing the bcrypt methods:
```ruby
require_relative 'crud'
 
users = [
          { username: "ryan", password: "password1" },
          { username: "jack", password: "password2" },
          { username: "maria", password: "password3" },
          { username: "michael", password: "password4" },
          { username: "phill", password: "password5" }
        ]
 
hashed_users = Crud.create_secure_users(users)
puts hashed_users
```
There are two things to notice here. First, take a look at `require_relative 'crud'`. This allows me to use the methods from the Crud module in this file. Second, notice the methods I wish to use from the Crud module must be appended with the `Crud` class.
```ruby
require_relative 'crud'
 
class Student
  include Crud
  attr_accessor :first_name, :last_name, :email, :username, :password
 
  def initialize(firstname, lastname, username, email, password)
    @first_name = firstname
    @last_name = lastname
    @username = username
    @email = email
    @password = password
  end
 
  def to_s
    "First name: #{@first_name}, Last name: #{@last_name}, Username: #{@username},
                  email address: #{@email}"
  end
 
end
 
ryan = Student.new("Ryan", "Parrish", "ryan1", "ryan@example.com",
                      "password1")
john = Student.new("John", "Doe", "john1", "john1@example.com",
                      "password2")
 
hashed_password = ryan.create_hash_digest(ryan.password)
 
puts hashed_password
```
If I include or "mixin" the module I want - `include Crud`, then the methods in the module needn't be class methods so the "self" keyword can be removed from the methods in the module and the methods can then be called on instances of objects in the class I want. 

Happy coding!