little-bobby-tables/rose_quartz

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# RoseQuartz

[![Build Status](https://travis-ci.org/little-bobby-tables/rose_quartz.svg?branch=master)](https://travis-ci.org/little-bobby-tables/rose_quartz)
[![Test Coverage](https://codeclimate.com/github/little-bobby-tables/rose_quartz/badges/coverage.svg)](https://codeclimate.com/github/little-bobby-tables/rose_quartz/coverage)
[![Gem Version](https://badge.fury.io/rb/rose_quartz.svg)](https://badge.fury.io/rb/rose_quartz)

A gem that adds two-factor authentication (time-based one-time passwords) to [Devise](https://github.com/plataformatec/devise) 
using the [rotp](https://github.com/mdp/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`.