Providing One Time Passwords via Voice Calls with Twilio and Laravel
Time to read: 8 minutes
One time passwords (OTP’s) provide an extra security layer for applications, and in this tutorial we will set up a system to provide one time passwords to users via voice calls powered by Twilio’s amazing programmable voice SDK and Laravel.
After you’re finished you will have developed an OTP system that can serve as an extra security layer for various actions in your application. The OTP could be used for authentication, purchase actions or whatever actions you consider worthy of an extra layer of authorisation in your application.
Requirements
For this tutorial, we’ll assume the following:
- You are familiar with the terminal (command line)
- You have Composer globally installed
- You are familiar with PHP and Laravel and have PHP 7.3.2+ installed
- You can create a Laravel project.
- You either have MySQL locally installed, or are able to use docker and docker-compose (see the “Database Considerations” section below for more on this)
Create a Laravel Project
First off we will be creating a new Laravel project.
Once the Laravel application is created, enter into the project directory and let the fun begin.
Database Considerations
Our application is going to need a database to store the OTP’s and handle whatever persistent data needs we might have. However, setting up the database and connecting it to our Laravel app is outside the scope of this tutorial, Laravel’s documentation provides instructions on how to connect to a database from a Laravel application. Ensure that you have your local database setup and connected to the app before we go on. If you’re interested in using Docker, follow the next steps, otherwise skip to “Twilio Account Setup”.
NOTE: If you prefer using Docker, you can copy the Dockerfiles (app.docker
and web.docker
) and the docker-compose setup found in the accompanying repository for this tutorial. Note that you also have to copy the vhost.conf
file into your project directory as its configuration for the nginx server spun up by the docker-compose stack.
To start up the docker-compose stack run the following command:
This command sets up everything needed to run the application and exposes the app at Localhost:1000.
Twilio Account Setup
Now that you have your Laravel application created and have connected it to your local database, you need to set up a Twilio account so you can use the Twilio Programmable Voice SDK as needed. Follow through the following steps to setup your Twilio account and begin using the Programmable Voice SDK.
- Create an account with Twilio
- Verify your phone number as requested by Twilio. You need to link a Twilio verified phone number to your account so that you can use it in testing Twilio’s various product offerings, including receiving the phone calls made in this tutorial.
- Set up a Twilio phone number that can handle Voice. This is a different phone number from the one we verified in step 2 above. Twilio phone numbers are set up to handle various tasks like making phone calls, sending SMS messages, etc., whereas the verified phone number was set up so it could receive phone calls and messages.
NOTE: Once you upgrade your Twilio account you can make calls and send messages to other phone numbers including the verified phone number.
To set up a Voice enabled Twilio phone number, go to your console, and click on the “Get a Trial Number” button.
If you followed the default prompts, you should now have a USA Twilio phone number capable of making voice calls to your verified account phone number. Next up we’ll take a look at Twilio’s programmable voice SDK and how we can use it in Laravel.
Account Credentials
Before we begin writing code, there are some environment variables we require from our Twilio account console to authorize programmatic use of Twilio’s services from our application:
1. Account SID
2. Auth Token
3. Trial Number
4. Authorised Phone Number (The phone number you authorized during account creation)
Create the environment variables below in your .env
file, and ensure to replace the placeholder values with your actual account values. We will use these later to authorize the Programmable Voice SDK to make phone calls from our application.
Twilio’s Programmable Voice SDK
Now that we have our Laravel app and Twilio voice phone number setup, we need to link them up so our Laravel application is able to make phone calls using Twilio, enter Twilio’s Programmable Voice SDK.
Twilio Programmable Voice allows you to make and receive phone calls in your application, alongside some other cool features like creating conference calls and transcribing call recordings. For this tutorial we only need to make phone calls from our Laravel application. Twilio has an amazing PHP SDK which we will use to drastically simplify the process of making phone calls from our application.
To get started, we'll install the Twilio PHP helper library. From your terminal, run the following command in your project directory:
Create The View That Requests an OTP
Next we will create a simple view page with a button which requests a one time password from the system. Create a blade file called create.blade.php
in resources/views/otp
and copy the following code snippet:
The create.blade.php
view simply displays a button requesting for an OTP from the system. The 'otp.store' route which it posts to will be implemented shortly.
Generate the OTPController
Now that we have created the view that requests our OTP codes, let's begin to flesh out the services, controllers and routes that handle OTP generation.
Run the command below to create the resourceful OTPController which will control several actions to be implemented.
Next, we add the resourceful route to routes/web.php
NOTE: The Laravel documentation explains resourceful routes and controllers in detail.
After creating resourceful routes and an OTPController, we need to make some changes to the OTPController. Replace the contents of your OTPController with the code below:
As you can see, we've updated OTPController@create to display the create OTP page to the user, and the following methods were added to the OTPController:
- 1. **generateVoiceMessage**
Twilio requires that we provide a url where it can get the TwiML that describes the call to be made. This function generates the TwiML response which includes the OTP code. - 2. **validateOTP**
This function handles a POST request to validate an OTP that a user provides and redirects to the user to an appropriate page providing feedback depending on whether the OTP validation was successful or not.
We also need to add a generateVoiceMessage()
function to the OTP controller. This method takes in the $otpCode
and generates the TwiML code that defines the call which the user will receive.
NOTE: TwiML (the Twilio Markup Language) is a set of instructions you can use to tell Twilio what to do when you receive or make a call, SMS, or fax.
Update Routes
Ensure that routes/web.php
has the following routes which power our application.
After updating our routes, we need to remove CSRF protection from the **generateMessage** route so that an external party (Twilio) can POST to that endpoint. Update the $except property in app/Http/Middleware/VerifyCsrfToken.php
to the following.
### Create OTP Model and Database Migrations
In order for us to create OTP’s in the database, we will create a model and migrations for our OTP’s. Run the following commands to create the model and migrations:
Replace the up()
method of the newly created migration with the following code:
Next, run the migrate command:
Add the fillable properties on the OTP model, and add the table name also.
Create OTPService for Creating and Validating OTPs
Next we create an OTP service that is used for the creation and validation of OTP codes. Create a file app/Services/OTPService.php
and paste the following code snippet:
The OTPService handles creating the new OTP in the database, and also validating an OTP.
Creating the Twilio Service for Voice Calls
We now need a service that our application uses to make the voice calls via the Twilio PHP helper library. Create app/Services/TwilioService.php
and paste the following code into it.
As seen above, we create an instance of the Twilio Rest Client when our service class is instantiated. This rest client instance uses the account SID and auth token we stored in our .env file to authorize the Twilio library to carry out actions on behalf of your Twilio account.
The makeOtpVoiceCall
function does exactly what the name signifies. It makes a call to a provided phone number with a predefined message which will include the OTP code.
The generateTwiMLForVoiceCall
function generates the TwiML XML that describes the call which will be placed to the user.
NOTE: If you're using a Twilio trial account, you can only make outgoing calls to phone numbers you have verified with Twilio. Phone numbers can be verified with your Twilio Console’s Verified Caller IDs.
Storing OTP’s and Making the Phone Call
Now that we have created the OTPService, and the TwilioService, update the store method in the app/Http/Controllers/OTPController.php
to create an OTP and make a call to the user once an OTP is created:
The store method above carries out the following actions:
- Creates and stores an OTP using the OTPService
- Places a call to the user with the OTP using the TwilioService
- Upon success of the call, redirect to an OTP validation page, passing in the call ID of the call made to the user providing the OTP.
Creating the OTP Validation View
After creating the OTP and making the call to the user in the previous step, we redirected to an OTP validation view. Let’s create this view page now. Create validate.blade.php
in resources/views/otp
, and paste the following code snippet into it:
This page displays a form that asks the user to validate an OTP, and posts our OTP validation route upon validation.
Expose our Application Online using Ngrok
Remember when we said Twilio needs to query a url for the TwiML that describes the call to be made?
Well we are about to test our application but there's just one problem, our application is deployed locally. This works for viewing pages and carrying out actions from our system, but Twilio also needs to access the generateMessage
route we defined over the Internet.
There are a number of services which facilitate exposing your localhost to the Internet, but one that we use in this tutorial is ngrok. ngrok is a free tool that lets you put the web app running on your local machine on the Internet.
Follow the official ngrok documentation to download and setup ngrok on your system.
Next, expose your application to the Internet by running the following command (replace 1000 with whatever port your app is running on).
After running the ngrok command, you get an ngrok URL which your local app is now accessible via the Internet. Replace the APP_URL in your .env
file with the ngrok URL.
Testing the Application
If you've been able to get this far in the tutorial congratulations, we are done with the coding and what remains is to enjoy your wonderful new OTP system.
Navigate to the OTP creation route i.e otp/create
to see the OTP request page
You can now request for an OTP, get a call and validate the OTP. Congratulations.
Conclusion
Because this is a tutorial focusing on Twilio Voice and Laravel, some implementation and security considerations were intentionally overlooked to reduce the scope of the tutorial.
Things like OTP invalidation after a certain duration, deactivation of the OTP upon validation, linking of OTP's to the user who created them e.t.c were not included, so if you're building a production-ready system, take care to implement these features.
There you have it, a way to protect important actions in your application with one time passwords that you provide to users via voice calls. Enjoy!
- Twitter: @omadoyeabraham
- Github: omadoyeabraham
- Email: omadoyeabraham@gmail.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.