How to build a one-time passcode protected conference line with Twilio Verify and Ruby
Time to read: 6 minutes
We've seen how to build a conference line and then protect it with a static passcode. However, passcodes can be guessed or leaked, especially if they are reused over time. An alternative is to make a list of numbers that are permitted to join the call. But, since spoofing phone numbers is relatively easy, this still may not protect you.
A one-time passcode (OTP) sent to a caller's phone or email, can verify they are who they say they are and increase the security of your conference line once more.
In this post we will take the Rails application we previously developed and add a conference line secured in two ways. We will:
- Ensure that the caller is a known participant by checking their caller ID against a list of permitted phone numbers
- Send them an OTP using Twilio Verify which they then have to enter correctly to ensure they aren't spoofing the number
What you'll need
In order to code along with this tutorial you will need:
- Ruby and Bundler installed
- A Twilio account (if you don't have one yet, sign up for a new Twilio account here and receive $10 credit when you upgrade)
- A Twilio phone number that can receive incoming calls
- ngrok for testing webhooks with our local application
Once you've got all that, we can get started.
On the Rails
We will use the existing Rails application that we've added a couple of conference lines to so far. We'll continue to add to that app in this post. If you don't already have the application, download or clone it from GitHub.
Install the dependencies:
Start the server to make sure everything is working as expected:
While the server is running, you can make a POST request to the open conference call webhook endpoint to see it working. It should look a bit like this:
This response is in TwiML and tells Twilio what to do with a call. If we set a phone number's incoming call webhook to the /calls
endpoint within this application, then anyone who calls will be welcomed and then entered into the conference call.
In the last blog post we added an endpoint that would enforce passcode protection on your conference call. This version is available at the /protected_calls/welcome
and /protected_calls/verify
routes.
Let's get started building verified called protection.
Protecting a call with a list of permitted callers
We're going to set the list of permitted callers using environment variables. To make that easier to manage we'll use the envyable gem. Open the Gemfile
and add the gem to the development and test group:
Install the dependency then run the envyable install task:
The install task creates a config/env.yml
file, open that up and fill in two variables:
PERMITTED_CALLERS
: a comma separated list of numbers in e.164 format that will be allowed into your conference callMODERATOR
: the number of your conference call moderator, this will be the caller that starts and ends the conference call
Next, generate a new controller for our verified conference calls:
Open your new controller located in app/controllers/verified_calls_controller.rb
. The first thing we need to do in this controller is disable cross site request forgery (CSRF) protection. This controller will be used to respond to incoming webhooks, which cannot include a CSRF token. We can protect webhook endpoints in our Rails application by validating Twilio's request signature using Rack middleware instead.
To disable the CSRF protection, add the following line to the controller class:
We're going to add two actions to this controller, one that will check whether the caller is on our permitted list of callers and the other to enter them into the conference. This could be done within one action, but when we add OTP verification later we will need two actions.
Create the welcome
action. We'll use the helpers from the twilio-ruby library to generate the TwiML response and render it as XML.
In the welcome
action we will check whether the caller is permitted to join the conference by checking against the PERMITTED_CALLERS
and MODERATOR
environment variables. We can write a private method to make what it is doing more obvious.
Use the participant_permitted?
method to check that the caller's number, the From
parameter in the request, is allowed and then redirect to the next path. If the number isn't recognised, we will use <Say>
to deliver a message to the caller and <Hangup>
to end the call.
We will use the path verified_calls_verify_path
which we are yet to define. We will need the verify
action for that. For now, this action won't verify anything, it will just add the caller to the conference. We'll use some of the <Conference>
TwiML attributes available here to control the call more effectively. The boolean attributes start_conference_on_enter
and end_conference_on_exit
are useful for moderated conferences. In this case, all participants will be held listening to hold music until the moderator dials in and joins the conference. The call will also be terminated once the moderator hangs up. Place this method after the welcome
method.
Let's define the routes for these actions now. Open config/routes.rb
and add POST
routes for both actions in this controller.
Testing out the line so far
Let's hook this application up to a phone number and test that it's working. Then we can add OTP verification to make the line extra secure.
Make sure that your own phone number is set as either in either the MODERATOR
or PERMITTED_PARTICIPANTS
variables in config/env.yml
Start the application with:
The application will start up on localhost:3000. Next, start ngrok so that we can get a public URL for this application to use with Twilio's webhooks.
You will get a URL like https://RANDOM_SUBDOMAIN.ngrok.io
, put it together with the path to the welcome action we just wrote to make https://RANDOM_SUBDOMAIN.ngrok.io/verified_calls/welcome
. Open the Twilio console and edit the phone number you chose to use for this application. Add the URL as the voice webhook for when calls come in and save the number.
Now call your number; you will be greeted and allowed to enter the conference call.
Remove your number from the permitted participants and call up again. This time you will be rejected from the conference call.
Securing the conference call with an OTP
Now we're going to make sure that callers are definitely who they say they are by using Twilio Verify to send them an OTP that they will have to enter.
For this feature, we are going to need to store some more details in the environment. We're going to make requests to the API, so we'll need the Account Sid and Auth Token from your Twilio console. Add them to config/env.yml
like so:
We also need a Verify Service Sid. To get one, create a new Verify Service in your Twilio console.
Grab the Verify Service Sid and add it to config/env.yml
too.
Head back to app/controllers/verified_calls_controller.rb
. The plan now is for the welcome
action to check whether the caller is permitted to join the conference and, if they are, start a verification and ask them to enter the passcode.
Starting an SMS verification with the Twilio Ruby library looks like this:
When they enter the code Twilio will make a request to the verify
action, passing the digits of the code as the Digits
parameter. We'll then use the code to check the verification and if it is approved send the caller into the conference call. If the code is incorrect we'll direct them back to the welcome
action and ask them to enter the code again.
Checking a verification looks like this:
Let's start by adding some more private helper methods: one to authorise an API client with your Account Sid and Auth Token and return the Verify service using the Verify Service Sid, and one to use the Verify service to start the verification for the caller and one to check the result:
When the caller enters the verification code and presses the hash, Twilio will send the request to the verify
action. In the verify
action we gate the conference entrance with the verification check. If the check succeeds we enter the conference as before and if it fails we redirect back to the welcome
action and start again.
Make sure you are in the permitted callers list again and restart the application. Call it up and you will receive an SMS with a verification code. If you enter the code incorrectly you will be asked for it again. Enter the code correctly and you will be entered into the conference, safe in the knowledge that you are indeed who you said you were.
What's next after protecting a conference line with an OTP?
Over these blog posts you've seen how to build an open conference line in Rails, how to protect that conference line with a passcode and now how to protect it with a list of permitted callers and Twilio Verify. The code for the application, which has all 3 types of conference line, can be found on GitHub.
To go further, you could expand this application with a database and save different conferences with different lists of permitted callers and moderators.
Twilio Verify can be used to protect more than conference calls with an SMS verification code. Check out how you can:
- Expand your OTP channels with email
- Verify your users' phone numbers in your Rails web application
- Sanitize phone numbers before sending mass alerts
Any further questions? I'd be glad to help, just drop me a note on Twitter at @philnash or over email at philnash@twilio.com.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.