Account Verification with Authy, Ruby and Rails

Ready to implement user account verification in your application? Here's how it works at a high level:

  1. The user begins the registration process by entering their data, including a phone number, into a signup form.
  2. The authentication system sends a one-time password to the user's mobile phone to verify their possession of that phone number.
  3. The user enters the one-time password into a form before completing registeration.
  4. The user sees a success page and receives an SMS indicating that their account has been created.

Building Blocks

To get this done, you'll be working with the following Twilio-powered APIs:

Authy REST API

  • Users Resource: You will need to create Authy users to send and verify one-time passwords with them.
  • SMS Resource: We will ask Authy to send one-time passwords to our user via SMS.
  • Verify Resource: Used to verify tokens entered by the user in our web form during registration.

Twilio REST API

  • Messages Resource: We will use Twilio directly to send our user a confirmation message after they create an account.

Let's get started!

About This Tutorial

In this tutorial, we will be working through a series of user stories that describe how to fully implement account verification in a web application. Our team implemented this example application in about 12 story points (roughly equivalent to 12 working hours).

Let's get started with our first user story around creating a new user account.

The User Story

As a user, I want to register for a new user account with my e-mail, full name, mobile phone number, and a password.

To do account verification, you need to start with an account. This requires that we create a bit of UI and a model object to create and save a new User in our system. At a high level, here's what we will need to add:

  • A form to enter details about the new user
  • A route and controller function on the server to render the form
  • A route and controller function on the server to handle the form POST request
  • A persistent User model object to store information about the user

Let's start by looking at the model, where we decide what information we want to store about our user.

The User Model

The User Model for this use-case is pretty straight-forward and Rails offers us some tools to make it even simpler. If you have already read through the 2FA tutorial this probably looks very similar. Let's start by defining our model and validating it.

First we need to create the ActiveRecord object, which creates the model in the related Postgres table and tells our app how to validate the model's data.

Data Validation

Validations are important since we want to make sure only accurate data is being saved into our datbase. In this case we only want to validate that all of our required fields are present. We can do this by creating a validates statement with presence: true.

Passwords

In Rails creating a secure password hash is as simple as calling has_secure_password. This created a hash that protects our user's passwords on the database.

One note: in order to run this demo you would need to run rake db:migrate which would run the migrations in our db/migrate folder. For this tutorial we're going to focus on the verification steps, but if you want to learn more about migrations you can read the Rails guide on the subject.

Loading Code Samples...
Language
class User < ActiveRecord::Base
  has_secure_password

  validates :email,  presence: true, format: { with: /\A.+@.+$\Z/ }, uniqueness: true
  validates :name, presence: true
  validates :country_code, presence: true
  validates :phone_number, presence: true
end
app/models/user.rb
Create a user model and its associated properties

app/models/user.rb

Now we're ready to move up to the controller level of the application, starting with the HTTP request routes we'll need.

Adding New Routes

In a Rails application, there is something called Resource Routing which automatically maps a resource's CRUD capabilities to its controller. Since our User is an ActiveRecord resource, we can tell Rails that we want to use some of these routes, which will save us some lines of code.

This means that in this one line of code we automatically have a 'user/new' route which will render our 'user/new.html.erb' file.

Loading Code Samples...
Language
Rails.application.routes.draw do

  get "users/verify", to: 'users#show_verify', as: 'verify'
  post "users/verify"
  post "users/resend"

  # Create users
  resources :users, only: [:new, :create, :show]

  # Home page
  root 'main#index'

end
config/routes.rb
Create application routes

config/routes.rb

 Let's take a look at the new user form up close.

New User Form

When we create a new user, we ask for a name, e-mail address, and a password. In order to validate their account with Authy, we also ask them for a mobile number with a country code, which we can use to send them one-time passwords via SMS.

By using the rails form_for tag we can bind the form to the model object. This will generate the necessary html markup that will create a new User on submit.

Loading Code Samples...
Language
SDK Version:
  • html
<h1>We're going to be *BEST* friends</h1>
<p> Thanks for your interest in signing up! Can you tell us a bit about yourself?</p>

<% if @user.errors.any? %>
  <h2>Oops, something went wrong!</h2>

  <ul>
    <% @user.errors.full_messages.each do |error| %>
      <li><%= error %></li>
    <% end -%>
  </ul>
<% end -%>

<%= form_for @user do |f| %>
  <div class="form-group">
    <%= f.label :name, "Tell us your name:" %>
    <%= f.text_field :name, class: "form-control", placeholder: "Zingelbert Bembledack" %>
  </div>
  <div class="form-group">
    <%= f.label :email, "Enter Your E-mail Address:" %>
    <%= f.email_field :email, class: "form-control", placeholder: "me@mydomain.com" %>
  </div>
  <div class="form-group">
    <%= f.label :password, "Enter a password:" %>
    <%= f.password_field :password, class: "form-control" %>
  </div>
  <div class="form-group">
    <%= f.label :country_code %>
    <%= f.text_field :country_code, class: "form-control", id: "authy-countries" %>
  </div>
  <div class="form-group">
    <%= f.label :phone_number %>
    <%= f.text_field :phone_number, class: "form-control", id: "authy-cellphone" %>
  </div>
  <button class="btn btn-primary">Sign up</button>
<% end -%>
app/views/users/new.html.erb
New User Form

app/views/users/new.html.erb

Let's jump back over to the controller to see what happens when we create a user.

