devise-argon2

Gem Version

A ruby gem that gives Devise models which use database_authenticatable the ability to hash passwords with Argon2id.

Installation

bundle add devise-argon2

Usage

Add devise :argon2 to your Devise model. For example:

class User < ApplicationRecord
  devise :database_authenticatable, :argon2
end

Now the password of a newly created user will be hashed with Argon2id. Existing BCrypt hashes will continue to work; if the password of a user is hashed with BCrypt, the Argon2id hash will replace the existing hash as soon as a user signs in (more specifically: as soon as valid_password? is called with a valid password).

Configuration

Argon2 options

For Argon2 hashing the gem ruby-argon2 is used, which provides FFI bindings to the Argon 2 reference implementation. ruby-argon2 can be configured by passing parameters like profile, t_cost, m_cost, p_cost, or secret to Argon2::Password.new. These parameters can be set like this:

class User < ApplicationRecord
  devise :database_authenticatable,
    :argon2,
    argon2_options: {  t_cost: 3, p_cost: 2 }
end

If the the configured work factors differ from the work factors of the hash in the database, the password will be re-hashed as soon as valid_password? is called with a valid password.

Pepper/secret key

The Argon 2 reference implementation has a built-in pepper which is called secret. This Argon2 secret key can be set like this:

class User < ApplicationRecord
  devise :database_authenticatable,
    :argon2,
    argon2_options: { secret: ENV['ARGON2_SECRET_KEY'] }
end

Traditionally, peppers in Devise are configured by setting config.pepper in devise.rb. This option in honored but argon2_options[:secret] takes precedence over config.pepper. Specifically:

  • config.pepper is used as secret key for new hashes if and only if argon2_options[:secret] is not set.
  • The verification of existing BCrypt hashes is not touched, so it continues to use config.pepper as pepper.

Updating from version 1

With version 2 come two major changes: First, devise-encryptable is no longer needed. Second, the mechanism for salting and peppering has changed: Salts are now managed by Argon2 and the pepper is passed as secret key parameter. If you have existing hashes in your database that have been generated by devise-argon2 v1, you'll need to set :migrate_from_devise_argon2_v1 in argon2_options.

With this option your existing hashes will continue to work as the old mechanism for salting and peppering is used if and only if password_salt is truthy. The first time you pass a valid password to valid_password?, the hash will be updated and password_salt will be set to nil. The next time you call valid_password? the new salting and peppering mechanism will be used because password_salt is not truthy anymore.

As soon as all password_salt fields are set to nil, you can delete the column from the database and remove :migrate_from_devise_argon2_v1 from argon2_options.

Please note that this works only if your database table has a field password_salt.

Upgrade Steps

  1. Update your Gemfile to use devise-argon2 version 2: gem 'devise-argon2', '~> 2.0'
  2. Remove devise-encryptable from your Gemfile
  3. Run bundle install
  4. Remove the line config.encryptor = :argon2 from config/initializers/devise.rb
  5. Change your Devise model by removing :encryptable and adding :argon2, argon2_options: { migrate_from_devise_argon2_v1: true }
    1. It should now look something like this
class User < ApplicationRecord
  devise :database_authenticatable,
    :argon2,
    argon2_options: { migrate_from_devise_argon2_v1: true }
end

That's it, you're done! Your users will now be able to log in with their existing passwords and their passwords will be migrated to the V2 format the next time they log in.


Once all of your users' passwords are migrated to the V2 format:

  1. Remove the argon2_options { migrated_from_devise_argon2_v1: true } line from your Devise model
  2. Delete the password_salt column from your database using a migration like this: class RemovePasswordSaltFromUsers < ActiveRecord::Migration[7.1] def change remove_column :users, :password_salt, :string end end

Note: If you do this before all of your users' passwords are migrated to the V2 format, they will be unable to log in with their current passwords.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

Contributors

Please see here for full list of contributors: https://github.com/erdostom/devise-argon2/graphs/contributors

License

Released under MIT License.