Overview

Authy is a simple REST API that does all the heavy lifting, so you can add two-factor authentication to your website or app in just a few hours.
We have a number of resources, such as javascript helpers and API libraries for most languages. This guide will make use of this resources as we build a simple web app using the Authy API.

Full source code for this app can be found here

Resources

You will find everything you need in Github

Parts

There are 2 main parts to implement the Authy API

  1. Adding new users: involves creating a html form that takes the user's phone number and submits it to the Authy API.
  2. Verifying users: involves adding a field to the login form were the user enters the token and then submitting it to Authy.

Part 1: Adding new user

First we are going to create a page in our users control panel (well call it /enableauthy). In this page we'll create a simple form that takes the persons phone number and area code.

This form uses the Authy Javascripts ( found here ). The html id's authy-cellphone and authy-countries are special id's recognized by this javascript.


%label
  Cellphone
=text_field "cellphone", :placeholder => "Enter your cellphone", :id => "authy-cellphone"

%label
  Country
=text_field "country_code", :id => "authy-countries", :placeholder => "Enter your country"

%button.btn(type="submit")
  Submit

Javascript id tag helpers

The Javascripts use id's to help you build this register form easier. This are the id's used

  1. authy-cellphone - If set on the text-field were the user inputs his cellphone it will automatically run phone validations on the client-side.
  2. authy-countries - If set on the text-field were the user inputs his area code will produce an auto-complete drop down with a list of countries with area-codes. This makes it really easy for the user to enter his area-code.

At this point you can send the users email, phone number and country code to Authy.


def register_authy
  @authy_user = Authy::API.register_user(:email => current_user.email,
                                         :cellphone => params[:user][:cellphone],
                                         :country_code => params[:user][:country_code])

  if @authy_user.ok?
    current_user.authy_id = @authy_user.id
    current_user.save
  else
    @errors = @authy_user.errors
    render 'enable_authy'
  end
end

If everything goes well:

Authy will return you the Authy ID of the users. This is an integer > 0. You need to store this id your users database.

If not a hash with errors in plain English is sent back. You should display this errors in the form so that the user can correct the inputs.


Part 2: Verifying users

After the user has register to Authy in your website you get back an Authy ID. Next time user wants to log-in you can use the Authy ID to verify the two-factor token.

There are many ways of doing this which depends on your application and the user experience you wish to create.
In this example we plan to support users that have two-factor authentication on, and some which don't. The easiest way is to do this is separating the authentication in 2 screens.

  1. The first screen is your usual login form were the user inputs his username and password.
  2. The second screen is were the user inputs his Authy Token if Authy is enabled in his account.

You can quickly check if a user has Authy enabled by checking your database. Assuming you called the Authy ID record in your database authy_id, you can check if authy_id field for the user is > 0. If so you can assume Authy is enabled.

Here's the function that validates username and password and redirects to the two-factor auth if authy is enabled:


 def create
  @user = User.find_by_email(params[:user][:email])

  if @user && @user.authenticate(params[:user][:password])
    #username and password is correct
    if(@user.authy_id != 0) #user is using two-factor
      Authy::API.request_sms(:id => @user.authy_id) #request the API to send and sms.

      #Rails sessions are tamper proof. We can store the ID and that the password was already validated
      session[:password_validated] = true 
      session[:id] = @user.id
      redirect_to url_for(:controller => "sessions", :action => "two_factor_auth")
    else
      sign_in(@user)
      flash[:notice] = "Successfully authenticated without two-factor"
      redirect_to @user
    end
  else
    flash[:error] = "Wrong username, password."
    @user = User.new
    render 'new'
  end
end

Basically, when the user wants to log-in, you use his e-mail to locate the record in the database. Then you try to authenticate him.
The authenticate function will check his username and password and also if the user has Authy enabled.
If so you will redirect the user to the second page were he can enter his Token and complete his authentication.

Here's the function that does the second factor authentication:

def create_two_factor_auth
  @user = User.find(session[:id])
  token = params[:token]
  if @user && session[:password_validated] && @user.verify_token(token) 
    sign_in(@user)
    @user.authy_used = true
    @user.save(:validate => false)
    session[:password_validated] = nil
    session[:id] = nil
    flash[:success] = "Securely signed in using Authy"
    redirect_to @user
  else
    flash[:error] = "Wrong token"
    redirect_to new_session_path
  end
end

Token verification involves sending the token and the id. Authy will respond HTTP status 200 if the token is correct.

def verify_token(token)
  token = Authy::API.verify(:id => self.id, :token => token)

  token.ok?
end

The function simply passes the authy_id and the token the user entered. Then it check if the response is HTTP status 200, if so it returns true.

To prevent users account getting locked down, Authy won't check the tokens until we are certain the user has completed the registration process. If you want to verify token's anyway, you can pass ?force=true to verify.