DEV Community

Hilmi Hidayat
Hilmi Hidayat

Posted on • Originally published at divisidev.com on

Implementasi Phone Number Verification dengan Twilio Verify di Laravel 9

Twilio Verify: User Verification API - Verify merupakan salah satu service yang disediakan oleh Twilio, service ini bekerja untuk menangkal penipuan dan melindungi akun user. Dan dengan twilio verify, kita dapat dengan cepat memverifikasi user via SMS, voice, TOTP, push dan email. Pada artikel ini, saya akan membagikan cara mengimplementasikan Twilio Verify untuk membuat verifikasi akun. Jadi skenarionya, kita akan membuat authentication menggunakan nomor handphone dan setiap user yang mendaftar harus dapat diverifikasi.

Oke, mari kita langsung saja ke step by stepnya: 👇

Step 1: Install Laravel

//via Laravel Installer
composer global require laravel/installer
laravel new laravel-twilio-verify

//via Composer
composer create-project laravel/laravel laravel-twilio-verify
Enter fullscreen mode Exit fullscreen mode

Langkah pertama yang harus kita lakukan tentu saja adalah menginstall laravel. Ada beberapa cara yang bisa dilakukan untuk menginstall laravel, diantaranya adalah dengan menggunakan composer atau laravel installer. Jika kamu sudah menginstall laravel installer, kamu bisa langsung saja menjalankan perintah laravel new laravel-twilio-verify. Dan jika kamu tidak menggunakan laravel installer atau terbiasa menggunakan composer, kamu bisa menjalankan perintah composer create-project laravel/laravel laravel-twilio-verify.

Setelah berhasil menginstall laravel, sekarang kita bisa menjalankan perintah php artisan serve, lalu buka pada browser dengan URL 127.0.0.1:{port} atau laravel-twilio-verify.test.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_twilio_verify
DB_USERNAME=root
DB_PASSWORD=
Enter fullscreen mode Exit fullscreen mode

Oke, setelah menyelesaikan step pertama, lanjutkan dengan membuat database baru dan jangan lupa untuk menyesuaikan DB_DATABASE pada file .env.

Step 2: Install Laravel UI

composer require laravel/ui
php artisan ui bootstrap --auth
npm install && npm run dev
Enter fullscreen mode Exit fullscreen mode

Kemudian, kita perlu auth preset. Untuk itu, disini saya akan menggunakan laravel ui package. Silahkan jalankan perintah seperti di atas secara berurutan untuk menginstall package tersebut pada project laravel kita.

Step 3: Setup Twilio Verify Service

Pada step ketigaini, kita akan melakukan set up Twilio pada laravel project kita. Jika kamu belum mendaftar akun Twilio, silahkan melakukan pendaftaran terlebih dahulu di situs resmi Twilio.com atau silahkan klik link disini. Isi data pada beberapa input fields yang tersedia seperti First Name, Last Name, Email dan Password.

Twilio Verify Service

Kemudian, masuk pada product verfiy/services dan silahkan buat service baru. Setelah kamu menambahkan friendly name seperti di atas dan klik create button, maka kamu akan mendapatkan service id. Simpan service id tersebut untuk kita tambahkan pada file .env nantinya.

composer require twilio/sdk
Enter fullscreen mode Exit fullscreen mode

Nah, sebelum mengimplementasi Twilio pada laravel project kita, ada hal yang harus kita lakukan yaitu menginstall Twilio SDK. Silahkan install Twilio SDK menggunakan perintah composer seperti di atas.

TWILIO_AUTH_SID="AC045b168ea3fad122bb8206dcb"
TWILIO_AUTH_TOKEN="cb6f96cd2e744f9b08112520"
TWILIO_VERIFY_SID="VAe74cefd2d8d146ba3e30c89fd"
Enter fullscreen mode Exit fullscreen mode

Selanjutnya, kita perlu menambahkan beberapa variable baru pada file .env kita. Tambahkan variable seperti di atas pada file .env dan sesuaikan valuenya dengan data dari akun Twilio kamu.

Step 4: Setup Model & Migration

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

Oke, selanjutnya kita perlu melakukan set up pada file users migration. Disini kita hanya perlu menambahkan dua column yaitu phone_number dan isVerified. Kenapa kita perlu menambahkan kedua column tersebut? Karena seperti yang telah saya jelaskan sebelumnya, pada artikel ini kita mengimplementasikan twilio verify service untuk membuat phone number verification di laravel.

Selain menambahkan field baru, dan pada artikel ini tujuannya adalah untuk implementasi phone number verification dengan twilio, jadi field email dan email_verified_at bisa kita hapus.

php artisan migrate
Enter fullscreen mode Exit fullscreen mode