Handling the Form POST

One of the other handy controllers created by our User resource route is 'user/create' which handles the POST from our form.

In our controller we take the input from our form and create a new User model. If the user is saved to the database successfully, we use the Authy gem to create a corresponding Authy User and save the ID for that user in our database.

Loading Code Samples...
Language
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def show
    @user = current_user
  end

  def create
    @user = User.new(user_params)
    if @user.save
      # Save the user_id to the session object
      session[:user_id] = @user.id

      # Create user on Authy, will return an id on the object
      authy = Authy::API.register_user(
        email: @user.email,
        cellphone: @user.phone_number,
        country_code: @user.country_code
      )
      @user.update(authy_id: authy.id)

      # Send an SMS to your user
      Authy::API.request_sms(id: @user.authy_id)

      redirect_to verify_path
    else
      render :new
    end
  end

  def show_verify
    return redirect_to new_user_path unless session[:user_id]
  end

  def verify
    @user = current_user

    # Use Authy to send the verification token
    token = Authy::API.verify(id: @user.authy_id, token: params[:token])

    if token.ok?
      # Mark the user as verified for get /user/:id
      @user.update(verified: true)

      # Send an SMS to the user 'success'
      send_message("You did it! Signup complete :)")

      # Show the user profile
      redirect_to user_path(@user.id)
    else
      flash.now[:danger] = "Incorrect code, please try again"
      render :show_verify
    end
  end

  def resend
    @user = current_user
    Authy::API.request_sms(id: @user.authy_id)
    flash[:notice] = 'Verification code re-sent'
    redirect_to verify_path
  end

  private

  def send_message(message)
    @user = current_user
    twilio_number = ENV['TWILIO_NUMBER']
    account_sid = ENV['TWILIO_ACCOUNT_SID']
    @client = Twilio::REST::Client.new account_sid, ENV['TWILIO_AUTH_TOKEN']
    message = @client.api.accounts(account_sid).messages.create(
      :from => twilio_number,
      :to => @user.country_code+@user.phone_number,
      :body => message
    )
  end

  def user_params
    params.require(:user).permit(
      :email, :password, :name, :country_code, :phone_number
    )
  end
end
app/controllers/users_controller.rb
Create a new user and register user with Authy

app/controllers/users_controller.rb

Now we have a user that has registered, but is not yet verified. In order to view anything else on the site they need to verify that they own the phone number they submitted by entering a token we send to that phone. Time to take a look at how we would send this token.

User Story: Sending a One-Time Password

As an authentication system, I want to send a one-time password to a user's mobile phone to verify their possession of that phone number.

This story covers a process that is invisible to the end user but necessary to power our account verification functionality. After a new user is created, the application needs to send a one-time password to that user's phone to validate the number (and the account). Here's what needs to get done:

  • Create and configure an Authy API client.
  • Modify the controller to send a one-time password after the user is created.

Let's begin by modifying the app's configuration to contain our Authy API key.

Configuring Authy

In secrets.yml, we list configuration parameters for the application. Most are pulled in from system environment variables, which is a helpful way to access sensitive values (like API keys). This prevents us from accidentally checking them in to source control.

Now, we need our Authy production key (sign up for Authy here). When you create an Authy application, the production key is found on the dashboard:

Authy dashboard

Loading Code Samples...
Language
# Be sure to restart your server when you modify this file.

# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!

# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rake secret` to generate a secure secret key.

# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.

development:
  secret_key_base: 2995cd200a475082070d5ad7b11c69407a6219b0b9bf1f747f62234709506c097da19f731ecf125a3fb53694ee103798d6962c199603b92be8f08b00bf6dbb18
  authy_key: <%= ENV["AUTHY_API_KEY"] %>

test:
  secret_key_base: deff24bab059bbcceeee98afac8df04814c44dd87d30841f8db532a815b64387d69cfd3d09a78417869c4846f133ba7978068882ca0a96626136ebd084b70732
  authy_key: <%= ENV["AUTHY_API_KEY"] %>

# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
  authy_key: <%= ENV["AUTHY_API_KEY"] %>
config/secrets.yml
Define configuration parameters used in the application

config/secrets.yml

Next, we need to jump over to the UserController to configure the Authy client and create an instance method to send a one-time password.

Sending a Token on Account Creation

Once the user has an authyId, we can actually send a verification code to that user's mobile phone.

When our user is created successfully via the form we implemented for the last story, we send a token to the user's mobile phone to verify their account in our controller.

Loading Code Samples...
Language
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def show
    @user = current_user
  end

  def create
    @user = User.new(user_params)
    if @user.save
      # Save the user_id to the session object
      session[:user_id] = @user.id

      # Create user on Authy, will return an id on the object
      authy = Authy::API.register_user(
        email: @user.email,
        cellphone: @user.phone_number,
        country_code: @user.country_code
      )
      @user.update(authy_id: authy.id)

      # Send an SMS to your user
      Authy::API.request_sms(id: @user.authy_id)

      redirect_to verify_path
    else
      render :new
    end
  end

  def show_verify
    return redirect_to new_user_path unless session[:user_id]
  end

  def verify
    @user = current_user

    # Use Authy to send the verification token
    token = Authy::API.verify(id: @user.authy_id, token: params[:token])

    if token.ok?
      # Mark the user as verified for get /user/:id
      @user.update(verified: true)

      # Send an SMS to the user 'success'
      send_message("You did it! Signup complete :)")

      # Show the user profile
      redirect_to user_path(@user.id)
    else
      flash.now[:danger] = "Incorrect code, please try again"
      render :show_verify
    end
  end

  def resend
    @user = current_user
    Authy::API.request_sms(id: @user.authy_id)
    flash[:notice] = 'Verification code re-sent'
    redirect_to verify_path
  end

  private

  def send_message(message)
    @user = current_user
    twilio_number = ENV['TWILIO_NUMBER']
    account_sid = ENV['TWILIO_ACCOUNT_SID']
    @client = Twilio::REST::Client.new account_sid, ENV['TWILIO_AUTH_TOKEN']
    message = @client.api.accounts(account_sid).messages.create(
      :from => twilio_number,
      :to => @user.country_code+@user.phone_number,
      :body => message
    )
  end

  def user_params
    params.require(:user).permit(
      :email, :password, :name, :country_code, :phone_number
    )
  end
