In this MessageBird Developer Tutorial you’ll learn how to improve your security building an SMS-based two factor authentication solution with the MessageBird Verify API. The runnable application we’ll build is a prototype in PHP for our fictitious online banking application, BirdBank.
Enterprises are increasingly challenged to keep sensitive information from falling into the wrong hands. This means that we can no longer trust old online authentication systems that rely solely on usernames and passwords, especially as security breaches grow in frequency, severity and sophistication.
With the MessageBird Verify API, you can implement two factor authentication (2FA) solutions to provide an additional layer of account security by verifying the user's password with a second authentication token and in turn, secure customer data, block fraudulent accounts, and safeguard key transactions in a matter of minutes. The most common use case involves the application of one-time passwords (OTP) generated by hardware tokens, authenticator apps or directly sent to the user's mobile phone via SMS messaging.
We'll walk you through the following steps:
Pro-tip: Follow this tutorial to build the whole application from scratch or, if you want to see it in action right away, you can download, clone or fork the sample application from our MessageBird Developer Tutorials GitHub repository.
First things first, we need to have PHP installed to run this sample 2FA application:
For Mac users, PHP will already be installed.
For Windows users, you can download PHP from windows.php.net.
For Linux users, please check your system's default package manager.
You also need Composer to install the MessageBird SDK for PHP and other dependencies, which is available at getcomposer.org.
Download the sample application by cloning the MessageBird Developer Tutorials GitHub repository or retrieving and extracting the ZIP file.
Next, let's open a console pointed at the directory into which you've stored the sample application and run the following command:
composer install
Apart from the MessageBird SDK, Composer will install the Slim framework, the Twig templating engine, and the Dotenv configuration library. We're using these libraries to add some structure to the project while keeping the sample easy to understand and without the overhead of a full-scale web framework.
The SDK is defined as a dependency in composer.json:
{"require" : {"messagebird/php-rest-api" : "^1.9.4"...}}
Composer autoloading makes the SDK available to the application and is initialized by creating an instance of the MessageBird\Client class. The constructor takes a single argument: an API key. For our Slim-based example, we add the SDK on the dependency injection container:
// Load and initialize MessageBird SDK$container['messagebird'] = function() {return new MessageBird\Client(getenv('MESSAGEBIRD_API_KEY'));};
Pro-tip: Hardcoding your credentials in the code is a risky practice that should never be used in production applications. A better method, also recommended by the Twelve-Factor App Definition, is to use environment variables. We've added dotenv to the sample application, so you can supply your API key in a file named .env, too.
So let's use getenv() to load the API key from the environment variable. To make the key available in the environment variable we need to initialize Dotenv and add the key to a .env file. You can copy the env.example file provided in the repository to .env and then add your API key like this:
MESSAGEBIRD_API_KEY=YOUR-API-KEY
API keys can be created or retrieved from the API access (REST) tab in the Developers section of your MessageBird Dashboard.
The first step in verifying a user's phone number is asking them to provide their phone number. In views/step1.html.twig you'll find a basic HTML form with a single input field and a button to submit the data using the POST method to /step2. Providing tel as the type attribute of our input field allows some browsers, especially on mobile devices, to optimize for telephone number input, for example by displaying a number pad.
The following route in index.php displays the form:
// Display page to ask the user for their phone number$app->get('/', function($request, $response) {return $this->view->render($response, 'step1.html.twig');});
Once we've collected the number, we can send a verification message to our user's mobile device. The MessageBird Verify API takes care of generating a random token, so you don't have to do this yourself. Codes are numeric and six digits by default; if you want to customize the length of the code or configure other options, you can check out our Verify API documentation.
The form we created in the last step submits the phone number to /step2, so let's define this route in our index.php:
// Handle phone number submission$app->post('/step2', function($request, $response) {// Create verify object$verify = new MessageBird\Objects\Verify;$verify->recipient = $request->getParsedBodyParam('number');$verify->originator = 'Code';$verify->template = "Your verification code is %token.";// Make request to Verify APItry {$result = $this->messagebird->verify->create($verify);} catch (Exception $e) {// Request has failedreturn $this->view->render($response, 'step1.html.twig', ['error' => get_class($e).": ".$e->getMessage()]);}// Request was successful, return step2 formreturn $this->view->render($response, 'step2.html.twig', ['id' => $result->getId()]);});
Before we move on, let's quickly dive into what happens here: 🤔
First, we're creating a MessageBird\Objects\Verify object to encapsulate the parameters for our API request. We set the number from the form as the recipient attribute and specify a template for the message. The value for the template attribute contains the placeholder %token, which is replaced with the generated token on MessageBird's end. If we omitted this, the message would contain the token and nothing else.
Also, using originator we specify the sender ID of the text message with the code. The value should either be a valid telephone number international format with country code , or an alphanumeric string with at most 11 characters. If we omitted this, it would default to the string Code. Keep in mind that alphanumeric senders are not supported in every country including the United States, so it’s important to check the country restrictions.
The MessageBird SDK throws exceptions for any error. Therefore, the next section is contained in a try-catch block. Using $this->messagebird we access the previously initialized SDK object and then call the verify->create() method with the parameter object. If the API call fails for any reason, for example, because the user has entered an invalid phone number, the catch-block executes, and we render the form from the first step again but include the error message. In production applications, you'd most likely not expose the raw API error; instead, you could consider different possible problems and return an appropriate message in your own words. You might also want to prevent some errors from happening by doing some input validation on the phone number yourself.
In case the request was successful, code execution continues after the catch-block, and we'll render a new page. Our API response contains an ID, which we'll need for the next step, so we'll add it to the form. Since the ID is meaningless without your API access key, there are no security implications of doing so; however, in practice you'd be more likely to store this ID in a session object on the server. You can see the form in the file views/step2.html.twig, it actually looks similar to the previous form but includes a hidden field with our verification ID.
Once the code is delivered, our user will check their phone, enter their verification code and submit the form. We now need to send the user's input along with the ID of the verification request to MessageBird's API and see whether the verification was successful or not. Let's declare this third step as a new route in our index.php:
// Verify whether the token is correct$app->post('/step3', function($request, $response) {$id = $request->getParsedBodyParam('id');$token = $request->getParsedBodyParam('token');// Make request to Verify APItry {$this->messagebird->verify->verify($id, $token);} catch (Exception $e) {// Request has failedreturn $this->view->render($response, 'step2.html.twig', ['id' => $id,'error' => get_class($e).": ".$e->getMessage()]);}// Request was successfulreturn $this->view->render($response, 'step3.html.twig');});
In this step, we retrieve the id and token inputs from the form. The verify->verify() method accepts these two parameters, so we don’t need to create an object first but pass them directly. As before, there's a catch-block to handle errors such as an invalid token entered by the user. In this case, we show the same form again with the error.
If verification was successful, we render a simple confirmation page. The template views/step3.html.twig only contains a static message.
You’re done! To test the application with PHP's built-in web server, enter the following command on the console to start:
php -S 0.0.0.0:8080 index.php
Then, point your browser to http://localhost:8080/ and try to verify your own phone number.
Awesome! You can now leverage the flow, code snippets and UI examples from this tutorial to build your own two factor authentication system. Don't forget to download the code from the MessageBird Developer Tutorials GitHub repository.
Nice work! 🎉
You now have a running integration of MessageBird's Verify API using PHP!
Want to build something similar but not quite sure how to get started? Please feel free to let us know at support@messagebird.com, we'd love to help!