If you ever need to contact your application’s users by phone then it’s good practice to verify that the phone number they enter is in fact theirs. Let’s see how to verify phone numbers in a Rails 5 application using the Authy Phone Verification API.
What you’ll need
To code along with this post, you’ll need:
- A Twilio account
- An Authy App which you can create in the Twilio console, you’ll need the API key
- Ruby and Rails installed, I am using the latest Rails 5.1.2 and Ruby 2.4.1
Create a new Rails application for this project:
rails new phone_verification cd phone_verification
We need to add a couple of gems that we’ll use in the project, open up the
Gemfile and add
envyable. Authy is going to be used for the phone verification, envyable to manage environment variables.
gem 'envyable' gem 'authy'
Install the gems, then initialise envyable from the command line:
bundle install bundle exec envyable install
config/env.yml and add your Authy app API key:
Now, initialise Authy itself by creating the file
config/initializers/authy.rb and add the following code:
Authy.api_key = ENV['AUTHY_API_KEY'] Authy.api_uri = 'https://api.authy.com/'
That is all the initialisation we need, we can now get on with building the application.
Building the app
The process of verification is quite straightforward.
- The user enters three bits of information
- Phone number
- Country code
- Whether they want to verify by voice or SMS
- Our application makes a request to the API to initiate the verification
- The user receives a call or text message with a 4 digit code
- They then enter that code into a form in the application
- The code is sent off to the API, with their phone number and country code again, to verify
- If it is correct then the user has verified their number
We’re going to need a controller that will both present the views we need as well as do the work to initialise the verification and actually verify the phone number. Generate a controller with:
bundle exec rails generate controller phone_verifications new create challenge verify success
This will create five actions and five views. We don’t need the create and verify views, so you can delete those. It will also generate some routes. Open
config/routes.rb remove the 5 new routes and replace them with:
resources :phone_verifications, :only => [:new, :create] do |p| collection do get 'challenge' post 'verify' get 'success' end end
This creates 5 routes which you can check out by running
rails routes on the command line. They look like this:
bundle exec rails routes Prefix Verb URI Pattern Controller#Action challenge_phone_verifications GET /phone_verifications/challenge(.:format) phone_verifications#challenge verify_phone_verifications POST /phone_verifications/verify(.:format) phone_verifications#verify success_phone_verifications GET /phone_verifications/success(.:format) phone_verifications#success phone_verifications POST /phone_verifications(.:format) phone_verifications#create new_phone_verification GET /phone_verifications/new(.:format) phone_verifications#new
The first view
new action needs to display a form to the user that takes their phone number, the country code of the country they are in and whether they want the verification by SMS or voice call.
app/views/phone_verifications/new.html.erb replace the code that was generated with the following:
<h1>Verify your phone number</h1> <%= form_tag(phone_verifications_path, method: :post) do -%> <% if @response %> <% @response.errors.each do |key, message| %> <p><%= message %></p> <% end %> <% end %> <div> <%= label_tag "authy-countries", "Country code:" %> <%= select_tag "authy-countries", nil, name: 'country_code', 'data-show-as': 'number' %> </div> <div> <%= label_tag "phone_number", "Phone number:" %> <%= telephone_field_tag "phone_number", nil, name: 'phone_number' %> </div> <div> <p>Verification method</p> <%= label_tag "method_sms", "SMS: " %> <%= radio_button_tag "method", "sms" %> <%= label_tag "method_call", "Call: " %> <%= radio_button_tag "method", "call" %> </div> <%= button_tag "Verify" %> <% end -%>
This code sets up the form to submit the three fields. Using the ID
"authy-countries" means that the
We also use
telephone_field_tag to create an HTML input with a type of
"tel" so that mobile devices show an optimised keyboard for entering telephone numbers.
Start up the server:
bundle exec rails server
Navigate to http://localhost:3000/phone_verifications/new to see the new form and try out the country code field.
The verification process
Now we have our form to start the process, we need to begin the verification. Using the parameters entered into the form, we will build an API request to the Authy phone verification API and send it off. If it is successful we will present the form asking for the verification code, otherwise we should re-render the initial form and show the error.
app/controllers/phone_verifications_controller.rb replace the empty
create method with this code:
def create session[:phone_number] = params[:phone_number] session[:country_code] = params[:country_code] @response = Authy::PhoneVerification.start( via: params[:method], country_code: params[:country_code], phone_number: params[:phone_number] ) if @response.ok? redirect_to challenge_phone_verifications_path else render :new end end
The key part here is the call to
Authy::PhoneVerification.start. We pass the parameters we gathered from the user, including the way to contact them, the phone number and the country code. If the response to this is ok, then the verification process will start, otherwise there is an issue.
We already built in the code to display errors if something does go wrong. These lines in the view handle that:
<% if @response %> <% @response.errors.each do |key, message| %> <p><%= message %></p> <% end %> <% end %>
Note too, that we save the phone number and country code to the session so that we can use them later. In a full application these would be saved against a user or phone number record in the database and we’d keep the ID of the record in the session.
We now need users to enter the 4 digits that the verification process sends them. Add the following code to
<h1>Challenge</h1> <%= form_tag(verify_phone_verifications_path, method: :post) do -%> <% if @response %> <% @response.errors.each do |key, message| %> <p><%= message %></p> <% end %> <% end %> <div> <%= label_tag "code", "Enter the code you were sent:" %> <%= text_field_tag "code" %> </div> <%= button_tag "Verify" %> <% end -%>
Time to verify
Now we have the user’s 4 digit code we need to verify it with the API. Replace the empty
verify action in the
def verify @response = Authy::PhoneVerification.check( verification_code: params[:code], country_code: session[:country_code], phone_number: session[:phone_number] ) if @response.ok? session[:phone_number] = nil session[:country_code] = nil redirect_to success_phone_verifications_path else render :challenge end end
This time the key part here is making the request to
Authy::PhoneVerification.check passing in the phone number and country code that we saved earlier along with the code the user entered. If the response is ok this time, then the verification was a success and we can clear the session and redirect to the success path. In a real application you would likely mark that the user or phone record was indeed verified and save that in the database too.
If the code was wrong, we’ll just show the challenge view again so that the user can try again if they made a mistake.
To finish off, add a success message to
<h1>Congratulations!</h1> <p>You have successfully verified your phone number.</p>
Let’s test it out
If you didn’t start the server earlier, do so now:
bundle exec rails server
Go to http://localhost:3000/phone_verifications/new and enter the correct details. When you get the phone call or SMS message, enter the verification code into the second form and you will see a message of success that your phone is verified.
Phone numbers? Verified!
That’s how to get started with the Authy Phone Verification API in Rails 5. You can check out the full code for this article on GitHub. This application is far from complete of course, there is much more to do. You’d want to:
- save the phone number and its verification status to a user model in your database
- handle errors better, giving users the chance to resend or call again or check and update the phone number
If you’ve got any questions or comments, then please do get in touch. Leave me a comment below or give me a shout on Twitter.