Jika sudah memperbarui file users migration, sekarang kita bisa menjalankan perintah artisan migrate untuk memigrasi file-file migration menjadi table-table di database yang telah kita buat sebelumnya.

protected $fillable = [
    'name',
    'phone_number',
    'password',
    'isVerified',
];
Enter fullscreen mode Exit fullscreen mode

Karena kita mengubah file default users migration dari laravel, maka kita juga perlu menyesuaikannya pada file User model. Silahkan buka file models/User.php, sesuaikan kode menjadi seperti di atas pada method $fillable.

Step 5: Setup RegisterController

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

Memasuki step ke lima, kali ini kita akan bekerja pada RegisterController.php. Silahkan buka file tersebut yang terletak di direktori app/Http/Controllers/Auth. Karena kita melakukan perubahan pada preset yang telah disediakan oleh laravel ui, jadi kita juga harus memperbarui beberapa hal pada RegisterController.php. Pertama, ubah validatornya menjadi contoh kode di atas. Disini kita mengubah validator untuk email menjadi phone_number.

    protected function create(array $data)
    {
        $sid = env("TWILIO_AUTH_SID");
        $token = env("TWILIO_AUTH_TOKEN");
        $twilio_verify_sid = env("TWILIO_VERIFY_SID");

        $twilio = new Client($sid, $token);

        $twilio->verify->v2->services($twilio_verify_sid)
            ->verifications
            ->create($data['phone_number'], "sms");

        User::create([
            'name' => $data['name'],
            'phone_number' => $data['phone_number'],
            'password' => Hash::make($data['password']),
        ]);

        return redirect()->route('verify')
                ->with(['phone_number' => $data['phone_number']]);
    }
Enter fullscreen mode Exit fullscreen mode

Kemudian pada function create, ubah kodenya menjadi seperti di atas. Disini kita menambahkan pengaturan untuk Twilio service, dan mengubah request data yang akan diinputkan ke table users.

    protected function verify(Request $request)
    {
        $data = $request->validate([
            'verification_code' => ['required', 'numeric'],
            'phone_number' => ['required', 'string'],
        ]);

        $sid = env("TWILIO_AUTH_SID");
        $token = env("TWILIO_AUTH_TOKEN");
        $twilio_verify_sid = env("TWILIO_VERIFY_SID");

        $twilio = new Client($sid, $token);

        $verification = $twilio->verify->v2->services($twilio_verify_sid)
            ->verificationChecks
            ->create($data['verification_code'], array('to' => $data['phone_number']));

            if ($verification->valid) {
                $user = tap(User::where('phone_number', $data['phone_number']))->update(['isVerified' => true]);
                Auth::login($user->first());
                return redirect()->route('home')
                    ->with(['message' => 'Your account has been verified']);
            }

        return back()->with([
            'phone_number' => $data['phone_number'],
            'error' => 'Invalid verification code entered!'
        ]);
    }
Enter fullscreen mode Exit fullscreen mode

Kemudian, tambahkan kode baru yaitu function verify untuk melakukan pekerjaan verifikasi akun dengan nomor handphone nantinya. Copy code seperti di atas, lalu paste pada file RegisterController.php.

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_number' => $request->phone_number]);
}
Enter fullscreen mode Exit fullscreen mode

Nah, selain menambahkan function verify, kita juga perlu menambahkan function register seperti di atas. By the way, kode tersebut merupakan bawaan dari laravel ui, namun kita akan overide kode tersebut pada RegisterController.php.

Step 6: Define Route

Route::get('/verify', function () {
    return view('auth.verify');
})->name('verify');

Route::post('/verify', [App\Http\Controllers\Auth\RegisterController::class,'verify'])->name('verify');
Enter fullscreen mode Exit fullscreen mode

Nah, setelah membuat controller, sekarang kita harus menambahkan route baru di file web.php. Copy code di atas, dan tambahkan pada routes/web.php.

Step 7: Setup View

register.blade.php

@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="row mb-3">
                            <label for="name" class="col-md-4 col-form-label text-md-end">{{ __('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="row mb-3">
                            <label for="phone_number" class="col-md-4 col-form-label text-md-end">{{ __('Phone Number') }}</label>

                            <div class="col-md-6">
                                <input id="phone_number" type="tel" class="form-control @error('phone_number') is-invalid @enderror" name="phone_number" value="{{ old('phone_number') }}" required autocomplete="phone_number">

                                @error('phone_number')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="row mb-3">
                            <label for="password" class="col-md-4 col-form-label text-md-end">{{ __('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="row mb-3">
                            <label for="password-confirm" class="col-md-4 col-form-label text-md-end">{{ __('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="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
Enter fullscreen mode Exit fullscreen mode

Setelah membuat controller dan menambahkan route, sekarang kita perlu mengubah file view bawaan dari laravel ui package. Silahkan buka file resources/views/auth/register.blade.php, ubah kode yang ada menjadi seperti di atas. Pada file ini, kita hanya mengubah email address input field menjadi phone number.

verify.blade.php

@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">Please enter the OTP sent to your number: {{session('phone_number')}}</div>
                <div class="card-body">
                    @if (session('error'))
                    <div class="alert alert-danger" role="alert">
                        {{session('error')}}
                    </div>
                    @endif
                    <form action="{{route('verify')}}" method="post">
                        @csrf
                        <div class="form-group row mb-3">
                            <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_number" value="{{session('phone_number')}}">
                                <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
Enter fullscreen mode Exit fullscreen mode

File view yang berikutnya adalah verify.blade.php. Silahkan buka file tersebut, lalu ubah kodenya menjadi seperti di atas. Di file ini, kita menyertakan input hidden yang mempunyai value phone number dari yang diisi user saat melakukan proses registrasi.

Testing

testing register

Oke, setelah melalui proses-proses di atas, sekarang merupakan waktunya untuk testing. Silahkan jalankan laravel project kamu, lalu buka di browser dengan 127.0.0.1:{port} atau bisa juga dengan seperti laravel-twilio-verify.test. Buka halaman register dan cobalah untuk register akun baru. *Untuk phone number input field, pastikan mengisinya dengan format +62.

twilio sms chanel

Jika proses registrasi berhasil, maka akan ada sms masuk yang berisi kode verifikasi seperti di atas.

laravel twilio verify phone number

Setelah proses registrasi pada langkah sebelumnya berhasil, maka kamu akan diarahkan ke halaman verify phone number seperti di atas. Silahkan isi input field tersebut dengan kode yang telah dikirim via sms. Jika akun berhasil diverifikasi, maka kamu akan diarahkan ke halaman home dan pada table users, isVerified akan berubah menjadi 1 atau true.

Bonus

$twilio->verify->v2->services($twilio_verify_sid)
    ->verifications
    ->create($data['phone_number'], "whatsapp");
Enter fullscreen mode Exit fullscreen mode

Jika kamu tidak ingin kode verifikasi dikirim via sms, mungkin kamu bisa mencoba opsi chanel whatsapp. Caranya, buka file RegisterController.php, lalu pada function create silahkan ubah chanelnya menjadi whatsapp atau seperti kode di atas.

twilio whatsapp chanel

Nah, sekarang jika kamu coba register akun lagi, kode verifikasi akan dikirim via whatsapp seperti gambar di atas.

$phone_number = $data['phone_number'];
if ($data['phone_number'][0] == "0") {
    $phone_number = substr($phone_number, 1);
}

if ($phone_number[0] == "8") {
    $phone_number = "62" . $phone_number;
}
Enter fullscreen mode Exit fullscreen mode

Ingin mengubah format input pada phone number input field? mungkin format input saat ini yaitu harus menyertakan kode negara seperti +62 dinilai kurang user friendly, kamu bisa menambahkan kode seperti di atas pada function create di RegisterController.php. Dengan kode tersebut, jika user menginputkan seperti 0821234567 maka akan dikonversi menjadi 62821234567.

protected function create(array $data)
{
    $sid = env("TWILIO_AUTH_SID");
    $token = env("TWILIO_AUTH_TOKEN");
    $twilio_verify_sid = env("TWILIO_VERIFY_SID");

    $phone_number = $data['phone_number'];
    if ($data['phone_number'][0] == "0") {
        $phone_number = substr($phone_number, 1);
    }

    if ($phone_number[0] == "8") {
        $phone_number = "62" . $phone_number;
    }

    $twilio = new Client($sid, $token);

    $twilio->verify->v2->services($twilio_verify_sid)
        ->verifications
        ->create('+'.$phone_number, "whatsapp");

    User::create([
        'name' => $data['name'],
        'phone_number' => $phone_number,
        'password' => Hash::make($data['password']),
    ]);

    return redirect()->route('verify')
            ->with(['phone_number' => $data['phone_number']]);
}
Enter fullscreen mode Exit fullscreen mode

Dan sekarang, function create pada RegisterController menjadi seperti kode di atas.

Demikianlah artikel tentang implementasi phone number verification dengan twilio verify service di laravel 9 kali ini. Jika kamu punya saran, kritik, masukan atau apapun itu yang ingin didiskusikan, silahkan tulis komentar teman-teman pada form komentar di bawah ini. Semoga artikel ini dapat membantu dan sampai jumpa pada artikel berikutnya. Happy coding 👨‍💻

Credit: Device illustrations by Storyset

Top comments (0)