How To Verify Account In Laravel 8 With Twilio Verify

How To Verify Account In Laravel 8 With Twilio Verify

Admin
Admin・ 7 Oktober 2021
14 min read ・ 1416 views

OTP - Laravel - To prevent fake accounts from registering in our system, we need a feature that can guarantee that the data entered by the user is really valid. One of these features is by verifying the account or verifying the account by using the telephone number of the user.

In this article, we will both learn how to make account verification or account verification in laravel 8 with twilio verify. In this experiment, we will start from 0 by starting to install a new laravel project, install laravel ui and finish.

Before starting, don't forget to register a twilio account here first. Follow the register flow to completion. If you have finished registering a twilio account, we will start trying to make an account verify or verify an account in laravel with twilio verify:

install laravel twilio

1. The first step we start by installing a new laravel project. Open a terminal and go to the directory where you want to install the laravel project and run the command with the command composer create-project laravel/laravel otp-laravel or like the picture above. With this command, will create a new laravel project with the name otp-laravel.

2. Then go to the project directory that has been created with cd otp-laravel.

3. Install the twilio PHP sdk package with the command composer require twilio/sdk.

membuat service laravel twilio
 

4. Before continuing, let's first create the service. Click here to create a service that will be used in this experiment. Click Create Service Now and enter a service name.

5. Update the .env file. Open the .env file and add a new record as below.

TWILIO_SID=ACf69bd19f874fd955e158939fxxxxxxxx
TWILIO_AUTH_TOKEN=15e551627356707394eaxxxxxxxxx0d
TWILIO_VERIFY_SID=VA5fe84a552065c41217a8xxxxxxxxb

TWILIO_SID and TWILIO_AUTH can be obtained from the twilio dashboard page or click here.

TWILIO_SID dan TWILIO_AUTH bisa didapat dari halaman dashboard twilio

On the Twilio dashboard page, you will see a display like the image above. Copy the ACCOUNT SID code to the .env file, precisely in the TWILIO_SID line. and AUTH TOKEN copy and paste in the line TWILIO_AUTH_TOKEN.

TWILIO_VERIFY_ID bisa didapatkan dari halaman service,

While the TWILIO_VERIFY_ID line can be obtained from the service page, later there will be a display like the picture above. Copy the ID as indicated by the blue underscore as shown above, then paste it in the .env file to be precise on the TWILIO_VERIFY_ID line.

Don't forget to also create a new database for trying to make account verification with laravel and twilio verify. Then enter the name of the database in the .env file.

6. Install laravel ui with the command composer require laravel/ui. followed by the next step, namely generating login or registration scaffolding with php artisan ui bootstrap --auth. Then run the command npm install && npm run dev.

7. update the user migration file in the database/migrations/[timestamp]_create_users_table.php directory. In the up method, the update becomes as below.

public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('phone')->unique();
            $table->boolean('isVerified')->default(false);
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

8. After updating the user migration file, now also update the User Model in the App/Models/User.php directory in the protected $fillable section to be as below.

protected $fillable = [
        'name',
        'phone',
        'password',
        'isVerified',
    ];

9. Run the php artisan migrate command to migrate the tables to the database.

10. Update the RegisterController.php file.

Delete record

 use App\Providers\RouteServiceProvider;

and

protected $redirectTo = RouteServiceProvider::HOME;