end
app/controllers/users_controller.rb
Send an SMS to your user and re-direct to the user's verification page

app/controllers/users_controller.rb

When the code is sent, we redirect to another page where the user can enter the token they were sent, completing the verification process.

User Story: Verify the One-Time Password

As a user, I want to enter the one-time password sent to my mobile phone from the authentication system before I complete the signup process.

This story covers the next user-facing step of the verification process, where they enter the code we sent them to verify their possession of the phone number they gave us. Here's what needs to get done to complete this story:

  • Create a form to allow the user to enter the one-time password they were sent.
  • Create routes and controllers to both display the form and handle the submission of the one-time password.
Loading Code Samples...
Language
SDK Version:
  • html
<h1>Just To Be Safe...</h1>
<p>
    Your account has been created, but we need to make sure you're a human
    in control of the phone number you gave us. Can you please enter the 
    verification code we just sent to your phone?
</p>
<%= form_tag users_verify_path do %>
  <div class="form-group">
    <%= label_tag :code, "Verification Code:" %>
    <%= text_field_tag :token, '', class: "form-control" %>
  </div>
  <button type="submit" class="btn btn-primary">Verify Token</button>
<% end -%>

<hr>
<%= form_tag users_resend_path do %>
  <button type="submit" class="btn">Resend code</button>
<% end -%>
app/views/users/show_verify.html.erb
Form to verify a one-time password

app/views/users/show_verify.html.erb

The route definition in config/routes.rb is pretty straight-forward, so we'll skip that bit here. Let's begin instead with the verification form, which is created with the Embedded Ruby Template code you see here.

The Verification Form

This page actually has two forms, but we'll focus on the form for verifying a user's code first. It has only a single field for the verification code, which we'll submit to the server for validation.

Loading Code Samples...
Language
SDK Version:
  • html
<h1>Just To Be Safe...</h1>
<p>
    Your account has been created, but we need to make sure you're a human
    in control of the phone number you gave us. Can you please enter the 
    verification code we just sent to your phone?
</p>
<%= form_tag users_verify_path do %>
  <div class="form-group">
    <%= label_tag :code, "Verification Code:" %>
    <%= text_field_tag :token, '', class: "form-control" %>
  </div>
  <button type="submit" class="btn btn-primary">Verify Token</button>
<% end -%>

<hr>
<%= form_tag users_resend_path do %>
  <button type="submit" class="btn">Resend code</button>
<% end -%>
app/views/users/show_verify.html.erb
Form to verify a one-time password

app/views/users/show_verify.html.erb

Now let's take a look at the controller code handling this form.

Verifying the Code: Controller

This controller function handles the form submission. It needs to:

  • Get the current user.
  • Verify the code that was entered by the user.
  • If the code entered was valid, flip a boolean flag on the user model to indicate the account was verified.

Verifying the Code

Authy provides us with a verify method that allows us to pass a user id, a token and a callback function if we'd like. In this case we just need to check that the API request was successful and, if so, set user.verified to true.

Loading Code Samples...
Language
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def show
    @user = current_user
  end

  def create
    @user = User.new(user_params)
    if @user.save
      # Save the user_id to the session object
      session[:user_id] = @user.id

      # Create user on Authy, will return an id on the object
      authy = Authy::API.register_user(
        email: @user.email,
        cellphone: @user.phone_number,
        country_code: @user.country_code
      )
      @user.update(authy_id: authy.id)

      # Send an SMS to your user
      Authy::API.request_sms(id: @user.authy_id)

      redirect_to verify_path
    else
      render :new
    end
  end

  def show_verify
    return redirect_to new_user_path unless session[:user_id]
  end

  def verify
    @user = current_user

    # Use Authy to send the verification token
    token = Authy::API.verify(id: @user.authy_id, token: params[:token])

    if token.ok?
      # Mark the user as verified for get /user/:id
      @user.update(verified: true)

      # Send an SMS to the user 'success'
      send_message("You did it! Signup complete :)")

      # Show the user profile
      redirect_to user_path(@user.id)
    else
      flash.now[:danger] = "Incorrect code, please try again"
      render :show_verify
    end
  end

  def resend
    @user = current_user
    Authy::API.request_sms(id: @user.authy_id)
    flash[:notice] = 'Verification code re-sent'
    redirect_to verify_path
  end

  private

  def send_message(message)
    @user = current_user
    twilio_number = ENV['TWILIO_NUMBER']
    account_sid = ENV['TWILIO_ACCOUNT_SID']
    @client = Twilio::REST::Client.new account_sid, ENV['TWILIO_AUTH_TOKEN']
    message = @client.api.accounts(account_sid).messages.create(
      :from => twilio_number,
      :to => @user.country_code+@user.phone_number,
      :body => message
    )
  end

  def user_params
    params.require(:user).permit(
      :email, :password, :name, :country_code, :phone_number
    )
  end
