Twilio Verify Phone Verification PHP Quickstart

Phone Verification is an important, high-confidence step in your registration flow to verify that a user has the device they claim to have. Adding phone verification to your application will greatly reduce your number of fraudulent registrations and protect future application users from having their numbers registered by scammers.

This quickstart guides you through creating a PHP, Laravel and AngularJS app that requires a phone verification step with Twilio Verify to create an account. Two channels of Phone Verification are demoed: SMS and Voice.

Ready to add Phone Verification to a demo app and keep the bad actors away? Enter stage left!

Sign into - or create- a Twilio account

Either sign up for a free Twilio trial, or sign into an existing Twilio account.

Create a New Account Security Application

Once logged in, visit the Account Security Console. Click on the big red plus ('+') to create a new Account Security application then name it something memorable.

Twilio will redirect you to the Settings page next:

Account Security API Key

Click the eyeball to reveal your Production API Key and copy it somewhere safe. You will use the API Key during the application setup step below.

Install the application prerequisites

To complete the quickstart today we'll use PHP 7.0+, Composer, MySQL, and the Twilio PHP Helper Library. Let's walk through each one now - but feel free to skip if you have already installed one.

Install Composer

When doing web development in PHP, we strongly suggest using Composer for package management. This quickstart relies on Composer to install the PHP Helper library. You can find manual Twilio PHP installation instructions on the PHP Helper Library page.

Install MySQL

While Twilio's Verify API doesn't return user information you'll need to store, to continue working on the app after this Quickstart you'll want a database. For this demo, we built our user database on top of MySQL 5.x.

If you haven't yet installed it, here are instructions for your platform:

When installed, start MySQL. If you're using the default MySQL credentials (as below), create a schema account_security with user homestead and password secret.

Install the quickstart application

Clone our PHP repository locally, then enter the directory:

git clone git@github.com:TwilioDevEd/account-security-quickstart-php.git
cd account-security-quickstart-php
composer install

Edit the dotenv file

cp .env.example .env

Next, copy your Authy API Key from the Authy Dashboard and set the API_KEY variable in your .env file.

Install PHP, Composer, Laravel and MySQL.

Loading Code Samples...
Language
# Get your API key here: https://www.twilio.com/console/authy/getting-started
API_KEY=your-authy-api-key

APP_DEBUG=true
APP_ENV=development
APP_KEY=
APP_LOG=errorlog
DB_DATABASE=account_security
DB_HOST=database
DB_PASSWORD=secret
DB_PORT=3306
DB_USERNAME=homestead
MYSQL_DATABASE=account_security
MYSQL_PASSWORD=secret
MYSQL_PORT=3306
MYSQL_ROOT_PASSWORD=secret
MYSQL_USER=homestead
SECRET=your-account-secret
Enter the API Key from the Account Security console and optionally change the port.
Enter an Application API Key

Enter the API Key from the Account Security console and optionally change the port.

Migrate and launch the PHP Verify quickstart

Now, launch the application with:

php artisan key:generate
php artisan migrate
php artisan serve --port 8081

Assuming your API Key is correctly entered and the command above executed correctly, you'll soon get a message that the app is up!

Use the PHP Phone Verification Demo

Keeping your phone at your side, vist the Phone Verification page of the demo at http://localhost:8081/verify/

Enter a Country Code and Phone Number, then choose which channel to request verification over, 'SMS' or 'CALL' (Voice). Finally, hit the blue 'Request Verification' button and wait.

Phone Verification by SMS or VoiceYou won't be waiting long - you'll either receive a phone call or an SMS with the verification token. If you requested a phone call, as an additional security feature you may need to interact to proceed (by entering a number on the phone keypad).

Loading Code Samples...
Language
<?php

namespace App\Http\Controllers\Auth;

