Devise Modules

What are Devise Modules

In my previous blog post I wrote a basic introduction to Devise. Go check that out if you’re not already familiar with installing Devise. In this post I will be diving deeper and exploring the 10 modules that make up Devise.

Lets get started.

How to enable/disable Devise Modules

After you install and generate Devise, your user model will look something like this:

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

The devise method allows you to include any of the Devise modules. Inversely, if you want to remove a module then you just need to remove it (or comment it out).

Applying options

Devise exposes a number of configuration options to allow application developers to customise Devise. When you install Devise it will create a file called  config/initializers/devise.rb where you can add configuration options:

Devise.setup do |config|
  config.remember_for = 52.weeks
  config.password_length = 8..24
end

Throughout this post I will talk about the configuration options that different Devise modules provide. All of these options can be applied in the same fashion as the example above.

Registerable

This module is completely hidden from the application developer. The Devise team haven’t documented it, other than to tell you what it is responsible for:

Registerable is responsible for everything related to registering a new resource (ie user sign up).

Validatable

This module is responsible for providing the email and password validations. This module is optional, many Devise users choose to write their own email/password validations. If you take a look at the source code for Validatable you can see which validations it will apply.

This module has proved tricky for me in the past while I working on a task to modify user email/password validations. It can take a while to remember that these validations are coming from Devise.

If you are using Validatable, there are two methods that you should be aware of: password_required? and email_required?. You can override these methods if you want to modify when validations are applied. For example, if you want email to only be required for users in specific countries.

Lastly, Validatable exposes two options which give you the opportunity to customise the validations.

  • email_regexp: allows you to modify the regex that is used to validate emails
  • password_length: allows you to modify the length of the password validation

DatabaseAuthenticatable

This module is responsible for Hashing the users password and validating the password when the user signs in. By default Devise uses bcrypt but you can override this with a different algorithm.

Alternatively, you can also increase the security of bcrypt without changing the underlying algorithm. Devise provides two configuration options:

Rememberable

screen-shot-2016-10-26-at-19-19-26This module is responsible for what happens when a user clicks ‘Remember me’. When you enable this module the user will see a ‘Remember me’ checkbox (as shown in the image). When the user checks this box and logs in, an additional cookie is set called remember_user_token with an expiry time (by default 2 weeks from now).

Normally, when a user closes their session and looses their session cookie, they are forced to login to the application again. However, when they have a remember_user_token Devise will use that cookie to create a new session for them. The user will get a new session cookie and will not be forced to login again.

Devise keeps the internals of this module well hidden. It is mainly used by Devise internally and does not have many public methods exposed. The only thing that you might want to change is the length of time that the user is remembered for. This can be configured with the a configuration option, remember_for.

Timeoutable

A simple module to understand, Timeoutable is responsible for figuring out whether the users session has expired or not and if so timing out the user.

Timeoutable has one configuration option timeout_in which allows you to configure how long users sessions will last (without activity from the user).

Trackable

This module uses a number of fields to track user sign in activity:

  • sign_in_count: Increases every time a sign in is made
  • current_sign_in_at: A timestamp updated when the user signs in
  • last_sign_in_at: Holds timestamp of the previous sign in
  • current_sign_in_ip: remote IP of the signed in user
  • last_sign_in_ip: remote IP of user from previous sign in.

Trackable doesn’t have any configuration options. The module’s design is simple, switch it on and you get user tracking.

Personally I haven’t found this module very useful. Typically when a project calls for tracking, the business wants more than just sign in count. However, if you just want some basic user login tracking then Trackable may be a good fit.

Recoverable

This module is responsible for resetting the users password and sending out reset instructions. Recoverable relies on two DB fields: reset_password_token and reset_password_sent_at.

reset_password_token allows Devise to safely find the user who is resetting their password.

reset_password_send_at tracks when the reset password request is sent. This is required because users only have a limited time in which they can reset their password before the token becomes invalid. You can use the reset_password_within option to configure the length of time within which the users password must be reset.

Recoverable exposes two methods that are useful to application developers:

  • reset_password(new_password, new_password_confirmation): Allows you to reset the users password
  • send_reset_password_instructions: Generates a new reset password token and sends out an email with password reset instruction.

reset_password: is worth taking note of. In the past I’ve had to use this method to reset users passwords outside of the normal Devise flow.

Lockable

This module handles blocking a user after a certain number of invalid attempts. Lockable has a number of useful configuration options:

  • maximum_attempts: The number of failed attempts the user is allowed before they are blocked
  • lock_strategy: Choose which strategy to use for account locking, either:
    • :failed_attempts: Turn on Devise account locking. Accounts will be locked when the user exceeds the specified number of attempts
    • :none: Devise will not handle locking. This allows to application developer to handle locking on their own.
  • unlock_strategy: Choose which strategy to use for unlocking a user, either:
    • :email: Sends an email to the user with an unlock link
    • :time: Re-enable the user after a certain period of time
    • :both: Both of the above strategies
    • :none: None of the above strategies
  • unlock_in: The time after which you will unlock a user.

For Lockable to work you will need to have the following lines in your Devise migration:

## Lockable
t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
t.string   :unlock_token # Only if unlock strategy is :email or :both
t.datetime :locked_at

Lockable works by incrementing the number of failed_attempts so that it can keep track of how many times the user has failed to sign in. Once an account has exceeded the allowed number of failed signups Devise sets locked_at to record that the account is locked.

Confirmable

This module is responsible for checking whether the user has been confirmed and is allowed to sign in. Confirmable is also responsible for sending out confirmation instructions.

Internally, Confirmable tracks this using the following fields:

## Confirmable
t.string   :confirmation_token
t.datetime :confirmed_at
t.datetime :confirmation_sent_at
t.string   :unconfirmed_email # Only if using reconfirmable

Confirmable has the following configuration options:

  • confirm_within: Time that conformation token is valid for
  • reconfirmable: Requires email changes to be re-confirmed
  • allow_unconfirmed_access_for: Allow the user to access their account before confirming it, for a specified amount of time. After which, the account will be blocked

Omniauthable

This module allows you to add Omniauth to Devise. For example, you could allow users to login using their Facebook or Twitter account.

The Devise team have written a fairly comprehensive guide to setting up Omniauth and adding new providers.

Other Modules

These are just the modules that are included with Devise out of the box. There are lots of other gems out there that add extra modules to Devise.

For example, the authy-devise gem allows you to use two-factor auth with Devise. The gem provides a new module called authy_authenticatable.

Thats all

I hope you found this post useful. Researching this has helped me to understand what all of the different modules in Devise do. I hope I’ve passed some of that learning on to you.

You can checkout the source code for this blog post on Github. You can also watch the screencast about this topic.