Back to Blog

2FA in Rails 4 with Devise, Authy and Puppies

 

Passwords aren’t enough anymore. Keeping user data safe is hard enough without users themselves choosing the worst passwords in the world. Yes, “123456” has topped the list of most commonly used password of the year…again.

Two-factor authentication keeps your users’ accounts secure by requiring a second factor of authentication, something a user has (their phone) as well as something they know (their password). Two-factor authentication can be hard to implement and even harder to secure properly. Authy is a Twilio service that provides two-factor authentication as an API, making it easy to secure our users’ accounts.

Your password needs to contain a capital letter, a number, an emoji, a plot, a protagonist with some character development, and a twist end.

— Jake Lawrence (@TheTimeCowboy) January 5, 2013

In this post I want to show you how to implement two-factor authentication using Authy in your Rails 4 apps using Devise. We already have a tutorial that walks you through adding two-factor authentication to a Rails application, but as Devise is the most popular authentication framework for Rails I thought it would be unwise to leave it out. In this post, we’ll take a basic Rails application, add user accounts with Devise and make them extra secure by enabling two-factor authentication.

The tools

To put this application together we’re going to need a couple of things:

  • a Twilio account (sign up for free here)
  • Ruby installed (I’m using the current latest, 2.3.0, but any version that runs Rails will work)
  • Bundler, so we can install our dependencies.

And that’s it. Let’s get going.

Something to protect

So that we don’t have to build a whole Rails application up from scratch I have created a starter application for us. It’s called Super Secret Puppies and is a simple app that allows users to log in and look at pictures of puppies. All we need to do is build that login functionality.

Let’s get the app up and running. You can clone the repository, install the dependencies and start the app with the following commands:

$ git clone https://github.com/philnash/super-secret-puppies.git
$ cd super-secret-puppies
$ bundle install
$ bundle exec rails server

Navigate to http://localhost:3000 and you’ll see the home page.

A screenshot of the Super Secret Puppies home page

You’ll find you can click on the call to action to see the puppies and you’ll be directed to a page of puppy pictures. I’ll give you a minute while you enjoy that.

Ok, it’s just one puppy, my one, but she’s called Ruby so I’m pretty happy that this is on topic for today.

For the rest of this post we’re going to implement user accounts with two-factor authentication to restrict access to this page to our registered users.

Implementing user accounts with Devise

We’ll start by adding Devise to our Gemfile. Add the following line after all the regular gems (that is, not inside any of the groups).

# Gemfile
gem 'devise'

Bundle the new gem into the project.

$ bundle install

Run the Devise generators and migrate the database.

$ bundle exec rails g devise:install
$ bundle exec rails g devise User
$ bundle exec rake db:migrate

This installs Devise and then creates a User model that we will use to sign up to our application with.

Let’s protect our puppies controller from non-logged in users. Open up app/controllers/puppies_controller.rb and add the following before_action at the top of the file:

# app/controllers/puppies_controller.rb
class PuppiesController < ApplicationController
  before_action :authenticate_user!

  def index
  end
end

This is a Devise helper that ensures there is a logged in user in the session. If there is no logged in user then the response will be a redirect to the login page.

I like to make one other change to the default Devise setup. That is to allow logging out by GET request. Open up config/initializers/devise.rb and change the line

# config/initializers/devise.rb
  config.sign_out_via = :delete

to

# config/initializers/devise.rb
  config.sign_out_via = :get

Restart the application and load up the home page again. You’ll find links to sign up and log in at the top right (I snuck those into the base app to save us writing HTML). Try navigating to the page of puppies. You’re now redirected to the login page. Hit the link to sign up, enter your email and a password, submit the form and you’re signed up and looking at a page of puppy pictures. Lovely, but we can make it more secure. Let’s get Authy involved and add two-factor authentication to this experience.

Adding two-factor authentication to Devise with Authy

The first thing we need to do is install the Devise-Authy gem that will handle most of the integration. Add another line to your Gemfile, below the Devise gem we added earlier.

# Gemfile 
gem 'devise'
gem 'devise-authy'

Bundle the new dependency.

$ bundle install

Create an initializer for Authy in config/initializers.

$ touch config/initializers/authy.rb

Add the following code to the initializer.

# config/initializers/authy.rb
Authy.api_key = ENV["AUTHY_API_KEY"]
Authy.api_uri = "https://api.authy.com/"

You’ll notice we need an API key for Authy. You can get this from your Twilio account portal. Click the link to access the Authy dashboard.

If you don’t already have an Authy account, this will set one up for you. You will need to verify your email address and set up two-factor authentication. Then you can create an application with Authy and this will give you your API key.

Click 'Access Authy Dashboard' go through the sign up procedure for Authy by enabling two factor authentication and then create a new application. Name the application whatever you like and skip the next two screens, then you will find your API Key.

If you already have an Authy account, click “New application” at the bottom of your dashboard menu and you will go through the same process.

Now you have your API key, copy config/env.yml.example to config/env.yml and fill in the key.

# config/env.yml
development:
  AUTHY_API_KEY: 'YOUR_AUTHY_API_KEY_HERE'

We’re using a gem called envyable to set the API key in your application’s environment. It’s all set up for you, but if you’re interested in this setup more, I wrote about environments and envyable last year.

Now we’re ready to run our Devise Authy install script. On the command line enter:

$ rails g devise_authy:install
$ rails g devise_authy User
$ rake db:migrate

This installs the Devise Authy plugin and updates the User model to use two factor authentication if it is enabled for the account. Let’s enable this for our user that we created earlier now.

Restart your server and visit this page: http://localhost:3000/users/enable_authy. Fill in your country and your mobile phone number and you will get an SMS with a 7 digit token. Or, if you are already a user of the Authy app, you will receive a push notification adding the Super Secret Puppies app to your account and showing you the token (though you can force the token to arrive by SMS if you need). Submit the token to the form in the puppies app and two-factor authentication will be enabled on your account.

You can test this by logging out with the link in the top right of the page and then logging in again. You will be asked once more for a token which you should receive by SMS or application and once you enter the token you will be logged in.

This is an animation showing the process of enabling two factor authentication and then signing out and back in again and going through the two factor authentication process.

Two-Factor Authentication in just a few lines of code

Since we were using Devise, adding two-factor authentication using Authy was pretty straightforward. All we had to do was add an initializer for Authy, enter our API key, run an install command and migrate the database.

If you didn’t follow along with the code, but you want to see the finished application, you can check out the complete branch in the GitHub repository.

If you want to customize your application a bit more there are a few options. You can edit the views, set up custom redirects and add internationalized messages throughout the flow. If you’re not using Devise, or are interested in how it works, check out the tutorial on securing your user accounts using just Authy and Rails.

If you’ve got any questions about two-factor authentication or using Authy, please reach out to me on Twitter at @philnash.

**Okay, okay, no-one needs to keep pictures of puppies safe. Everyone wants to show off pictures of puppies, why else do you think I’d use them as an example in a blog post? Hope you enjoyed them!

This post originally appeared on the Twilio blog

We can text you a link to get started:

Close