Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

Account Verification with Authy, PHP and Laravel


(warning)

Warning

As of November 2022, Twilio no longer provides support for Authy SMS/Voice-only customers. Customers who were also using Authy TOTP or Push prior to March 1, 2023 are still supported. The Authy API is now closed to new customers and will be fully deprecated in the future.

For new development, we encourage you to use the Verify v2 API.

Existing customers will not be impacted at this time until Authy API has reached End of Life. For more information about migration, see Migrating from Authy to Verify for SMS(link takes you to an external page).

Ready to implement user account verification in your application? Here's how it works at a high level:

  1. The users begin the registration process by entering their data, including a phone number, into a signup form.
  2. The authentication system sends a one-time password to the user's mobile phone to verify the possession of that phone number.
  3. The user enters the one-time password into a form before completing registration.
  4. The user opens a success page and receives an SMS indicating that their account has been created!

Building Blocks

building-blocks page anchor

To get this done, you'll be working with the following Twilio-powered APIs:

Authy REST API

  • Authy Docs : Find quick starts, documentation, and all about the helper libraries.

Twilio REST API

  • Messages Resource : We will use Twilio directly to send our user a confirmation message after they create an account.

All of this can be done in under a half an hour with the simplicity and power of Authy and Twilio. Let's get started!


The User Model for this use-case is pretty straight-forward, and Laravel offers us some tools to make it even simpler. If you have already read through the 2FA tutorial, this one probably looks very similar.

Migration to create user table

migration-to-create-user-table page anchor
database/migrations/2014_10_12_000000_create_users_table.php

_38
<?php
_38
_38
use Illuminate\Database\Schema\Blueprint;
_38
use Illuminate\Database\Migrations\Migration;
_38
_38
class CreateUsersTable extends Migration
_38
{
_38
/**
_38
* Run the migrations.
_38
*
_38
* @return void
_38
*/
_38
public function up()
_38
{
_38
Schema::create('users', function (Blueprint $table) {
_38
$table->increments('id');
_38
$table->string('name');
_38
$table->string('email')->unique();
_38
$table->string('password', 60);
_38
$table->string('phone_number');
_38
$table->string('country_code');
_38
$table->string('authy_id')->nullable();
_38
$table->boolean('verified')->default(false);
_38
$table->rememberToken();
_38
$table->timestamps();
_38
});
_38
}
_38
_38
/**
_38
* Reverse the migrations.
_38
*
_38
* @return void
_38
*/
_38
public function down()
_38
{
_38
Schema::drop('users');
_38
}
_38
}

Pretty simple user model, right? Next, we're going to visit the registration form on the client side.


When we create a new user, we ask for a name, email address, and a password. To validate their account, we also ask them for a mobile number with a country code. We use Authy to send a one-time password via SMS to this phone number.

It is now the controller's responsibility to verify that the user provides the necessary information to create a new user. If the user is created successfully, they will be logged into the system automatically.

app/Http/Controllers/UserController.php