use \Exception;
use App\Http\Controllers\Controller;
use Authy\AuthyApi;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class PhoneVerificationController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Phone Verification  Controller
    |--------------------------------------------------------------------------
    |
    | Uses Authy to verify a users phone via voice or sms.
    |
    */

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Get a validator for an incoming verification request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function verificationRequestValidator(array $data)
    {
        return Validator::make($data, [
            'country_code' => 'required|string|max:3',
            'phone_number' => 'required|string|max:10',
            'via' => 'required|string|max:4',
        ]);
    }

    /**
     * Get a validator for an code verification request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function verificationCodeValidator(array $data)
    {
        return Validator::make($data, [
            'country_code' => 'required|string|max:3',
            'phone_number' => 'required|string|max:10',
            'token' => 'required|string|max:4'
        ]);
    }

    /**
     * Request phone verification via PhoneVerificationService.
     *
     * @param  array  $data
     * @return Illuminate\Support\Facades\Response;
     */
    protected function startVerification(
        Request $request,
        AuthyApi $authyApi
    ) {
        $data = $request->all();
        $validator = $this->verificationRequestValidator($data);
        extract($data);

        if ($validator->passes()) {
            return $authyApi->phoneVerificationStart($phone_number, $country_code, $via);
        }

        return response()->json(['errors'=>$validator->errors()], 403);
    }

    /**
     * Request phone verification via PhoneVerificationService.
     *
     * @param  array  $data
     * @return Illuminate\Support\Facades\Response;
     */
    protected function verifyCode(
        Request $request,
        AuthyApi $authyApi
    ) {
        $data = $request->all();
        $validator = $this->verificationCodeValidator($data);
        extract($data);

        if ($validator->passes()) {
            try {
                $result = $authyApi->phoneVerificationCheck($phone_number, $country_code, $token);
                return response()->json($result, 200);
            } catch (Exception $e) {
                $response=[];
                $response['exception'] = get_class($e);
                $response['message'] = $e->getMessage();
                $response['trace'] = $e->getTrace();
                return response()->json($response, 403);
            }
        }

        return response()->json(['errors'=>$validator->errors()], 403);
    }
}
Send a Phone Verification via SMS or Voice

Either way you requested the passcode, enter the token into the Verification entry form and click 'Verify Phone':

Phone Verification Entry Box

Loading Code Samples...
Language
<?php

namespace App\Http\Controllers\Auth;

use \Exception;
use App\Http\Controllers\Controller;
use Authy\AuthyApi;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class PhoneVerificationController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Phone Verification  Controller
    |--------------------------------------------------------------------------
    |
    | Uses Authy to verify a users phone via voice or sms.
    |
    */

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Get a validator for an incoming verification request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function verificationRequestValidator(array $data)
    {
        return Validator::make($data, [
            'country_code' => 'required|string|max:3',
            'phone_number' => 'required|string|max:10',
            'via' => 'required|string|max:4',
        ]);
    }

    /**
     * Get a validator for an code verification request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function verificationCodeValidator(array $data)
    {
        return Validator::make($data, [
            'country_code' => 'required|string|max:3',
            'phone_number' => 'required|string|max:10',
            'token' => 'required|string|max:4'
        ]);
    }

    /**
     * Request phone verification via PhoneVerificationService.
     *
     * @param  array  $data
     * @return Illuminate\Support\Facades\Response;
     */
    protected function startVerification(
        Request $request,
        AuthyApi $authyApi
    ) {
        $data = $request->all();
        $validator = $this->verificationRequestValidator($data);
        extract($data);

        if ($validator->passes()) {
            return $authyApi->phoneVerificationStart($phone_number, $country_code, $via);
        }

        return response()->json(['errors'=>$validator->errors()], 403);
    }

    /**
     * Request phone verification via PhoneVerificationService.
     *
     * @param  array  $data
     * @return Illuminate\Support\Facades\Response;
     */
    protected function verifyCode(
        Request $request,
        AuthyApi $authyApi
    ) {
        $data = $request->all();
        $validator = $this->verificationCodeValidator($data);
        extract($data);

        if ($validator->passes()) {
            try {
                $result = $authyApi->phoneVerificationCheck($phone_number, $country_code, $token);
                return response()->json($result, 200);
            } catch (Exception $e) {
                $response=[];
                $response['exception'] = get_class($e);
                $response['message'] = $e->getMessage();
                $response['trace'] = $e->getTrace();
                return response()->json($response, 403);
            }
        }

        return response()->json(['errors'=>$validator->errors()], 403);
    }
}
This function verifies the token for a user delivered over the Voice or SMS channel.
Verify a Token

This function verifies the token for a user delivered over the Voice or SMS channel.

And with that, your demo app is protected with Twilio's Verify phone verification! You can now log out to try the other channel.

What's Next?

Your demo app is now keeping hordes of fraudulent users from registering with your business and polluting the database. Next, you should check out all of the variables and options available to you in the Verify API Reference. Also, for protecting your customers in an ongoing manner (with this same codebase) try the PHP Authy Two-Factor Authentication Quickstart.

After that, take a stroll through the Docs for more Account Security demos and tutorials - as well as sample web applications using all of Twilio's products. Encore!

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

Loading Code Samples...
# Get your API key here: https://www.twilio.com/console/authy/getting-started
API_KEY=your-authy-api-key