Then in the validator method, the update becomes as below.

 protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255'],
            'phone' => ['required', 'numeric', 'unique:users'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

also update the create method to be as below,

protected function create(array $data)
    {
        $token = getenv("TWILIO_AUTH_TOKEN");
        $twilio_sid = getenv("TWILIO_SID");
        $twilio_verify_sid = getenv("TWILIO_VERIFY_SID");
        $twilio = new Client($twilio_sid, $token);
        $twilio->verify->v2->services($twilio_verify_sid)
            ->verifications
            ->create($data['phone'], "sms");
        User::create([
            'name' => $data['name'],
            'phone' => $data['phone'],
            'password' => Hash::make($data['password']),
        ]);
    }

Then add the verify method in RegisterController.php as below.

protected function verify(Request $request)
    {
        $data = $request->validate([
            'verification_code' => ['required', 'numeric'],
            'phone' => ['required', 'string'],
        ]);
        /* Get credentials from .env */
        $token = getenv("TWILIO_AUTH_TOKEN");
        $twilio_sid = getenv("TWILIO_SID");
        $twilio_verify_sid = getenv("TWILIO_VERIFY_SID");
        $twilio = new Client($twilio_sid, $token);
        $verification = $twilio->verify->v2->services($twilio_verify_sid)
            ->verificationChecks
            ->create($data['verification_code'], array('to' => $data['phone']));
        if ($verification->valid) {
            $user = tap(User::where('phone', $data['phone']))->update(['isVerified' => true]);
            /* Authenticate user */
            Auth::login($user->first());
            return redirect()->route('home')->with(['message' => 'Phone number verified']);
        }
        return back()->with(['phone' => $data['phone'], 'error' => 'Invalid verification code entered!']);
    }

So overall, the code in the App/Http/Controller/Auth/RegisterController.php file becomes as below.

<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Twilio\Rest\Client;
use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */
    use RegistersUsers;
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }
    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255'],
            'phone' => ['required', 'numeric', 'unique:users'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }
    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return \App\Models\User
     */
    protected function create(array $data)
    {
        $token = getenv("TWILIO_AUTH_TOKEN");
        $twilio_sid = getenv("TWILIO_SID");
        $twilio_verify_sid = getenv("TWILIO_VERIFY_SID");
        $twilio = new Client($twilio_sid, $token);
        $twilio->verify->v2->services($twilio_verify_sid)
            ->verifications
            ->create($data['phone'], "sms");
        User::create([
            'name' => $data['name'],
            'phone' => $data['phone'],
            'password' => Hash::make($data['password']),
        ]);
    }
    protected function verify(Request $request)
    {
        $data = $request->validate([
            'verification_code' => ['required', 'numeric'],
            'phone' => ['required', 'string'],
        ]);
        /* Get credentials from .env */
        $token = getenv("TWILIO_AUTH_TOKEN");
        $twilio_sid = getenv("TWILIO_SID");
        $twilio_verify_sid = getenv("TWILIO_VERIFY_SID");
        $twilio = new Client($twilio_sid, $token);
        $verification = $twilio->verify->v2->services($twilio_verify_sid)
            ->verificationChecks
            ->create($data['verification_code'], array('to' => $data['phone']));
        if ($verification->valid) {
            $user = tap(User::where('phone', $data['phone']))->update(['isVerified' => true]);
            /* Authenticate user */
            Auth::login($user->first());
            return redirect()->route('home')->with(['message' => 'Phone number verified']);
        }
        return back()->with(['phone' => $data['phone'], 'error' => 'Invalid verification code entered!']);
    }
}

11. Update the file vendor/laravel/ui/auth-backend/RegistersUsers.php. In the register method, update the code to be as below.

public function register(Request $request)
    {
        $this->validator($request->all())->validate();
        event(new Registered($user = $this->create($request->all())));
        if ($response = $this->registered($request, $user)) {
            return $response;
        }
        return $request->wantsJson()
                    ? new JsonResponse([], 201)
                    : redirect()->route('verify')->with(['phone' => $request->phone]);
    }

Also add

use Illuminate\Http\Request;

So overall, the code in the vendor/laravel/ui/auth-backend/RegistersUsers.php file is as below.

<?php
namespace Illuminate\Foundation\Auth;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
trait RegistersUsers
{
    use RedirectsUsers;
    /**
     * Show the application registration form.
     *
     * @return \Illuminate\View\View
     */
    public function showRegistrationForm()
    {
        return view('auth.register');
    }
    /**
     * Handle a registration request for the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
     */
    public function register(Request $request)
    {
        $this->validator($request->all())->validate();
        event(new Registered($user = $this->create($request->all())));
        if ($response = $this->registered($request, $user)) {
            return $response;
        }
        return $request->wantsJson()
                    ? new JsonResponse([], 201)
                    : redirect()->route('verify')->with(['phone' => $request->phone]);
    }
    /**
     * Get the guard to be used during registration.
     *
     * @return \Illuminate\Contracts\Auth\StatefulGuard
     */
    protected function guard()
    {
        return Auth::guard();
    }
    /**
     * The user has been registered.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  mixed  $user
     * @return mixed
     */
    protected function registered(Request $request, $user)
    {
        //
    }
}