end
app/controllers/users_controller.rb
Handle Authy verification and confirmation

app/controllers/users_controller.rb

That's all for this story! However, our verification form wouldn't be very usable if there wasn't a way to resend a verification code if the message didn't arrive at the end user's handset for whatever reason. Let's look at that next.

Re-sending the Code

Since the form for re-sending the code is one line (see show_verify.html.erb) we're going to skip that for this tutorial. Let's just look at the controller function.

This controller loads the User model associated with the request and then uses the same Authy API method we used earlier to resend the code. Pretty straightforward!

Loading Code Samples...
Language
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def show
    @user = current_user
  end

  def create
    @user = User.new(user_params)
    if @user.save
      # Save the user_id to the session object
      session[:user_id] = @user.id

      # Create user on Authy, will return an id on the object
      authy = Authy::API.register_user(
        email: @user.email,
        cellphone: @user.phone_number,
        country_code: @user.country_code
      )
      @user.update(authy_id: authy.id)

      # Send an SMS to your user
      Authy::API.request_sms(id: @user.authy_id)

      redirect_to verify_path
    else
      render :new
    end
  end

  def show_verify
    return redirect_to new_user_path unless session[:user_id]
  end

  def verify
    @user = current_user

    # Use Authy to send the verification token
    token = Authy::API.verify(id: @user.authy_id, token: params[:token])

    if token.ok?
      # Mark the user as verified for get /user/:id
      @user.update(verified: true)

      # Send an SMS to the user 'success'
      send_message("You did it! Signup complete :)")

      # Show the user profile
      redirect_to user_path(@user.id)
    else
      flash.now[:danger] = "Incorrect code, please try again"
      render :show_verify
    end
  end

  def resend
    @user = current_user
    Authy::API.request_sms(id: @user.authy_id)
    flash[:notice] = 'Verification code re-sent'
    redirect_to verify_path
  end

  private

  def send_message(message)
    @user = current_user
    twilio_number = ENV['TWILIO_NUMBER']
    account_sid = ENV['TWILIO_ACCOUNT_SID']
    @client = Twilio::REST::Client.new account_sid, ENV['TWILIO_AUTH_TOKEN']
    message = @client.api.accounts(account_sid).messages.create(
      :from => twilio_number,
      :to => @user.country_code+@user.phone_number,
      :body => message
    )
  end

  def user_params
    params.require(:user).permit(
      :email, :password, :name, :country_code, :phone_number
    )
  end
end
app/controllers/users_controller.rb
Re-send Authy code to current user

app/controllers/users_controller.rb

To wrap things up, let's implement our last user story where we confirm the user's account creation and verification.

User Story: Confirm Account Creation

As a user, I want to view a success page and receive a text message indicating that my account has been created successfully.

This story completes the account verification use case by indicating to the user that their account has been created and verified successfully. To implement this story, we need to:

  • Display a page that indicates that the user account has been created and verified successfully.
  • Send a text message to the user's phone indicating their account has been verified.
Loading Code Samples...
Language
SDK Version:
  • html
<h1><%= @user.name %></h1>
<p>Account Status: <% if @user.verified? %>Verified<% else -%>Not Verified<% end -%>
<% if !@user.verified? %>
<p>
  <%= link_to "Verify your account now.", verify_path %>
</p>
<% end -%>
app/views/users/show.html.erb
Account creation & verification confirmation page

app/views/users/show.html.erb

Show User Details Page

This simple .erb template displays a user name and let's them know they've been verified.

Just a reminder that our router is automatically looking for a 'show.html.erb' template to render since we told it to use Resource Routing which automatically creates a users/show/:id route.

Loading Code Samples...
Language
SDK Version:
  • html
<h1><%= @user.name %></h1>
<p>Account Status: <% if @user.verified? %>Verified<% else -%>Not Verified<% end -%>
<% if !@user.verified? %>
<p>
  <%= link_to "Verify your account now.", verify_path %>
</p>
<% end -%>
app/views/users/show.html.erb
Account creation & verification confirmation page

app/views/users/show.html.erb

This should suffice for in-browser confirmation that the user has been verified. Let's see how we might send that text message next.

Configuring Twilio

Authy is awesome for abstracting SMS and handling 2FA and account verification, but we can't use it to send arbitrary text messages. Let's use the Twilio API directly to do that!

In order to use the 'twilio-ruby' helper library we just need to include it in our Gemfile.

But first, we need to configure our Twilio account. We'll need three things, all of which can be found or set up through the Twilio console:

  • Our Twilio account SID
  • Our Twilio auth token
  • A Twilio number in our account that can send text messages
Loading Code Samples...
Language
source 'https://rubygems.org'


# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.3'
# Use postgresql as the database for Active Record
gem 'pg'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.1.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby

# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0', group: :doc

# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.7'

# Use Authy for sending token
gem 'authy'

# Use Twilio to send confirmation message
gem 'twilio-ruby', '~>5.0.0'

# Use Unicorn as the app server
gem 'unicorn'

group :production do
  gem 'rails_12factor'
end