_153
<?php
_153
namespace App\Http\Controllers;
_153
_153
use App\Http\Requests;
_153
use App\User;
_153
use Auth;
_153
use Authy\AuthyApi as AuthyApi;
_153
use DB;
_153
use Hash;
_153
use Illuminate\Contracts\Auth\Authenticatable;
_153
use Illuminate\Http\Request;
_153
use Illuminate\Support\MessageBag;
_153
use Twilio\Rest\Client;
_153
_153
class UserController extends Controller
_153
{
_153
/**
_153
* Store a new user
_153
*
_153
* @param \Illuminate\Http\Request $request
_153
* @return \Illuminate\Http\Response
_153
*/
_153
public function createNewUser(Request $request, AuthyApi $authyApi)
_153
{
_153
$this->validate(
_153
$request, [
_153
'name' => 'required|string',
_153
'email' => 'required|unique:users|email',
_153
'password' => 'required',
_153
'country_code' => 'required',
_153
'phone_number' => 'required|numeric'
_153
]
_153
);
_153
_153
$values = $request->all();
_153
$values['password'] = Hash::make($values['password']);
_153
_153
DB::beginTransaction();
_153
_153
$newUser = new User($values);
_153
$newUser->save();
_153
Auth::login($newUser);
_153
_153
$authyUser = $authyApi->registerUser(
_153
$newUser->email,
_153
$newUser->phone_number,
_153
$newUser->country_code
_153
);
_153
if ($authyUser->ok()) {
_153
$newUser->authy_id = $authyUser->id();
_153
$newUser->save();
_153
$request->session()->flash(
_153
'status',
_153
"User created successfully"
_153
);
_153
_153
$sms = $authyApi->requestSms($newUser->authy_id);
_153
DB::commit();
_153
return redirect()->route('user-show-verify');
_153
} else {
_153
$errors = $this->getAuthyErrors($authyUser->errors());
_153
DB::rollback();
_153
return view('newUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
/**
_153
* This controller function shows the current user status
_153
*
_153
* @param Authenticatable $user Current user
_153
* @return mixed Response view
_153
*/
_153
public function show(Authenticatable $user)
_153
{
_153
return view('showUser', ['user' => $user]);
_153
}
_153
_153
/**
_153
* This controller function handles the submission form
_153
*
_153
* @param Request $request Current User Request
_153
* @param Authenticatable $user Current User
_153
* @param AuthyApi $authyApi Authy Client
_153
* @return mixed Response view
_153
*/
_153
public function verify(Request $request, Authenticatable $user,
_153
AuthyApi $authyApi, Client $client)
_153
{
_153
$token = $request->input('token');
_153
$verification = $authyApi->verifyToken($user->authy_id, $token);
_153
_153
if ($verification->ok()) {
_153
$user->verified = true;
_153
$user->save();
_153
$this->sendSmsNotification($client, $user);
_153
_153
return redirect()->route('user-index');
_153
} else {
_153
$errors = $this->getAuthyErrors($verification->errors());
_153
return view('verifyUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
/**
_153
* This controller function handles the verification code resent
_153
*
_153
* @param Request $request Current User Request
_153
* @param Authenticatable $user Current User
_153
* @param AuthyApi $authyApi Authy Client
_153
* @return mixed Response view
_153
*/
_153
public function verifyResend(Request $request, Authenticatable $user,
_153
AuthyApi $authyApi)
_153
{
_153
$sms = $authyApi->requestSms($user->authy_id);
_153
_153
if ($sms->ok()) {
_153
$request->session()->flash(
_153
'status',
_153
'Verification code re-sent'
_153
);
_153
return redirect()->route('user-show-verify');
_153
} else {
_153
$errors = $this->getAuthyErrors($sms->errors());
_153
return view('verifyUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
private function getAuthyErrors($authyErrors)
_153
{
_153
$errors = [];
_153
foreach ($authyErrors as $field => $message) {
_153
array_push($errors, $field . ': ' . $message);
_153
}
_153
return $errors;
_153
}
_153
_153
private function sendSmsNotification($client, $user)
_153
{
_153
$twilioNumber = config('services.twilio')['number'] or die(
_153
"TWILIO_NUMBER is not set in the environment"
_153
);
_153
$messageBody = 'You did it! Signup complete :)';
_153
_153
$client->messages->create(
_153
$user->fullNumber(), // Phone number which receives the message
_153
[
_153
"from" => $twilioNumber, // From a Twilio number in your account
_153
"body" => $messageBody
_153
]
_153
);
_153
}
_153
}

Now the user is logged in but not verified. In the next step, we'll learn how to configure Authy to integrate with our application.


In .env.example(link takes you to an external page) we list configuration parameters for the application. These are pulled from system environment variables, which is a helpful way to access sensitive values (like API keys). Using environment variables prevents us from accidentally checking them into source control. We also use our Laravel configuration file to load the key and inject Authy\AuthyApi into the application using a service provider.

Now we need our Authy production key (sign up for Authy here(link takes you to an external page)). When you create an Authy application, the production key is found on the dashboard.

Authy dashboard.

Register the service provider for the Authy API

register-the-service-provider-for-the-authy-api page anchor
app/Providers/AuthyApiProvider.php

_25
<?php
_25
namespace App\Providers;
_25
_25
use Authy\AuthyApi as AuthyApi;
_25
use Illuminate\Support\ServiceProvider;
_25
_25
class AuthyApiProvider extends ServiceProvider
_25
{
_25
/**
_25
* Register the application services.
_25
*
_25
* @return void
_25
*/
_25
public function register()
_25
{
_25
$this->app->singleton(AuthyApi::class, function ($app) {
_25
$authyKey = getenv('AUTHY_API_KEY') or die(
_25
"You must specify your api key for Authy. " .
_25
"Visit https://dashboard.authy.com/"
_25
);
_25
_25
return new AuthyApi($authyKey);
_25
});
_25
}
_25
}

Now that we've learned how to configure Authy, we need to jump over to the UserController to configure the Authy client and create an instance method to send a one-time password.


Sending a Token on Account Creation

sending-a-token-on-account-creation page anchor

Once the user has an authy_id we can actually send a verification code to that user's mobile phone.

When our user is created successfully via the form we implemented, we send a token to the user's mobile phone to verify their account in our controller. Once the code is sent, we redirect to another page where the user can enter the token they received, completing the verification process.

Send verification token via SMS on user creation

send-verification-token-via-sms-on-user-creation page anchor
app/Http/Controllers/UserController.php

_153
<?php
_153
namespace App\Http\Controllers;
_153
_153
use App\Http\Requests;
_153
use App\User;
_153
use Auth;
_153
use Authy\AuthyApi as AuthyApi;
_153
use DB;
_153
use Hash;
_153
use Illuminate\Contracts\Auth\Authenticatable;
_153
use Illuminate\Http\Request;
_153
use Illuminate\Support\MessageBag;
_153
use Twilio\Rest\Client;
_153
_153
class UserController extends Controller
_153
{
_153
/**
_153
* Store a new user
_153
*
_153
* @param \Illuminate\Http\Request $request
_153
* @return \Illuminate\Http\Response
_153
*/
_153
public function createNewUser(Request $request, AuthyApi $authyApi)
_153
{
_153
$this->validate(
_153
$request, [
_153
'name' => 'required|string',
_153
'email' => 'required|unique:users|email',
_153
'password' => 'required',
_153
'country_code' => 'required',
_153
'phone_number' => 'required|numeric'
_153
]
_153
);
_153
_153
$values = $request->all();
_153
$values['password'] = Hash::make($values['password']);
_153
_153
DB::beginTransaction();
_153
_153
$newUser = new User($values);
_153
$newUser->save();
_153
Auth::login($newUser);
_153
_153
$authyUser = $authyApi->registerUser(
_153
$newUser->email,
_153
$newUser->phone_number,
_153
$newUser->country_code
_153
);
_153
if ($authyUser->ok()) {
_153
$newUser->authy_id = $authyUser->id();
_153
$newUser->save();
_153
$request->session()->flash(
_153
'status',
_153
"User created successfully"
_153
);
_153
_153
$sms = $authyApi->requestSms($newUser->authy_id);
_153
DB::commit();
_153
return redirect()->route('user-show-verify');
_153
} else {
_153
$errors = $this->getAuthyErrors($authyUser->errors());
_153
DB::rollback();
_153
return view('newUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
/**
_153
* This controller function shows the current user status
_153
*
_153
* @param Authenticatable $user Current user
_153
* @return mixed Response view
_153
*/
_153
public function show(Authenticatable $user)
_153
{
_153
return view('showUser', ['user' => $user]);
_153
}
_153
_153
/**
_153
* This controller function handles the submission form
_153
*
_153
* @param Request $request Current User Request
_153
* @param Authenticatable $user Current User
_153
* @param AuthyApi $authyApi Authy Client
_153
* @return mixed Response view
_153
*/
_153
public function verify(Request $request, Authenticatable $user,
_153
AuthyApi $authyApi, Client $client)
_153
{
_153
$token = $request->input('token');
_153
$verification = $authyApi->verifyToken($user->authy_id, $token);
_153
_153
if ($verification->ok()) {
_153
$user->verified = true;
_153
$user->save();
_153
$this->sendSmsNotification($client, $user);
_153
_153
return redirect()->route('user-index');
_153
} else {
_153
$errors = $this->getAuthyErrors($verification->errors());
_153
return view('verifyUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
/**
_153
* This controller function handles the verification code resent
_153
*
_153
* @param Request $request Current User Request
_153
* @param Authenticatable $user Current User
_153
* @param AuthyApi $authyApi Authy Client
_153
* @return mixed Response view
_153
*/
_153
public function verifyResend(Request $request, Authenticatable $user,
_153
AuthyApi $authyApi)
_153
{
_153
$sms = $authyApi->requestSms($user->authy_id);
_153
_153
if ($sms->ok()) {
_153
$request->session()->flash(
_153
'status',
_153
'Verification code re-sent'
_153
);
_153
return redirect()->route('user-show-verify');
_153
} else {
_153
$errors = $this->getAuthyErrors($sms->errors());
_153
return view('verifyUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
private function getAuthyErrors($authyErrors)
_153
{
_153
$errors = [];
_153
foreach ($authyErrors as $field => $message) {
_153
array_push($errors, $field . ': ' . $message);
_153
}
_153
return $errors;
_153
}
_153
_153
private function sendSmsNotification($client, $user)
_153
{
_153
$twilioNumber = config('services.twilio')['number'] or die(
_153
"TWILIO_NUMBER is not set in the environment"
_153
);
_153
$messageBody = 'You did it! Signup complete :)';
_153
_153
$client->messages->create(
_153
$user->fullNumber(), // Phone number which receives the message
_153
[
_153
"from" => $twilioNumber, // From a Twilio number in your account
_153
"body" => $messageBody
_153
]
_153
);
_153
}
_153
}

Next, we'll take a look at verifying the code the user provides us.


This controller function handles the submission form. It needs to:

  • Get the current user.
  • Verify the code that was entered by the user.
  • If the code entered was valid, flip a boolean flag on the user model to indicate the account was verified.

The Authy PHP client(link takes you to an external page) provides us with a verifyToken() method that allows us to pass a user id and a token. In this case, we just need to check that the API request was successful and if so, set $user->verified to true.

Verify a user-submitted token

verify-a-user-submitted-token page anchor
app/Http/Controllers/UserController.php

_153
<?php
_153
namespace App\Http\Controllers;
_153
_153
use App\Http\Requests;
_153
use App\User;
_153
use Auth;
_153
use Authy\AuthyApi as AuthyApi;
_153
use DB;
_153
use Hash;
_153
use Illuminate\Contracts\Auth\Authenticatable;
_153
use Illuminate\Http\Request;
_153
use Illuminate\Support\MessageBag;
_153
use Twilio\Rest\Client;
_153
_153
class UserController extends Controller
_153
{
_153
/**
_153
* Store a new user
_153
*
_153
* @param \Illuminate\Http\Request $request
_153
* @return \Illuminate\Http\Response
_153
*/
_153
public function createNewUser(Request $request, AuthyApi $authyApi)
_153
{
_153
$this->validate(
_153
$request, [
_153
'name' => 'required|string',
_153
'email' => 'required|unique:users|email',
_153
'password' => 'required',
_153
'country_code' => 'required',
_153
'phone_number' => 'required|numeric'
_153
]
_153
);
_153
_153
$values = $request->all();
_153
$values['password'] = Hash::make($values['password']);
_153
_153
DB::beginTransaction();
_153
_153
$newUser = new User($values);
_153
$newUser->save();
_153
Auth::login($newUser);
_153
_153
$authyUser = $authyApi->registerUser(
_153
$newUser->email,
_153
$newUser->phone_number,
_153
$newUser->country_code
_153
);
_153
if ($authyUser->ok()) {
_153
$newUser->authy_id = $authyUser->id();
_153
$newUser->save();
_153
$request->session()->flash(
_153
'status',
_153
"User created successfully"
_153
);
_153
_153
$sms = $authyApi->requestSms($newUser->authy_id);
_153
DB::commit();
_153
return redirect()->route('user-show-verify');
_153
} else {
_153
$errors = $this->getAuthyErrors($authyUser->errors());
_153
DB::rollback();
_153
return view('newUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
/**
_153
* This controller function shows the current user status
_153
*
_153
* @param Authenticatable $user Current user
_153
* @return mixed Response view
_153
*/
_153
public function show(Authenticatable $user)
_153
{
_153
return view('showUser', ['user' => $user]);
_153
}
_153
_153
/**
_153
* This controller function handles the submission form
_153
*
_153
* @param Request $request Current User Request
_153
* @param Authenticatable $user Current User
_153
* @param AuthyApi $authyApi Authy Client
_153
* @return mixed Response view
_153
*/
_153
public function verify(Request $request, Authenticatable $user,
_153
AuthyApi $authyApi, Client $client)
_153
{
_153
$token = $request->input('token');
_153
$verification = $authyApi->verifyToken($user->authy_id, $token);
_153
_153
if ($verification->ok()) {
_153
$user->verified = true;
_153
$user->save();
_153
$this->sendSmsNotification($client, $user);
_153
_153
return redirect()->route('user-index');
_153
} else {
_153
$errors = $this->getAuthyErrors($verification->errors());
_153
return view('verifyUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
/**
_153
* This controller function handles the verification code resent
_153
*
_153
* @param Request $request Current User Request
_153
* @param Authenticatable $user Current User
_153
* @param AuthyApi $authyApi Authy Client
_153
* @return mixed Response view
_153
*/
_153
public function verifyResend(Request $request, Authenticatable $user,
_153
AuthyApi $authyApi)
_153
{
_153
$sms = $authyApi->requestSms($user->authy_id);
_153
_153
if ($sms->ok()) {
_153
$request->session()->flash(
_153
'status',
_153
'Verification code re-sent'
_153
);
_153
return redirect()->route('user-show-verify');
_153
} else {
_153
$errors = $this->getAuthyErrors($sms->errors());
_153
return view('verifyUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
private function getAuthyErrors($authyErrors)
_153
{
_153
$errors = [];
_153
foreach ($authyErrors as $field => $message) {
_153
array_push($errors, $field . ': ' . $message);
_153
}
_153
return $errors;
_153
}
_153
_153
private function sendSmsNotification($client, $user)
_153
{
_153
$twilioNumber = config('services.twilio')['number'] or die(
_153
"TWILIO_NUMBER is not set in the environment"
_153
);
_153
$messageBody = 'You did it! Signup complete :)';
_153
_153
$client->messages->create(
_153
$user->fullNumber(), // Phone number which receives the message
_153
[
_153
"from" => $twilioNumber, // From a Twilio number in your account
_153
"body" => $messageBody
_153
]
_153
);
_153
}
_153
}

That's all for token verification! However, our verification form wouldn't be very usable if there wasn't a way to resend a verification code if the message didn't arrive at the end user's handset.


Since the form for re-sending the code(link takes you to an external page) is one line, we're going to skip that for this tutorial. Let's just look at the controller function.

Re-send a verification code when initial SMS fails

re-send-a-verification-code-when-initial-sms-fails page anchor
app/Http/Controllers/UserController.php

_153
<?php
_153
namespace App\Http\Controllers;
_153
_153
use App\Http\Requests;
_153
use App\User;
_153
use Auth;
_153
use Authy\AuthyApi as AuthyApi;
_153
use DB;
_153
use Hash;
_153
use Illuminate\Contracts\Auth\Authenticatable;
_153
use Illuminate\Http\Request;
_153
use Illuminate\Support\MessageBag;
_153
use Twilio\Rest\Client;
_153
_153
class UserController extends Controller
_153
{
_153
/**
_153
* Store a new user
_153
*
_153
* @param \Illuminate\Http\Request $request
_153
* @return \Illuminate\Http\Response
_153
*/
_153
public function createNewUser(Request $request, AuthyApi $authyApi)
_153
{
_153
$this->validate(
_153
$request, [
_153
'name' => 'required|string',
_153
'email' => 'required|unique:users|email',
_153
'password' => 'required',
_153
'country_code' => 'required',
_153
'phone_number' => 'required|numeric'
_153
]
_153
);
_153
_153
$values = $request->all();
_153
$values['password'] = Hash::make($values['password']);
_153
_153
DB::beginTransaction();
_153
_153
$newUser = new User($values);
_153
$newUser->save();
_153
Auth::login($newUser);
_153
_153
$authyUser = $authyApi->registerUser(
_153
$newUser->email,
_153
$newUser->phone_number,
_153
$newUser->country_code
_153
);
_153
if ($authyUser->ok()) {
_153
$newUser->authy_id = $authyUser->id();
_153
$newUser->save();
_153
$request->session()->flash(
_153
'status',
_153
"User created successfully"
_153
);
_153
_153
$sms = $authyApi->requestSms($newUser->authy_id);
_153
DB::commit();
_153
return redirect()->route('user-show-verify');
_153
} else {
_153
$errors = $this->getAuthyErrors($authyUser->errors());
_153
DB::rollback();
_153
return view('newUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
/**
_153
* This controller function shows the current user status
_153
*
_153
* @param Authenticatable $user Current user
_153
* @return mixed Response view
_153
*/
_153
public function show(Authenticatable $user)
_153
{
_153
return view('showUser', ['user' => $user]);
_153
}
_153
_153
/**
_153
* This controller function handles the submission form
_153
*
_153
* @param Request $request Current User Request
_153
* @param Authenticatable $user Current User
_153
* @param AuthyApi $authyApi Authy Client
_153
* @return mixed Response view
_153
*/
_153
public function verify(Request $request, Authenticatable $user,
_153
AuthyApi $authyApi, Client $client)
_153
{
_153
$token = $request->input('token');
_153
$verification = $authyApi->verifyToken($user->authy_id, $token);
_153
_153
if ($verification->ok()) {
_153
$user->verified = true;
_153
$user->save();
_153
$this->sendSmsNotification($client, $user);
_153
_153
return redirect()->route('user-index');
_153
} else {
_153
$errors = $this->getAuthyErrors($verification->errors());
_153
return view('verifyUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
/**
_153
* This controller function handles the verification code resent
_153
*
_153
* @param Request $request Current User Request
_153
* @param Authenticatable $user Current User
_153
* @param AuthyApi $authyApi Authy Client
_153
* @return mixed Response view
_153
*/
_153
public function verifyResend(Request $request, Authenticatable $user,
_153
AuthyApi $authyApi)
_153
{
_153
$sms = $authyApi->requestSms($user->authy_id);
_153
_153
if ($sms->ok()) {
_153
$request->session()->flash(
_153
'status',
_153
'Verification code re-sent'
_153
);
_153
return redirect()->route('user-show-verify');
_153
} else {
_153
$errors = $this->getAuthyErrors($sms->errors());
_153
return view('verifyUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
private function getAuthyErrors($authyErrors)
_153
{
_153
$errors = [];
_153
foreach ($authyErrors as $field => $message) {
_153
array_push($errors, $field . ': ' . $message);
_153
}
_153
return $errors;
_153
}
_153
_153
private function sendSmsNotification($client, $user)
_153
{
_153
$twilioNumber = config('services.twilio')['number'] or die(
_153
"TWILIO_NUMBER is not set in the environment"
_153
);
_153
$messageBody = 'You did it! Signup complete :)';
_153
_153
$client->messages->create(
_153
$user->fullNumber(), // Phone number which receives the message
_153
[
_153
"from" => $twilioNumber, // From a Twilio number in your account
_153
"body" => $messageBody
_153
]
_153
);
_153
}
_153
}

This controller loads the $user associated with the request and then uses the same Authy API method we used earlier to resend the code.

To wrap things up, let's implement the last step. We need to confirm that the user's account has been verified with a success page and a text message.


This simple blade template displays a user name and let's them know they've been verified.

Render user information with a blade template

render-user-information-with-a-blade-template page anchor
resources/views/showUser.blade.php

_21
@extends('layouts.master')
_21
_21
@section('title')
_21
User
_21
@endsection
_21
_21
@section('content')
_21
<h1>{{ $user->name }}</h1>
_21
<p>Account Status:
_21
@if($user->verified)
_21
Verified
_21
@else
_21
Not Verified
_21
@endif
_21
</p>
_21
@if( !$user->verified )
_21
<p>
_21
<a href="{{ route('user-verify') }}">Verify your account now</a>
_21
</p>
_21
@endif
_21
@endsection

This should suffice for confirmation in the browser that the user has been verified. Let's see how we might send that text message next.


Sending the Confirmation Message

sending-the-confirmation-message page anchor

We create a single instance of the Twilio REST API helper(link takes you to an external page), called $client in this example.

Then all we need to do to send an SMS to the user's phone is use messages->create() method. Notice that we are using the user's fullNumber() to make sure we support international numbers. The fullNumber() method in the User model simply returns a combination of the country_code and phone_number that the user provided upon registration.

Send a confirmation message via SMS

send-a-confirmation-message-via-sms page anchor
app/Http/Controllers/UserController.php

_153
<?php
_153
namespace App\Http\Controllers;
_153
_153
use App\Http\Requests;
_153
use App\User;
_153
use Auth;
_153
use Authy\AuthyApi as AuthyApi;
_153
use DB;
_153
use Hash;
_153
use Illuminate\Contracts\Auth\Authenticatable;
_153
use Illuminate\Http\Request;
_153
use Illuminate\Support\MessageBag;
_153
use Twilio\Rest\Client;
_153
_153
class UserController extends Controller
_153
{
_153
/**
_153
* Store a new user
_153
*
_153
* @param \Illuminate\Http\Request $request
_153
* @return \Illuminate\Http\Response
_153
*/
_153
public function createNewUser(Request $request, AuthyApi $authyApi)
_153
{
_153
$this->validate(
_153
$request, [
_153
'name' => 'required|string',
_153
'email' => 'required|unique:users|email',
_153
'password' => 'required',
_153
'country_code' => 'required',
_153
'phone_number' => 'required|numeric'
_153
]
_153
);
_153
_153
$values = $request->all();
_153
$values['password'] = Hash::make($values['password']);
_153
_153
DB::beginTransaction();
_153
_153
$newUser = new User($values);
_153
$newUser->save();
_153
Auth::login($newUser);
_153
_153
$authyUser = $authyApi->registerUser(
_153
$newUser->email,
_153
$newUser->phone_number,
_153
$newUser->country_code
_153
);
_153
if ($authyUser->ok()) {
_153
$newUser->authy_id = $authyUser->id();
_153
$newUser->save();
_153
$request->session()->flash(
_153
'status',
_153
"User created successfully"
_153
);
_153
_153
$sms = $authyApi->requestSms($newUser->authy_id);
_153
DB::commit();
_153
return redirect()->route('user-show-verify');
_153
} else {
_153
$errors = $this->getAuthyErrors($authyUser->errors());
_153
DB::rollback();
_153
return view('newUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
/**
_153
* This controller function shows the current user status
_153
*
_153
* @param Authenticatable $user Current user
_153
* @return mixed Response view
_153
*/
_153
public function show(Authenticatable $user)
_153
{
_153
return view('showUser', ['user' => $user]);
_153
}
_153
_153
/**
_153
* This controller function handles the submission form
_153
*
_153
* @param Request $request Current User Request
_153
* @param Authenticatable $user Current User
_153
* @param AuthyApi $authyApi Authy Client
_153
* @return mixed Response view
_153
*/
_153
public function verify(Request $request, Authenticatable $user,
_153
AuthyApi $authyApi, Client $client)
_153
{
_153
$token = $request->input('token');
_153
$verification = $authyApi->verifyToken($user->authy_id, $token);
_153
_153
if ($verification->ok()) {
_153
$user->verified = true;
_153
$user->save();
_153
$this->sendSmsNotification($client, $user);
_153
_153
return redirect()->route('user-index');
_153
} else {
_153
$errors = $this->getAuthyErrors($verification->errors());
_153
return view('verifyUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
/**
_153
* This controller function handles the verification code resent
_153
*
_153
* @param Request $request Current User Request
_153
* @param Authenticatable $user Current User
_153
* @param AuthyApi $authyApi Authy Client
_153
* @return mixed Response view
_153
*/
_153
public function verifyResend(Request $request, Authenticatable $user,
_153
AuthyApi $authyApi)
_153
{
_153
$sms = $authyApi->requestSms($user->authy_id);
_153
_153
if ($sms->ok()) {
_153
$request->session()->flash(
_153
'status',
_153
'Verification code re-sent'
_153
);
_153
return redirect()->route('user-show-verify');
_153
} else {
_153
$errors = $this->getAuthyErrors($sms->errors());
_153
return view('verifyUser', ['errors' => new MessageBag($errors)]);
_153
}
_153
}
_153
_153
private function getAuthyErrors($authyErrors)
_153
{
_153
$errors = [];
_153
foreach ($authyErrors as $field => $message) {
_153
array_push($errors, $field . ': ' . $message);
_153
}
_153
return $errors;
_153
}
_153
_153
private function sendSmsNotification($client, $user)
_153
{
_153
$twilioNumber = config('services.twilio')['number'] or die(
_153
"TWILIO_NUMBER is not set in the environment"
_153
);
_153
$messageBody = 'You did it! Signup complete :)';
_153
_153
$client->messages->create(
_153
$user->fullNumber(), // Phone number which receives the message
_153
[
_153
"from" => $twilioNumber, // From a Twilio number in your account
_153
"body" => $messageBody
_153
]
_153
);
_153
}
_153
}

We've just implemented account verification so your users can confirm their phone number. Where can we take it from here?


If you're a PHP developer working with Twilio, you might want to check out these other tutorials:

Click-To-Call

Put a button on your web page that connects visitors to live support or sales people via telephone.

Automated Survey(link takes you to an external page)

Instantly collect structured data from your users with a survey conducted over a voice call or SMS text messages.

Did this help?

did-this-help page anchor

Thanks for checking out this tutorial! If you have any feedback to share with us, we'd love to hear it. Reach out to us on Twitter(link takes you to an external page) and let us know what you've built!


Rate this page: