[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-cats-ngidenet":3,"blog-detail-ngidenet-cara-membuat-otp-di-laravel":20},{"items":4},[5,9,13,17],{"name":6,"slug":7,"count":8},"Digital Marketing","digital-marketing",41,{"name":10,"slug":11,"count":12},"Programming","programming",56,{"name":14,"slug":15,"count":16},"Tips","tips",75,{"name":18,"slug":19,"count":8},"Web Development","web-development",{"id":21,"slug":22,"title":23,"short_text":24,"excerpt":24,"cover":25,"cover_image":25,"cover_alt_text":25,"category":10,"tags":26,"published_at":27,"created_at":28,"full_text":29,"meta_title":25,"meta_description":30,"faqs":31,"images":32,"views_count":33},497,"cara-membuat-otp-di-laravel","Cara membuat OTP di Laravel","Helo teman-teman, kali ini saya akan membahas bagaimana cara membuat kode OTP di PHP atau lebih tepatnya dengan menggunakan framework Laravel. Apa itu kode OTP? Kode OTP adalah singkatan dari kode One",null,[],"2023-12-07T16:00:00Z","2026-07-14T04:39:44.406313Z","\u003Cp>Helo teman-teman, kali ini saya akan membahas bagaimana cara membuat kode OTP di PHP atau lebih tepatnya dengan menggunakan framework Laravel.\u003C\u002Fp>\u003Ch3>Apa itu kode OTP?\u003C\u002Fh3>\u003Cp>Kode OTP adalah singkatan dari kode \u003Ci>One Time-Password\u003C\u002Fi> atau bisa juga diartikan sebagai kode \u003Ci>password\u003C\u002Fi> yang hanya bersifat sementara dan dapat digunakan satu kali saja. Karena kode OTP ini hanya bisa dipakai 1 kali biasanya kode OTP ini memiliki waktu expired-nya.\u003C\u002Fp>\u003Cp>\u003Ch3>Daftar Isi\u003C\u002Fh3> \u003Cul>\n\u003Cli>\nApa itu kode OTP?\n\u003C\u002Fli>\n\u003Cli>\nFlow security dengan OTP\n\u003C\u002Fli>\n\u003Cli>\nInstalasi Laravel\n\u003C\u002Fli>\n\u003Cli>\nUpdate .ENV dan Migrate\n\u003C\u002Fli>\n\u003Cli>\nBuat table dan model untuk OTP User\n\u003C\u002Fli>\n\u003Cli>\nModifikasi Register Controller\n\u003C\u002Fli>\n\u003Cli>\nBuat Listener dan Notification file Untuk Kirim OTP\n\u003C\u002Fli>\n\u003Cli>\nBuat tampilan halaman OTP\n\u003C\u002Fli>\n\u003Cli>\nBagaimana cara validasi OTP?\n\u003C\u002Fli>\n\u003Cli>\nKesimpulan\n\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Kode \u003Ci>One Time-Password\u003C\u002Fi> umumnya digunakan sebagai \u003Ci>password\u003C\u002Fi> sekali pakai yang ditujukan untuk melakukan proses verifikasi, authentikasi. Bisa juga digunakan untuk meningkatkan sekuriti dari sistem yang dibuat sebagai lapis ke dua selain menggunakan password umum.\u003C\u002Fp>\u003Cp>\u003Cp>Kode OTP ini biasanya dikirim via SMS, Online Chatting App seperti WA\u002FTelegram atau ke alamat email.\u003C\u002Fp>\u003Ch3>Flow security dengan OTP\u003C\u002Fh3>\u003Cp>Ada banyak flow implementasi OTP, tapi kali ini saya akan coba membuat flow yang sangat simple agar teman-teman memahami konsep OTP dengan lebih baik.\u003C\u002Fp>\u003Cp>Flownya adalah:\u003C\u002Fp>\u003Col>\u003Cli>User daftar dan mengisi data user yang dibutuhkan\u003C\u002Fli>\u003Cli>Setelah user berhasil mendaftar, redirect ke halaman validasi OTP\u003C\u002Fli>\u003Cli>Kirim OTP ke email user\u003C\u002Fli>\u003Cli>user mengisi kode OTP\u003C\u002Fli>\u003Cli>Sistem memvalidasi kode OTP\u003C\u002Fli>\u003Cli>aktivasi user dan dan loginkan user.\u003C\u002Fli>\u003C\u002Fol>\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Fres.cloudinary.com\u002Fdprnqhug7\u002Fimage\u002Fupload\u002Fv1693465463\u002Fngide\u002Fflow-otw-laravel.jpg\"\u002F>\u003Cfigcaption>Flow OTP dengan Laravel\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Cp>Nah flownya sangat simple kan? Jadi selain bisa digunakan untuk verifikasi email user yang digunakan apakah aktif atau tidak, kode OTP ini juga nanti bisa dikembangkan lagi dengan membuat security lapis ke dua saat login.\u003C\u002Fp>\u003Ch3>Instalasi Laravel\u003C\u002Fh3>\u003Cp>Kita sudah belajar flownya, saatnya instalasi laravel dulu.\u003C\u002Fp>\u003Cp>Mungkin temen-teman sudah punya aplikasi Laravel yang sedang berjalan bisa pakai aplikasi yang sudah dibangun ya. Nah bagi yang belum bisa coba install laravel dulu.\u003C\u002Fp>\u003Cp>Saya akan install secara cepat saja langsung dengan command composer \u003Ccode>composer create-project laravel\u002Flaravel otp-sample\u003C\u002Fcode>\u003C\u002Fp>\u003Cp>Setelah instalasi selesai, pergi ke folder \u003Ccode>otp-sample\u003C\u002Fcode> atau folder lain sesuai yang teman-teman buat.\u003C\u002Fp>\u003Cp>Install Package Brezze\u003C\u002Fp>\u003Cp>Kita akan pakai package breeze dari Laravel langsung untuk mengurus soal authentication. Jadi kita tidak buat dari 0 lagi. Cek lebih detail di: \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Flaravel\u002Fbreeze\">https:\u002F\u002Fgithub.com\u002Flaravel\u002Fbreeze\u003C\u002Fa>\u003C\u002Fp>\u003Cp>Kita akan sedikit memodifikasi untuk implementasi OTP kode saat register.\u003C\u002Fp>\u003Cp>Untuk install breeze, jalankan command berikut.\u003C\u002Fp>\u003Cp>\u003Ccode>composer require laravel\u002Fbreeze --dev\u003C\u002Fcode>\u003C\u002Fp>\u003Cp>Setelah selesai di install, jalankan command selanjutnya.\u003C\u002Fp>\u003Cp>\u003Ccode>php artisan breeze:install\u003C\u002Fcode>\u003C\u002Fp>\u003Cp>Dalam tutorial kali ini, saya akan pakai blade template saja, kalian bisa coba menggunakan react\u002Fvue sesuai dengan frontend yang diinginkan.\u003C\u002Fp>\u003Cp>Nah setelah laravel dan brezze sudah kita install, maka selanjutnya coba jalankan php artisan serve untuk melilhat laravel project di browser kita.\u003C\u002Fp>\u003Cp>Buka \u003Ccode>http:\u002F\u002Flocalhost:8000\u003C\u002Fcode>\u003C\u002Fp>\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Fres.cloudinary.com\u002Fdprnqhug7\u002Fimage\u002Fupload\u002Fv1693548705\u002Fngide\u002Fhomepage.png\"\u002F>\u003Cfigcaption>Tampilan awal default laravel.\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Ch3>Update .ENV dan Migrate\u003C\u002Fh3>\u003Cp>Hampir kelupaan, jadi karena kita akan kirim email, saya akan setting \u003Ccode>MAIL_MAILER=log\u003C\u002Fcode>  untuk testing email nanti.\u003C\u002Fp>\u003Cp>Jangan lupa juga setup databasenya disesuaikan dengan database kalian ya.\u003C\u002Fp>\u003Cpre>\u003Ccode>APP_NAME=Laravel\nAPP_ENV=local\nAPP_KEY=base64:SgQ2Gp+CTCRMluws6oU9Zxr3OquUZAzHeAQbBBTx8hg=\nAPP_DEBUG=true\nAPP_URL=http:\u002F\u002Flocalhost\nLOG_CHANNEL=stack\nLOG_DEPRECATIONS_CHANNEL=null\nLOG_LEVEL=debug\nDB_CONNECTION=mysql\nDB_HOST=127.0.0.1\nDB_PORT=3306\nDB_DATABASE=otp_example\nDB_USERNAME=root\nDB_PASSWORD=\nDB_SOCKET='\u002FApplications\u002FMAMP\u002Ftmp\u002Fmysql\u002Fmysql.sock'\nBROADCAST_DRIVER=log\nCACHE_DRIVER=file\nFILESYSTEM_DISK=local\nQUEUE_CONNECTION=sync\nSESSION_DRIVER=file\nSESSION_LIFETIME=120\nMEMCACHED_HOST=127.0.0.1\nREDIS_HOST=127.0.0.1\nREDIS_PASSWORD=null\nREDIS_PORT=6379\nMAIL_MAILER=log\nMAIL_HOST=mailpit\nMAIL_PORT=1025\nMAIL_USERNAME=null\nMAIL_PASSWORD=null\nMAIL_ENCRYPTION=null\nMAIL_FROM_ADDRESS=\"hello@example.com\"\nMAIL_FROM_NAME=\"${APP_NAME}\"\nAWS_ACCESS_KEY_ID=\nAWS_SECRET_ACCESS_KEY=\nAWS_DEFAULT_REGION=us-east-1\nAWS_BUCKET=\nAWS_USE_PATH_STYLE_ENDPOINT=false\nPUSHER_APP_ID=\nPUSHER_APP_KEY=\nPUSHER_APP_SECRET=\nPUSHER_HOST=\nPUSHER_PORT=443\nPUSHER_SCHEME=https\nPUSHER_APP_CLUSTER=mt1\nVITE_PUSHER_APP_KEY=\"${PUSHER_APP_KEY}\"\nVITE_PUSHER_HOST=\"${PUSHER_HOST}\"\nVITE_PUSHER_PORT=\"${PUSHER_PORT}\"\nVITE_PUSHER_SCHEME=\"${PUSHER_SCHEME}\"\nVITE_PUSHER_APP_CLUSTER=\"${PUSHER_APP_CLUSTER}\"\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Jangan lupa ulangin \u003Ccode>php artisan serve\u003C\u002Fcode> jika untuk me refresh settingnya.\u003C\u002Fp>\u003Ch3>Buat table dan model untuk OTP User\u003C\u002Fh3>\u003Cp>Untuk membuat table otp, kita akan buat dulu sebuah migration dengan command seperti berikut ini:\u003C\u002Fp>\u003Cp>\u003Ccode>php artisan make:migration create_user_otps\u003C\u002Fcode>\u003C\u002Fp>\u003Cp>Setelah selesai dibuat, buka file migration tersebut dan sesuaikan isi filenya seperti berikut ini:\u003C\u002Fp>\u003Cpre>\u003Ccode>&lt;?php\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\nreturn new class extends Migration\n{\n    \u002F**\n     * Run the migrations.\n     *\n     * @return void\n     *\u002F\n    public function up()\n    {\n        Schema::create('user_otps', function (Blueprint $table) {\n            $table-&gt;id();\n            $table-&gt;integer('user_id');\n            $table-&gt;integer('otp_code');\n            $table-&gt;dateTime('expired_at');\n            $table-&gt;timestamps();\n        });\n    }\n    \u002F**\n     * Reverse the migrations.\n     *\n     * @return void\n     *\u002F\n    public function down()\n    {\n        Schema::dropIfExists('user_otps');\n    }\n};\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Kita akan membuat table \u003Ccode>user_otps\u003C\u002Fcode> yang akan menampung data OTP dengan fieldnya yaitu:\u003C\u002Fp>\u003Col>\u003Cli>id\u003C\u002Fli>\u003Cli>user_id : untuk relasi ke table user\u003C\u002Fli>\u003Cli>otp_code: kode otp, dimana angka yang panjangnya 6 huruf.\u003C\u002Fli>\u003Cli>expired_at: datetime, agar kode OTP tidak bisa dipakai lagi jika sudah lewat expired datenya.\u003C\u002Fli>\u003C\u002Fol>\u003Cp>Jika sudah, run migration dengan menjalankan command: \u003Ccode>php artisan migrate\u003C\u002Fcode> \u003C\u002Fp>\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Fres.cloudinary.com\u002Fdprnqhug7\u002Fimage\u002Fupload\u002Fv1693548383\u002Fngide\u002Frun-migration.png\"\u002F>\u003Cfigcaption>Hasil Migration.\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Cp>Selanjutnya adalah membuat model UserOTP dengan command \u003Ccode>php artisan make:model UserOTP\u003C\u002Fcode>\u003C\u002Fp>\u003Cp>Buka file \u003Ccode>UserOTP.php\u003C\u002Fcode> dan sesuaikan isinya seperti berikut:\u003C\u002Fp>\u003Cpre>\u003Ccode>&lt;?php\nnamespace App\\Models;\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\nclass UserOTP extends Model\n{\n    protected $table = 'user_otps';\n     \u002F**\n     * The attributes that are mass assignable.\n     *\n     * @var array&lt;int, string&gt;\n     *\u002F\n    protected $fillable = [\n        'otp_code',\n        'user_id',\n        'expired_at'\n    ];\n    public function user(){\n        return $this-&gt;belongsTo(User::class,'user_id');\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Langkah selanjutnya adalah menambahkan relasi activeOTP di model user.\u003C\u002Fp>\u003Cp>Buka file model User.php dan tambahkan relasi berikut:\u003C\u002Fp>\u003Cpre>\u003Ccode>public function activeOTP()\n    {\n        return $this-&gt;hasOne(UserOTP::class,'user_id')-&gt;where('expired_at','&gt;', 'now()');\n    }\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Nah model dan databasenya sudah siap, saatnya membuat alur untuk OTP nya.\u003C\u002Fp>\u003Ch3>Modifikasi Register Controller\u003C\u002Fh3>\u003Cp>Secara default, saat submit register, file yang digunakan adalah \u003Ccode>RegisteredUserController.php\u003C\u002Fcode> khususnya di method \u003Ccode>store()\u003C\u002Fcode>\u003C\u002Fp>\u003Cp>Sekarang buka file \u003Ccode>RegisteredUserController.php\u003C\u002Fcode>, kita akan melakukan sedikit perubahan di dalam method \u003Ccode>store()\u003C\u002Fcode>\u003C\u002Fp>\u003Cpre>\u003Ccode>\u002F**\n     * Handle an incoming registration request.\n     *\n     * @throws \\Illuminate\\Validation\\ValidationException\n     *\u002F\n    public function store(Request $request): RedirectResponse\n    {\n        $request-&gt;validate([\n            'name' =&gt; ['required', 'string', 'max:255'],\n            'email' =&gt; ['required', 'string', 'email', 'max:255', 'unique:'.User::class],\n            'password' =&gt; ['required', 'confirmed', Rules\\Password::defaults()],\n        ]);\n        $user = User::create([\n            'name' =&gt; $request-&gt;name,\n            'email' =&gt; $request-&gt;email,\n            'password' =&gt; Hash::make($request-&gt;password),\n        ]);\n        UserOTP::create([\n            'user_id' =&gt; $user-&gt;id,\n            'otp_code' =&gt; rand(100000,999999),\n            'expired_at' =&gt; Date::now()-&gt;addMinutes(5)\n        ]);\n        event(new Registered($user));\n        return redirect()-&gt;route('otp-verification', $user-&gt;id);\n    }\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Jadi saat register, kita akan membuat kode OTP yang akan dikirim ke email user.\u003C\u002Fp>\u003Cp>Kita perlu merubah alur verifikasi email yang dikirim melalui event \u003Ccode>Registered()\u003C\u002Fcode>.\u003C\u002Fp>\u003Ch3>Buat Listener dan Notification file Untuk Kirim OTP\u003C\u002Fh3>\u003Cp>Kita akan buat 2 file untuk listener dan notification mengirim kode OTP ke email user.\u003C\u002Fp>\u003Cp>Jalankan 2 command ini untuk membuat 2 file tersebut.\u003C\u002Fp>\u003Cp>\u003Ccode>php artisan make:listener SendOTPEventListener\u003C\u002Fcode>\u003C\u002Fp>\u003Cp>\u003Ccode>php artisan make:notification SendOTPNotification\u003C\u002Fcode>\u003C\u002Fp>\u003Cp>Buka file \u003Ccode>SendOTPEventNotification.php\u003C\u002Fcode> dan update isinya seperti dibawah ini:\u003C\u002Fp>\u003Cpre>\u003Ccode>&lt;?php\nnamespace App\\Notifications;\nuse Illuminate\\Bus\\Queueable;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Notifications\\Messages\\MailMessage;\nuse Illuminate\\Notifications\\Notification;\nclass SendOTPNotification extends Notification\n{\n    use Queueable;\n    public $otp;\n    \u002F**\n     * Create a new notification instance.\n     *\n     * @return void\n     *\u002F\n    public function __construct($otp)\n    {\n        $this-&gt;otp = $otp;\n    }\n    \u002F**\n     * Get the notification's delivery channels.\n     *\n     * @param  mixed  $notifiable\n     * @return array\n     *\u002F\n    public function via($notifiable)\n    {\n        return ['mail'];\n    }\n    \u002F**\n     * Get the mail representation of the notification.\n     *\n     * @param  mixed  $notifiable\n     * @return \\Illuminate\\Notifications\\Messages\\MailMessage\n     *\u002F\n    public function toMail($notifiable)\n    {\n        return (new MailMessage)\n                    -&gt;line('Your OTP code: '.$this-&gt;otp)\n                    -&gt;line('Thank you for using our application!');\n    }\n    \u002F**\n     * Get the array representation of the notification.\n     *\n     * @param  mixed  $notifiable\n     * @return array\n     *\u002F\n    public function toArray($notifiable)\n    {\n        return [\n            \u002F\u002F\n        ];\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>File ini akan bertugas untuk mengirimkan email ke user yang berisi kode OTP nantinya.\u003C\u002Fp>\u003Cp>Buka file \u003Ccode>SendOTPEventListener.php\u003C\u002Fcode> dan update isinya seperti dibawah ini:\u003C\u002Fp>\u003Cpre>\u003Ccode>&lt;?php\nnamespace App\\Listeners;\nuse App\\Notifications\\SendOTPNotification;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nclass SendOTPEventListener\n{\n    \u002F**\n     * Create the event listener.\n     *\n     * @return void\n     *\u002F\n    public function __construct()\n    {\n        \u002F\u002F\n    }\n    \u002F**\n     * Handle the event.\n     *\n     * @param  object  $event\n     * @return void\n     *\u002F\n    public function handle($event)\n    {\n        \n        $event-&gt;user-&gt;notify(new SendOTPNotification($event-&gt;user-&gt;activeOTP-&gt;otp_code));\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Langkah selanjutnya adalah kita perlu merubah listener saat Registered event dipanggil. \u003C\u002Fp>\u003Cp>Buka file \u003Ccode>EventServiceProvider.php\u003C\u002Fcode> dan edit dibagian listen-nya menjadi seperti dibawah ini:\u003C\u002Fp>\u003Cpre>\u003Ccode>&lt;?php\nnamespace App\\Providers;\nuse App\\Listeners\\SendOTPEventListener;\nuse Illuminate\\Auth\\Events\\Registered;\nuse Illuminate\\Auth\\Listeners\\SendEmailVerificationNotification;\nuse Illuminate\\Foundation\\Support\\Providers\\EventServiceProvider as ServiceProvider;\nuse Illuminate\\Support\\Facades\\Event;\nclass EventServiceProvider extends ServiceProvider\n{\n    \u002F**\n     * The event to listener mappings for the application.\n     *\n     * @var array&lt;class-string, array&lt;int, class-string&gt;&gt;\n     *\u002F\n    protected $listen = [\n        Registered::class =&gt; [\n            \u002F\u002F SendEmailVerificationNotification::class,\n            SendOTPEventListener::class\n        ],\n    ];\n    \u002F**\n     * Register any events for your application.\n     *\n     * @return void\n     *\u002F\n    public function boot()\n    {\n        \u002F\u002F\n    }\n    \u002F**\n     * Determine if events and listeners should be automatically discovered.\n     *\n     * @return bool\n     *\u002F\n    public function shouldDiscoverEvents()\n    {\n        return false;\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Jadi ceritanya nanti saat ada event \u003Ccode>Registered\u003C\u002Fcode>, app akan memanggil listener \u003Ccode>SendOTPEventListener\u003C\u002Fcode> untuk mengirim email notifikasi ke user. \u003C\u002Fp>\u003Cp>Desain seperti ini biasanya disebut sebagai \u003Ci>event driven pattern.\u003C\u002Fi>\u003C\u002Fp>\u003Ch3>Buat tampilan halaman OTP\u003C\u002Fh3>\u003Cp>Masih ingat dengan flow sebelumnya? \u003C\u002Fp>\u003Cp>Jadi saat selesai mengisi data registrasi, kita akan redirect ke halaman untuk mengisi kode OTP.\u003C\u002Fp>\u003Cp>Buat sebuah route dan \u003Ci>view\u003C\u002Fi> baru untuk tampilan form validasi kode OTP.\u003C\u002Fp>\u003Cp>Buka file \u003Ccode>web.php\u003C\u002Fcode> dan tambahkan \u003Ci>route\u003C\u002Fi> ini:\u003C\u002Fp>\u003Cpre>\u003Ccode>\u002F\u002F Route lainnya\nuse App\\Models\\User;\nRoute::get('\u002F{user_id}\u002Fotp-verification', function ($user_id) {\n    $user = User::find($user_id);\n    return view('otp-verification', compact('user'));\n    \n})-&gt;middleware([])-&gt;name('otp-verification');\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Selanjutnya buat sebuah \u003Ci>view\u003C\u002Fi> baru dengan nama \u003Ccode>otp-verification.blade.php\u003C\u002Fcode>\u003C\u002Fp>\u003Cpre>\u003Ccode>&lt;x-guest-layout&gt;\n    &lt;form method=\"POST\" action=\"{{ route('otp.validation', $user-&gt;id) }}\"&gt;\n        @csrf\n        \n        &lt;div&gt;\n            &lt;x-input-label for=\"otp\" :value=\"__('OTP CODE')\" \u002F&gt;\n            &lt;x-text-input id=\"otp\" class=\"block mt-1 w-full\" type=\"text\" name=\"otp_code\" required autofocus \u002F&gt;\n            &lt;x-input-error :messages=\"$errors-&gt;get('otp_code')\" class=\"mt-2\" \u002F&gt;\n        &lt;\u002Fdiv&gt;\n        &lt;div class=\"flex items-center justify-center mt-4\"&gt;\n            &lt;x-primary-button&gt;\n                {{ __('Validate OTP CODE') }}\n            &lt;\u002Fx-primary-button&gt;\n        &lt;\u002Fdiv&gt;\n    &lt;\u002Fform&gt;\n&lt;\u002Fx-guest-layout&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Jangan lupa buat 1 buah route baru lagi untuk menangani post data dan mengecek apakah kode OTP tersebut valid atau tidak.\u003C\u002Fp>\u003Cp>Buka lagi file \u003Ccode>web.php\u003C\u002Fcode> dan tambahkan route baru ini:\u003C\u002Fp>\u003Cpre>\u003Ccode>Route::post('\u002F{user_id}\u002Fotp-validation', function ($user_id, Request $request) {\n    $otp = UserOTP::where('otp_code', $request-&gt;otp_code)-&gt;where('expired_at','&gt;',now())-&gt;first();\n    if (!$otp) {\n        return redirect()-&gt;back()-&gt;withErrors([\n            'otp_code' =&gt; 'OTP CODE tidak ditemukan.'\n        ]);\n    }\n    $otp-&gt;user-&gt;email_verified_at = Date::now();\n    $otp-&gt;user-&gt;save();\n    Auth::login($otp-&gt;user);\n    return redirect(RouteServiceProvider::HOME);\n    \n})-&gt;middleware([])-&gt;name('otp.validation');\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Okay, semua proses untuk validasi sudah selesai\u003C\u002Fp>\u003Cp>Tampilannya kurang lebih seperti berikut ini.\u003C\u002Fp>\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Fres.cloudinary.com\u002Fdprnqhug7\u002Fimage\u002Fupload\u002Fv1693548370\u002Fngide\u002Fotp-view.png\"\u002F>\u003Cfigcaption>Input kode OTP\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Cp>Sekarang saatnya mencobanya ya.\u003C\u002Fp>\u003Cp>Silakan daftar dan jika berhasil akan dialihkan ke halaman kode OTP.\u003C\u002Fp>\u003Cp>Kode OTP bisa kalian cek di laravel.log untuk isi emailnya.\u003C\u002Fp>\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Fres.cloudinary.com\u002Fdprnqhug7\u002Fimage\u002Fupload\u002Fv1693548371\u002Fngide\u002Femail-log.png\"\u002F>\u003Cfigcaption>Contoh Kode OTP di email\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Cp>Jika sudah berhasil mengisi kode OTP, maka user akan otomatis terverifikasi dan langsung login ke dalam sistem.\u003C\u002Fp>\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Fres.cloudinary.com\u002Fdprnqhug7\u002Fimage\u002Fupload\u002Fv1693548370\u002Fngide\u002Fdashboard.png\"\u002F>\u003Cfigcaption>Halaman dashboard\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Ch3>Bagaimana cara validasi OTP?\u003C\u002Fh3>\u003Cp>OTP yang kita buat ini sangat simple. Konsepnya adalah mengganti verifikasi via link dengan kode OTP.\u003C\u002Fp>\u003Cp>Jadi saat verifikasi kode OTP, jika kode OTP benar, maka kita update field \u003Ccode>email_verified_at\u003C\u002Fcode> ke data saat itu juga.\u003C\u002Fp>\u003Cp>Dengan begitu, artinya user berhasil memverifikasi datanya dengan benar.\u003C\u002Fp>\u003Ch3>Kesimpulan\u003C\u002Fh3>\u003Cp>Jadi itulah cara membuat implementasi kode OTP di laravel dengan sederhana. Sebenarnya ada beberapa use case yang bisa dikembangkan lagi, misalnya bagaimana menghandle saat token OTPnya expired. Bisa juga dikembangkan menjadi tambahan security untuk login user, dimana selain login dengan password, perlu mengisi kode OTP juga saat login.\u003C\u002Fp>\u003Cp>Mungin nanti akan saya tambahkan beberapa use case lainnya di artikel lanjutkan mengenai cara membuat kode OTP dengan laravel.\u003C\u002Fp>\u003Cp>Semoga tutorial ini membantu ya.\u003C\u002Fp>\u003Cp>Oh iya, kalau mau nonton versi video, bisa tonton di youtube saya ya, ingat juga di subscribe :D\u003C\u002Fp>\n\u003C\u002Fp>\u003C\u002Fp>","Helo teman-teman, kali ini saya akan membahas bagaimana cara membuat kode OTP di PHP atau lebih tepatnya dengan menggunakan framework Laravel. Apa itu kode OTP?",[],[],0]