0.0
No commit activity in last 3 years
No release in over 3 years
An extremely narrow in scope, convention-over-configuration TOTP integration for Rails
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies
 Project Readme

RoseQuartz

Build Status Test Coverage Gem Version

A gem that adds two-factor authentication (time-based one-time passwords) to Devise using the rotp library.

It attempts to stay lightweight by making a lot of assumptions — for example, that you have a single authenticatable resource, User, and that you're using ActiveRecord.

Highlights:

  • Adds optional TOTP (compatible with Google Authenticator) to the sign-in process.
  • Provides a backup code as a fallback option; resets it once it has been used and notifies the user.
  • Does not tamper with the User model — no additional fields, no included modules.
  • Employs a separate table that can be updated in future without affecting your codebase and data.
  • Built with Rails 5 and Devise 4 in mind.

What it does not do:

Use a multiple-page login system (email and password first, two-factor authentication token next). This introduces lots of needless complexity, which goes against the purpose of the gem.

What it should do, but does not (yet):

  • Encrypt the backup code and the secret used to generate OTP.

Getting Started

First, add RoseQuartz to your Gemfile:

gem 'rose_quartz'

And run:

bundle install

Next, you need to copy initializers, locales, and add a migration:

rails g rose_quartz:install

Finally, run the migration:

rails db:migrate

Adding views

Signing in

You need a special field for one-time password/backup code on the sign-in page (app/views/devise/sessions/new.html.erb).

Here's an example:

<%# E-mail and password fields %>

<div class="field">
  <%= label_tag :otp, 'Two-factor authentication token' %>
  <%= text_field_tag :otp, '', autocomplete: "off" %>
</div>

<%# The rest of the form %>

Note that you must leave the parameter name (otp) intact.

Enabling/disabling two-factor authentication

The gem adds a special extension to Devise that allows you to include two-factor authentication setup in the account editing page (app/views/devise/registrations/edit.html.erb).

As with other settings there, a password is required to toggle two-factor authentication. The user also needs to provide a correct token generated by their TOTP application of choice, which ensures that their device clock is in sync with the server.

Here's a sample implementation:

<div class="field">
  <%= fields_for :two_factor_authentication do |tfa| %>
    <% if two_factor_authentication_enabled? %>
      <%= tfa.label :disable, 'Disable two-factor authentication' %>
      <%= tfa.check_box :disable %>
      <p>
        Your backup code is <strong><%= two_factor_authentication_backup_code %></strong> -
        save it to access your account if you ever lose your device or don't have it with you.
      </p>
      <%= tfa.label :reset_backup_code %>
      <%= tfa.check_box :reset_backup_code %>
    <% else %>
      <%= tfa.hidden_field :secret, value: two_factor_authentication_secret %>
      <%= image_tag two_factor_authentication_qr_code_uri(size: 200) %>
      <p>
        Scan this QR code with your device and enter the token below:
      </p>
      <%= tfa.label :token, 'Token' %><br />
      <%= tfa.text_field :token, value: '' %>
      <p>
        Tip: to configure authentication on multiple devices, scan the code using each device.
      </p>
    <% end %>
  <% end %>
</div>

The following helper methods are available in the view: two_factor_authentication_enabled?, two_factor_authentication_backup_code, two_factor_authentication_qr_code_uri, two_factor_authentication_secret.