Back to Blog

Phone verification using SMS via Twilio

on January 12, 2015

In this blog post, I'm going to show you how to do phone verification using SMS via Twilio. We will be using Twilio gem.

Requirement

  • When a user signs up , we want to send an SMS to that user with a random string to verify user's phone number.
  • If that user replies back with that code, then verify user's phone number in the app. Once the phone number is verified, then we can use that phone number for future use.

Step 1: Create required columns in users table

Let's create phone_number, phone_verification_code and phone_verified columns in the users table.

1 $ bin/rails generate migration AddPhoneAttributesToUsers phone_number:string phone_verification_code:string phone_verified:boolean

Then run the migration.

Step 2: Add phone number field in registration form

Add phone_number field in the registration form.

1  <%= f.text_field :phone_number %>

Step 3: Send an SMS with verification code

When a user submits registration form, we need to send SMS if phone number is present. To handle this, add following code in User model.

1class User < ActiveRecord::Base
2  scope :unverified_phones,  -> { where(phone_verified: false) }
3
4  before_save :set_phone_attributes, if: :phone_verification_needed?
5  after_save :send_sms_for_phone_verification, if: :phone_verification_needed?
6
7  def mark_phone_as_verified!
8    update!(phone_verified: true, phone_verification_code: nil)
9  end
10
11  private
12
13  def set_phone_attributes
14    self.phone_verified = false
15    self.phone_verification_code = generate_phone_verification_code
16
17    # removes all white spaces, hyphens, and parenthesis
18    self.phone_number.gsub!(/[\s\-\(\)]+/, '')
19  end
20
21  def send_sms_for_phone_verification
22    PhoneVerificationService.new(user_id: id).process
23  end
24
25  def generate_phone_verification_code
26    begin
27     verification_code = SecureRandom.hex(3)
28    end while self.class.exists?(phone_verification_code: verification_code)
29
30    verification_code
31  end
32
33  def phone_verification_needed?
34    phone_number.present? && phone_number_changed?
35  end
36end

We have added 2 major changes in the user model,

  • set_phone_attributes method is set in before_save callback.
  • send_sms_for_phone_verification method is set in after_save callback.

In set_phone_attributes method, we are setting up the phone attributes mainly sanitizing phone number and generating unique phone verification code. In send_sms_for_phone_verification method, we send SMS to the user. Creation of SMS for the phone verification message is handled in PhoneVerificationService class.

1class PhoneVerificationService
2  attr_reader :user
3
4  def initialize(options)
5    @user = User.find(options[:user_id])
6  end
7
8  def process
9    send_sms
10  end
11
12  private
13
14  def from
15    # Add your twilio phone number (programmable phone number)
16    Settings.twilio_number_for_app
17  end
18
19  def to
20    # +1 is a country code for USA
21    "+1#{user.phone_number}"
22  end
23
24  def body
25    "Please reply with this code '#{user.phone_verification_code}' to
26    verify your phone number"
27  end
28
29  def twilio_client
30    # Pass your twilio account SID and auth token
31    @twilio ||= Twilio::REST::Client.new(Settings.twilio_account_sid,
32                                         Settings.twilio_auth_token)
33  end
34
35  def send_sms
36    Rails.logger.info "SMS: From: #{from} To: #{to} Body: \"#{body}\""
37
38    twilio_client.account.messages.create(
39      from: from,
40      to: to,
41      body: body
42    )
43  end
44end

In PhoneVerificationService class, we have defined user as an attribute reader and in initialize method, we have set the user object to it. Now if you see process method, it does lots of stuff for us.

Lets go through each method.

  • from - In this method, we set up the twilio phone number e.g. programmable number.
  • to - In this method, we set the phone number to which we want to send an SMS.
  • body - In this method, we build text message with verification code.
  • twilio_client - It creates twilio client based on twilio account SID and auth token.
  • send_sms - And last, it sends SMS to the user.

Step 4: Set request URL for phone verification in Twilio

As of now the system has the capability to send SMS to a user. Now we need to add capability to receive the SMS and to match the verification code.

First, we need to set up a request URL in Twilio account.

Open twilio account and under NUMBERS section/tab, click on your Twilio number. Then in Messaging section, add request URL with HTTP POST method. Add URL like this.

1http://your.ngrok.com/phone_verifications/verify_from_message/

But to make it work, we need our Rails app on the public internet. There are two options for this:

  1. Deploy Rails app to your VPS or PaaS of choice.
  2. Use a tunneling service to take the server running on your development machine and make it available at an address on the public internet.

I'm going to use Ngrok tunneling service for the purpose of this blog. You can check this blog for more about its usage.

Step 5: Create phone verification controller

We need one more controller, which will handle phone verification when request comes from Twilio. When a user replies back with a verification code, it will trigger request URL through Twilio API. To handle that request, let's add phone verifications controller.

1  $ bin/rails generate controller phone_verifications

Add new route in config/routes.rb

1post "phone_verifications/verify_from_message" => "phone_verifications#verify_from_message"

Add following code to the PhoneVerificationsController.

1class PhoneVerificationsController < ApplicationController
2  skip_before_action :verify_authenticity_token
3
4  def verify_from_message
5    user = get_user_for_phone_verification
6    user.mark_phone_as_verified! if user
7
8    render nothing: true
9  end
10
11  private
12
13  def get_user_for_phone_verification
14    phone_verification_code = params['Body'].try(:strip)
15    phone_number            = params['From'].gsub('+1', '')
16
17    condition = { phone_verification_code: phone_verification_code,
18                  phone_number: phone_number }
19
20    User.unverified_phones.where(condition).first
21  end
22end

In this controller, we added skip_before_action :verify_authenticity_token, this is because we need to allow twilio request in our Rails app which is actually an outside request (e.g. not secured request). This means we have disabled CSRF detection for this controller.

Now look at the verify_from_message method, in this method we take phone verification code and phone number from params hash. Using those data, we find the user from the database. Once we get the user, then we mark user's phone number as a verified phone number.

Finally we are set to send business level text messages to the verified phone number.

This blog has more information about how to make secure twilio requests.


You might also like

If you liked this blog post, check out similar ones from BigBinary