group :development do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug'

  # Access an IRB console on exception pages or by using <%= console %> in views
  gem 'web-console', '~> 2.0'

  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'

  # Mocha for mocking
  gem 'mocha'
end
Gemfile
Configure Twilio and Authy in your application

Gemfile

Once we've hunted these config variables down we can create an instance function to send a message to the user's phone.

Sending a Message: Using the Twilio Client

Much as we did for our Authy client, we create a single instance of the Twilio REST API helper, called @client in this example.

Then all we need to do to send an sms is use the built in messages.create() to send an SMS to the user's phone. Notice we are combing country_code and phone_number to make sure we support international numbers.

Loading Code Samples...
Language
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def show
    @user = current_user
  end

  def create
    @user = User.new(user_params)
    if @user.save
      # Save the user_id to the session object
      session[:user_id] = @user.id

      # Create user on Authy, will return an id on the object
      authy = Authy::API.register_user(
        email: @user.email,
        cellphone: @user.phone_number,
        country_code: @user.country_code
      )
      @user.update(authy_id: authy.id)

      # Send an SMS to your user
      Authy::API.request_sms(id: @user.authy_id)

      redirect_to verify_path
    else
      render :new
    end
  end

  def show_verify
    return redirect_to new_user_path unless session[:user_id]
  end

  def verify
    @user = current_user

    # Use Authy to send the verification token
    token = Authy::API.verify(id: @user.authy_id, token: params[:token])

    if token.ok?
      # Mark the user as verified for get /user/:id
      @user.update(verified: true)

      # Send an SMS to the user 'success'
      send_message("You did it! Signup complete :)")

      # Show the user profile
      redirect_to user_path(@user.id)
    else
      flash.now[:danger] = "Incorrect code, please try again"
      render :show_verify
    end
  end

  def resend
    @user = current_user
    Authy::API.request_sms(id: @user.authy_id)
    flash[:notice] = 'Verification code re-sent'
    redirect_to verify_path
  end

  private

  def send_message(message)
    @user = current_user
    twilio_number = ENV['TWILIO_NUMBER']
    account_sid = ENV['TWILIO_ACCOUNT_SID']
    @client = Twilio::REST::Client.new account_sid, ENV['TWILIO_AUTH_TOKEN']
    message = @client.api.accounts(account_sid).messages.create(
      :from => twilio_number,
      :to => @user.country_code+@user.phone_number,
      :body => message
    )
  end

  def user_params
    params.require(:user).permit(
      :email, :password, :name, :country_code, :phone_number
    )
  end
end
app/controllers/users_controller.rb
Send message to user with Twilio

app/controllers/users_controller.rb

Sending a Message: Updating the Controller

In the controller, after a new user has been successfully verified, we use send_message to deliver them the happy news!

Loading Code Samples...
Language
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def show
    @user = current_user
  end

  def create
    @user = User.new(user_params)
    if @user.save
      # Save the user_id to the session object
      session[:user_id] = @user.id

      # Create user on Authy, will return an id on the object
      authy = Authy::API.register_user(
        email: @user.email,
        cellphone: @user.phone_number,
        country_code: @user.country_code
      )
      @user.update(authy_id: authy.id)

      # Send an SMS to your user
      Authy::API.request_sms(id: @user.authy_id)

      redirect_to verify_path
    else
      render :new
    end
  end

  def show_verify
    return redirect_to new_user_path unless session[:user_id]
  end

  def verify
    @user = current_user

    # Use Authy to send the verification token
    token = Authy::API.verify(id: @user.authy_id, token: params[:token])

    if token.ok?
      # Mark the user as verified for get /user/:id
      @user.update(verified: true)

      # Send an SMS to the user 'success'
      send_message("You did it! Signup complete :)")

      # Show the user profile
      redirect_to user_path(@user.id)
    else
      flash.now[:danger] = "Incorrect code, please try again"
      render :show_verify
    end
  end

  def resend
    @user = current_user
    Authy::API.request_sms(id: @user.authy_id)
    flash[:notice] = 'Verification code re-sent'
    redirect_to verify_path
  end

  private

  def send_message(message)
    @user = current_user
    twilio_number = ENV['TWILIO_NUMBER']
    account_sid = ENV['TWILIO_ACCOUNT_SID']
    @client = Twilio::REST::Client.new account_sid, ENV['TWILIO_AUTH_TOKEN']
    message = @client.api.accounts(account_sid).messages.create(
      :from => twilio_number,
      :to => @user.country_code+@user.phone_number,
      :body => message
    )
  end

  def user_params
    params.require(:user).permit(
      :email, :password, :name, :country_code, :phone_number
    )
  end
end
app/controllers/users_controller.rb
Send success SMS

app/controllers/users_controller.rb

Congratulations! You now have the power to register and verify users with Authy and Twilio SMS.

Where to Next?

If you're a Ruby developer working with Twilio, you might want to check out these other tutorials:

Click To Call

Put a button on your web page that connects visitors to live support or sales people via telephone.

Automated Survey

Instantly collect structured data from your users with a survey conducted over a voice call or SMS text messages.

Did this help?

Thanks for checking this tutorial out! If you have any feedback to share with us, we'd love to hear it. Reach out to us on Twitter and let us know what you build!

Jarod Reyes
Jose Oliveros
Kat King
Agustin Camino
Samuel Mendes
Hector Ortega

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