12. Update the routes/web.php file. In the routes/web.php file add a new route like below.

Route::get('/verify', function () {
    return view('auth.verify');
})->name('verify');
Route::post('/verify', [App\Http\Controllers\Auth\RegisterController::class,'verify'])->name('verify');

So overall, the routes/web.php file will be like below.

<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
    return view('welcome');
});
Auth::routes();
Route::get('/verify', function () {
    return view('auth.verify');
})->name('verify');
Route::post('/verify', [App\Http\Controllers\Auth\RegisterController::class,'verify'])->name('verify');
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');

13. In the resources/views/auth/register.blade.php file, update it as below.

@extends('layouts.app')
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Register') }}</div>
                <div class="card-body">
                    <form method="POST" action="{{ route('register') }}">
                        @csrf
                        <div class="form-group row">
                            <label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>
                            <div class="col-md-6">
                                <input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>
                                @error('name')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>
                        <div class="form-group row">
                            <label for="phone" class="col-md-4 col-form-label text-md-right">{{ __('Phone Number') }}</label>
                            <div class="col-md-6">
                                <input id="phone" type="tel" class="form-control @error('phone') is-invalid @enderror" name="phone" value="{{ old('phone') }}" required autocomplete="phone">
                                @error('phone')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>
                        <div class="form-group row">
                            <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
                                @error('password')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>
                        <div class="form-group row">
                            <label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
                            <div class="col-md-6">
                                <input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
                            </div>
                        </div>
                        <div class="form-group row mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Register') }}
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

14. Then also update the verify.blade.php file in the resources/views/auth/verify.blade.php directory to be as below.

@extends('layouts.app')
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Verify Your Phone Number') }}</div>
                <div class="card-body">
                    @if (session('error'))
                    <div class="alert alert-danger" role="alert">
                        {{session('error')}}
                    </div>
                    @endif
                    Please enter the OTP sent to your number: {{session('phone')}}
                    <form action="{{route('verify')}}" method="post">
                        @csrf
                        <div class="form-group row">
                            <label for="verification_code"
                                class="col-md-4 col-form-label text-md-right">{{ __('Phone Number') }}</label>
                            <div class="col-md-6">
                                <input type="hidden" name="phone" value="{{session('phone')}}">
                                <input id="verification_code" type="tel"
                                    class="form-control @error('verification_code') is-invalid @enderror"
                                    name="verification_code" value="{{ old('verification_code') }}" required>
                                @error('verification_code')
                                <span class="invalid-feedback" role="alert">
                                    <strong>{{ $message }}</strong>
                                </span>
                                @enderror
                            </div>
                        </div>
                        <div class="form-group row mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Verify Phone Number') }}
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

15. Testing.

OK, we have finished configuring twilio verify, creating a database and writing code to make account verification in laravel 8 with twilio verify. Now it's time for us to try it. Try running the server with php artisan serve and go to the register menu.

mencoba register dan verifikasi akun di laravel
Then try to enter the data in the forms provided. For the phone number form, the format that must be entered is the country code followed by the phone number. As shown above, the input format is like +6282 and so on (6282 cannot be input).

verifikasi akun sms dengan twilio di laravel
 verifikasi akun dengan twilio di laravel

Now, it's time for verification. Enter the code that has been received via sms into the form as shown above. The code entered must also be exactly the same, if it is not the same then we cannot continue verifying the phone number.

This article is finished, which has discussed how to make account verification with sms in laravel 8 using twilio verify. Here, we have learned together from installing a new laravel project, creating a twilio verify service, writing codes to testing account verification in laravel 8 using twilio verify.

From the experiments that have been carried out, we can conclude that the existence of an account verification feature on a system that must register such as e-commerce is indeed very important. This is intended to avoid users who list carelessly. Example: on a website or system that must register but there is no account verification, we can carelessly enter important data, we can login. Whereas on websites or systems that have account verification, we can no longer carelessly enter the data.

That's all for this article, if there are criticisms, suggestions, input or anything you want to discuss, please write them in the comment form below.

See you in the next article :-)

Tinggalkan Komentar
Loading Comments