APP_DEBUG=true
APP_ENV=development
APP_KEY=
APP_LOG=errorlog
DB_DATABASE=account_security
DB_HOST=database
DB_PASSWORD=secret
DB_PORT=3306
DB_USERNAME=homestead
MYSQL_DATABASE=account_security
MYSQL_PASSWORD=secret
MYSQL_PORT=3306
MYSQL_ROOT_PASSWORD=secret
MYSQL_USER=homestead
SECRET=your-account-secret
<?php

namespace App\Http\Controllers\Auth;

use \Exception;
use App\Http\Controllers\Controller;
use Authy\AuthyApi;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class PhoneVerificationController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Phone Verification  Controller
    |--------------------------------------------------------------------------
    |
    | Uses Authy to verify a users phone via voice or sms.
    |
    */

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Get a validator for an incoming verification request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function verificationRequestValidator(array $data)
    {
        return Validator::make($data, [
            'country_code' => 'required|string|max:3',
            'phone_number' => 'required|string|max:10',
            'via' => 'required|string|max:4',
        ]);
    }

    /**
     * Get a validator for an code verification request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function verificationCodeValidator(array $data)
    {
        return Validator::make($data, [
            'country_code' => 'required|string|max:3',
            'phone_number' => 'required|string|max:10',
            'token' => 'required|string|max:4'
        ]);
    }

    /**
     * Request phone verification via PhoneVerificationService.
     *
     * @param  array  $data
     * @return Illuminate\Support\Facades\Response;
     */
    protected function startVerification(
        Request $request,
        AuthyApi $authyApi
    ) {
        $data = $request->all();
        $validator = $this->verificationRequestValidator($data);
        extract($data);

        if ($validator->passes()) {
            return $authyApi->phoneVerificationStart($phone_number, $country_code, $via);
        }

        return response()->json(['errors'=>$validator->errors()], 403);
    }

    /**
     * Request phone verification via PhoneVerificationService.
     *
     * @param  array  $data
     * @return Illuminate\Support\Facades\Response;
     */
    protected function verifyCode(
        Request $request,
        AuthyApi $authyApi
    ) {
        $data = $request->all();
        $validator = $this->verificationCodeValidator($data);
        extract($data);

        if ($validator->passes()) {
            try {
                $result = $authyApi->phoneVerificationCheck($phone_number, $country_code, $token);
                return response()->json($result, 200);
            } catch (Exception $e) {
                $response=[];
                $response['exception'] = get_class($e);
                $response['message'] = $e->getMessage();
                $response['trace'] = $e->getTrace();
                return response()->json($response, 403);
            }
        }

        return response()->json(['errors'=>$validator->errors()], 403);
    }
}
<?php

namespace App\Http\Controllers\Auth;

use \Exception;
use App\Http\Controllers\Controller;
use Authy\AuthyApi;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class PhoneVerificationController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Phone Verification  Controller
    |--------------------------------------------------------------------------
    |
    | Uses Authy to verify a users phone via voice or sms.
    |
    */

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Get a validator for an incoming verification request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function verificationRequestValidator(array $data)
    {
        return Validator::make($data, [
            'country_code' => 'required|string|max:3',
            'phone_number' => 'required|string|max:10',
            'via' => 'required|string|max:4',
        ]);
    }

    /**
     * Get a validator for an code verification request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function verificationCodeValidator(array $data)
    {
        return Validator::make($data, [
            'country_code' => 'required|string|max:3',
            'phone_number' => 'required|string|max:10',
            'token' => 'required|string|max:4'
        ]);
    }

    /**
     * Request phone verification via PhoneVerificationService.
     *
     * @param  array  $data
     * @return Illuminate\Support\Facades\Response;
     */
    protected function startVerification(
        Request $request,
        AuthyApi $authyApi
    ) {
        $data = $request->all();
        $validator = $this->verificationRequestValidator($data);
        extract($data);

        if ($validator->passes()) {
            return $authyApi->phoneVerificationStart($phone_number, $country_code, $via);
        }

        return response()->json(['errors'=>$validator->errors()], 403);
    }

    /**
     * Request phone verification via PhoneVerificationService.
     *
     * @param  array  $data
     * @return Illuminate\Support\Facades\Response;
     */
    protected function verifyCode(
        Request $request,
        AuthyApi $authyApi
    ) {
        $data = $request->all();
        $validator = $this->verificationCodeValidator($data);
        extract($data);

        if ($validator->passes()) {
            try {
                $result = $authyApi->phoneVerificationCheck($phone_number, $country_code, $token);
                return response()->json($result, 200);
            } catch (Exception $e) {
                $response=[];
                $response['exception'] = get_class($e);
                $response['message'] = $e->getMessage();
                $response['trace'] = $e->getTrace();
                return response()->json($response, 403);
            }
        }

        return response()->json(['errors'=>$validator->errors()], 403);
    }
}