1 / 1
Loading Code Samples...
class User < ActiveRecord::Base
  has_secure_password

  validates :email,  presence: true, format: { with: /\A.+@.+$\Z/ }, uniqueness: true
  validates :name, presence: true
  validates :country_code, presence: true
  validates :phone_number, presence: true
end
Rails.application.routes.draw do

  get "users/verify", to: 'users#show_verify', as: 'verify'
  post "users/verify"
  post "users/resend"

  # Create users
  resources :users, only: [:new, :create, :show]

  # Home page
  root 'main#index'

end
SDK Version:
  • html
<h1>We're going to be *BEST* friends</h1>
<p> Thanks for your interest in signing up! Can you tell us a bit about yourself?</p>

<% if @user.errors.any? %>
  <h2>Oops, something went wrong!</h2>

  <ul>
    <% @user.errors.full_messages.each do |error| %>
      <li><%= error %></li>
    <% end -%>
  </ul>
<% end -%>

<%= form_for @user do |f| %>
  <div class="form-group">
    <%= f.label :name, "Tell us your name:" %>
    <%= f.text_field :name, class: "form-control", placeholder: "Zingelbert Bembledack" %>
  </div>
  <div class="form-group">
    <%= f.label :email, "Enter Your E-mail Address:" %>
    <%= f.email_field :email, class: "form-control", placeholder: "me@mydomain.com" %>
  </div>
  <div class="form-group">
    <%= f.label :password, "Enter a password:" %>
    <%= f.password_field :password, class: "form-control" %>
  </div>
  <div class="form-group">
    <%= f.label :country_code %>
    <%= f.text_field :country_code, class: "form-control", id: "authy-countries" %>
  </div>
  <div class="form-group">
    <%= f.label :phone_number %>
    <%= f.text_field :phone_number, class: "form-control", id: "authy-cellphone" %>
  </div>
  <button class="btn btn-primary">Sign up</button>
<% end -%>
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def show
    @user = current_user
  end

  def create
    @user = User.new(user_params)
    if @user.save
      # Save the user_id to the session object
      session[:user_id] = @user.id

      # Create user on Authy, will return an id on the object
      authy = Authy::API.register_user(
        email: @user.email,
        cellphone: @user.phone_number,
        country_code: @user.country_code
      )
      @user.update(authy_id: authy.id)

      # Send an SMS to your user
      Authy::API.request_sms(id: @user.authy_id)

      redirect_to verify_path
    else
      render :new
    end
  end

  def show_verify
    return redirect_to new_user_path unless session[:user_id]
  end

  def verify
    @user = current_user

    # Use Authy to send the verification token
    token = Authy::API.verify(id: @user.authy_id, token: params[:token])

    if token.ok?
      # Mark the user as verified for get /user/:id
      @user.update(verified: true)

      # Send an SMS to the user 'success'
      send_message("You did it! Signup complete :)")

      # Show the user profile
      redirect_to user_path(@user.id)
    else
      flash.now[:danger] = "Incorrect code, please try again"
      render :show_verify
    end
  end

  def resend
    @user = current_user
    Authy::API.request_sms(id: @user.authy_id)
    flash[:notice] = 'Verification code re-sent'
    redirect_to verify_path
  end

  private

  def send_message(message)
    @user = current_user
    twilio_number = ENV['TWILIO_NUMBER']
    account_sid = ENV['TWILIO_ACCOUNT_SID']
    @client = Twilio::REST::Client.new account_sid, ENV['TWILIO_AUTH_TOKEN']
    message = @client.api.accounts(account_sid).messages.create(
      :from => twilio_number,
      :to => @user.country_code+@user.phone_number,
      :body => message
    )
  end

  def user_params
    params.require(:user).permit(
      :email, :password, :name, :country_code, :phone_number
    )
  end
end
# Be sure to restart your server when you modify this file.

# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!

# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rake secret` to generate a secure secret key.

# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.

development:
  secret_key_base: 2995cd200a475082070d5ad7b11c69407a6219b0b9bf1f747f62234709506c097da19f731ecf125a3fb53694ee103798d6962c199603b92be8f08b00bf6dbb18
  authy_key: <%= ENV["AUTHY_API_KEY"] %>

test:
  secret_key_base: deff24bab059bbcceeee98afac8df04814c44dd87d30841f8db532a815b64387d69cfd3d09a78417869c4846f133ba7978068882ca0a96626136ebd084b70732
  authy_key: <%= ENV["AUTHY_API_KEY"] %>

# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
  authy_key: <%= ENV["AUTHY_API_KEY"] %>
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def show
    @user = current_user
  end

  def create
    @user = User.new(user_params)
    if @user.save
      # Save the user_id to the session object
      session[:user_id] = @user.id

      # Create user on Authy, will return an id on the object
      authy = Authy::API.register_user(
        email: @user.email,
        cellphone: @user.phone_number,
        country_code: @user.country_code
      )
      @user.update(authy_id: authy.id)

      # Send an SMS to your user
      Authy::API.request_sms(id: @user.authy_id)

      redirect_to verify_path
    else
      render :new
    end
  end

  def show_verify
    return redirect_to new_user_path unless session[:user_id]
  end

  def verify
    @user = current_user

    # Use Authy to send the verification token
    token = Authy::API.verify(id: @user.authy_id, token: params[:token])

    if token.ok?
      # Mark the user as verified for get /user/:id
      @user.update(verified: true)

      # Send an SMS to the user 'success'
      send_message("You did it! Signup complete :)")

      # Show the user profile
      redirect_to user_path(@user.id)
    else
      flash.now[:danger] = "Incorrect code, please try again"
      render :show_verify
    end
  end

  def resend
    @user = current_user
    Authy::API.request_sms(id: @user.authy_id)
    flash[:notice] = 'Verification code re-sent'
    redirect_to verify_path
  end

  private

  def send_message(message)
    @user = current_user
    twilio_number = ENV['TWILIO_NUMBER']
    account_sid = ENV['TWILIO_ACCOUNT_SID']
    @client = Twilio::REST::Client.new account_sid, ENV['TWILIO_AUTH_TOKEN']
    message = @client.api.accounts(account_sid).messages.create(
      :from => twilio_number,
      :to => @user.country_code+@user.phone_number,
      :body => message
    )
  end

  def user_params
    params.require(:user).permit(
      :email, :password, :name, :country_code, :phone_number
    )
  end
end
SDK Version:
  • html
<h1>Just To Be Safe...</h1>
<p>
    Your account has been created, but we need to make sure you're a human
    in control of the phone number you gave us. Can you please enter the 
    verification code we just sent to your phone?
</p>
<%= form_tag users_verify_path do %>
  <div class="form-group">
    <%= label_tag :code, "Verification Code:" %>
    <%= text_field_tag :token, '', class: "form-control" %>
  </div>
  <button type="submit" class="btn btn-primary">Verify Token</button>
<% end -%>

<hr>
<%= form_tag users_resend_path do %>
  <button type="submit" class="btn">Resend code</button>
<% end -%>
SDK Version:
  • html
<h1>Just To Be Safe...</h1>
<p>
    Your account has been created, but we need to make sure you're a human
    in control of the phone number you gave us. Can you please enter the 
    verification code we just sent to your phone?
</p>
<%= form_tag users_verify_path do %>
  <div class="form-group">
    <%= label_tag :code, "Verification Code:" %>
    <%= text_field_tag :token, '', class: "form-control" %>
  </div>
  <button type="submit" class="btn btn-primary">Verify Token</button>
<% end -%>

<hr>
<%= form_tag users_resend_path do %>
  <button type="submit" class="btn">Resend code</button>
<% end -%>
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def show
    @user = current_user
  end

  def create
    @user = User.new(user_params)
    if @user.save
      # Save the user_id to the session object
      session[:user_id] = @user.id

      # Create user on Authy, will return an id on the object
      authy = Authy::API.register_user(
        email: @user.email,
        cellphone: @user.phone_number,
        country_code: @user.country_code
      )
      @user.update(authy_id: authy.id)

      # Send an SMS to your user
      Authy::API.request_sms(id: @user.authy_id)

      redirect_to verify_path
    else
      render :new
    end
  end

  def show_verify
    return redirect_to new_user_path unless session[:user_id]
  end

  def verify
    @user = current_user

    # Use Authy to send the verification token
    token = Authy::API.verify(id: @user.authy_id, token: params[:token])

    if token.ok?
      # Mark the user as verified for get /user/:id
      @user.update(verified: true)

      # Send an SMS to the user 'success'
      send_message("You did it! Signup complete :)")

      # Show the user profile
      redirect_to user_path(@user.id)
    else
      flash.now[:danger] = "Incorrect code, please try again"
      render :show_verify
    end
  end

  def resend
    @user = current_user
    Authy::API.request_sms(id: @user.authy_id)
    flash[:notice] = 'Verification code re-sent'
    redirect_to verify_path
  end

  private

  def send_message(message)
    @user = current_user
    twilio_number = ENV['TWILIO_NUMBER']
    account_sid = ENV['TWILIO_ACCOUNT_SID']
    @client = Twilio::REST::Client.new account_sid, ENV['TWILIO_AUTH_TOKEN']
    message = @client.api.accounts(account_sid).messages.create(
      :from => twilio_number,
      :to => @user.country_code+@user.phone_number,
      :body => message
    )
  end

  def user_params
    params.require(:user).permit(
      :email, :password, :name, :country_code, :phone_number
    )
  end
end
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def show
    @user = current_user
  end

  def create
    @user = User.new(user_params)
    if @user.save
      # Save the user_id to the session object
      session[:user_id] = @user.id

      # Create user on Authy, will return an id on the object
      authy = Authy::API.register_user(
        email: @user.email,
        cellphone: @user.phone_number,
        country_code: @user.country_code
      )
      @user.update(authy_id: authy.id)

      # Send an SMS to your user
      Authy::API.request_sms(id: @user.authy_id)

      redirect_to verify_path
    else
      render :new
    end
  end

  def show_verify
    return redirect_to new_user_path unless session[:user_id]
  end

  def verify
    @user = current_user

    # Use Authy to send the verification token
    token = Authy::API.verify(id: @user.authy_id, token: params[:token])

    if token.ok?
      # Mark the user as verified for get /user/:id
      @user.update(verified: true)

      # Send an SMS to the user 'success'
      send_message("You did it! Signup complete :)")

      # Show the user profile
      redirect_to user_path(@user.id)
    else
      flash.now[:danger] = "Incorrect code, please try again"
      render :show_verify
    end
  end

  def resend
    @user = current_user
    Authy::API.request_sms(id: @user.authy_id)
    flash[:notice] = 'Verification code re-sent'
    redirect_to verify_path
  end

  private

  def send_message(message)
    @user = current_user
    twilio_number = ENV['TWILIO_NUMBER']
    account_sid = ENV['TWILIO_ACCOUNT_SID']
    @client = Twilio::REST::Client.new account_sid, ENV['TWILIO_AUTH_TOKEN']
    message = @client.api.accounts(account_sid).messages.create(
      :from => twilio_number,
      :to => @user.country_code+@user.phone_number,
      :body => message
    )
  end

  def user_params
    params.require(:user).permit(
      :email, :password, :name, :country_code, :phone_number
    )
  end
end
SDK Version:
  • html
<h1><%= @user.name %></h1>
<p>Account Status: <% if @user.verified? %>Verified<% else -%>Not Verified<% end -%>
<% if !@user.verified? %>
<p>
  <%= link_to "Verify your account now.", verify_path %>
</p>
<% end -%>
SDK Version:
  • html
<h1><%= @user.name %></h1>
<p>Account Status: <% if @user.verified? %>Verified<% else -%>Not Verified<% end -%>
<% if !@user.verified? %>
<p>
  <%= link_to "Verify your account now.", verify_path %>
</p>
<% end -%>
source 'https://rubygems.org'


# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.3'
# Use postgresql as the database for Active Record
gem 'pg'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.1.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby

# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0', group: :doc

# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.7'

# Use Authy for sending token
gem 'authy'

# Use Twilio to send confirmation message
gem 'twilio-ruby', '~>5.0.0'

# Use Unicorn as the app server
gem 'unicorn'

group :production do
  gem 'rails_12factor'
end

group :development do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug'

  # Access an IRB console on exception pages or by using <%= console %> in views
  gem 'web-console', '~> 2.0'

  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'

  # Mocha for mocking
  gem 'mocha'
end
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def show
    @user = current_user
  end

  def create
    @user = User.new(user_params)
    if @user.save
      # Save the user_id to the session object
      session[:user_id] = @user.id

      # Create user on Authy, will return an id on the object
      authy = Authy::API.register_user(
        email: @user.email,
        cellphone: @user.phone_number,
        country_code: @user.country_code
      )
      @user.update(authy_id: authy.id)

      # Send an SMS to your user
      Authy::API.request_sms(id: @user.authy_id)

      redirect_to verify_path
    else
      render :new
    end
  end

  def show_verify
    return redirect_to new_user_path unless session[:user_id]
  end

  def verify
    @user = current_user

    # Use Authy to send the verification token
    token = Authy::API.verify(id: @user.authy_id, token: params[:token])

    if token.ok?
      # Mark the user as verified for get /user/:id
      @user.update(verified: true)

      # Send an SMS to the user 'success'
      send_message("You did it! Signup complete :)")

      # Show the user profile
      redirect_to user_path(@user.id)
    else
      flash.now[:danger] = "Incorrect code, please try again"
      render :show_verify
    end
  end

  def resend
    @user = current_user
    Authy::API.request_sms(id: @user.authy_id)
    flash[:notice] = 'Verification code re-sent'
    redirect_to verify_path
  end

  private

  def send_message(message)
    @user = current_user
    twilio_number = ENV['TWILIO_NUMBER']
    account_sid = ENV['TWILIO_ACCOUNT_SID']
    @client = Twilio::REST::Client.new account_sid, ENV['TWILIO_AUTH_TOKEN']
    message = @client.api.accounts(account_sid).messages.create(
      :from => twilio_number,
      :to => @user.country_code+@user.phone_number,
      :body => message
    )
  end

  def user_params
    params.require(:user).permit(
      :email, :password, :name, :country_code, :phone_number
    )
  end
end
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def show
    @user = current_user
  end

  def create
    @user = User.new(user_params)
    if @user.save
      # Save the user_id to the session object
      session[:user_id] = @user.id

      # Create user on Authy, will return an id on the object
      authy = Authy::API.register_user(
        email: @user.email,
        cellphone: @user.phone_number,
        country_code: @user.country_code
      )
      @user.update(authy_id: authy.id)

      # Send an SMS to your user
      Authy::API.request_sms(id: @user.authy_id)

      redirect_to verify_path
    else
      render :new
    end
  end

  def show_verify
    return redirect_to new_user_path unless session[:user_id]
  end

  def verify
    @user = current_user

    # Use Authy to send the verification token
    token = Authy::API.verify(id: @user.authy_id, token: params[:token])

    if token.ok?
      # Mark the user as verified for get /user/:id
      @user.update(verified: true)

      # Send an SMS to the user 'success'
      send_message("You did it! Signup complete :)")

      # Show the user profile
      redirect_to user_path(@user.id)
    else
      flash.now[:danger] = "Incorrect code, please try again"
      render :show_verify
    end
  end

  def resend
    @user = current_user
    Authy::API.request_sms(id: @user.authy_id)
    flash[:notice] = 'Verification code re-sent'
    redirect_to verify_path
  end

  private

  def send_message(message)
    @user = current_user
    twilio_number = ENV['TWILIO_NUMBER']
    account_sid = ENV['TWILIO_ACCOUNT_SID']
    @client = Twilio::REST::Client.new account_sid, ENV['TWILIO_AUTH_TOKEN']
    message = @client.api.accounts(account_sid).messages.create(
      :from => twilio_number,
      :to => @user.country_code+@user.phone_number,
      :body => message
    )
  end

  def user_params
    params.require(:user).permit(
      :email, :password, :name, :country_code, :phone_number
    )
  end
end