DEV Community

Cover image for Authentication with Laravel OTP
Fouladgar.dev
Fouladgar.dev

Posted on • Edited on

5 1

Authentication with Laravel OTP

Nowadays most web applications prefer to use OTP(One-Time Password) instead of using username/password which was a classic authentication system to validate users. Because, this way is more secure and in contrast to static passwords, they are not vulnerable to replay attacks.

Maybe you are also worried about implementing a one-time password as a web developer in the Laravel framework.

There are many concerns about that such as :

  • How can I generate a secure token?
  • Where should I store generated token?
  • Is token valid or not? Is token expired or not?
  • How can I have an integrated and also usable system for different user providers?
  • etc…

Well, good news! We have just released a package to resolve your concerns. Here you are. This is Laravel OTP package.

Let’s start a practical implementation step by step.

Getting started

First, you should install OTP package via composer:



composer require fouladgar/laravel-otp


Enter fullscreen mode Exit fullscreen mode

Then, publish config/otp.php file by running:



php artisan vendor:publish --provider="Fouladgar\OTP\ServiceProvider" --tag="config"


Enter fullscreen mode Exit fullscreen mode

And Finally migrate the database:



php artisan migrate


Enter fullscreen mode Exit fullscreen mode

Model Preparation

As next step, make sure the user model implement Fouladgar\OTP\Contracts\OTPNotifiable, and also use Fouladgar\OTP\Concerns\HasOTPNotify trait:

<?php
namespace App\Models;
use Fouladgar\OTP\Concerns\HasOTPNotify;
use Fouladgar\OTP\Contracts\OTPNotifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable implements OTPNotifiable
{
use Notifiable;
use HasOTPNotify;
// ...
}
view raw User.php hosted with ❤ by GitHub

SMS Client

There is a default OTPSMSChannel which needs a SMS client for sending generated token to the user mobile phone. So, you should specify your SMS client and implement Fouladgar\OTP\Contracts\SMSClient contract. This contract requires you to implement sendMessage method.

This method will return your SMS service API results via a Fouladgar\OTP\Notifications\Messages\MessagePayload object which contains user mobile and token message:

<?php
namespace App;
use Fouladgar\OTP\Contracts\SMSClient;
use Fouladgar\OTP\Notifications\Messages\MessagePayload;
class SampleSMSClient implements SMSClient
{
public function __construct(protected SampleSMSService $SMSService)
{
}
public function sendMessage(MessagePayload $payload): mixed
{
return $this->SMSService->send($payload->to(), $payload->content());
}
// ...
}

Next, you should set the client wrapper SampleSMSClient class in config/otp.php file:

<?php
return [
'sms_client' => App\SampleSMSClient::class,
//...
];

It’s almost over…

Setup Routes and Controller

We need some routes to send and validate the token. Let’s make them and implement our controller.

You may add those in the web or api routes. It depends on you want to use OTP as Full Stack or API Back-End. It’s up to you. In this article I prefer use the second way.

Well, open the routes/api.php and put this routes:

<?php
use App\Http\Controllers\AuthController;
use Illuminate\Support\Facades\Route;
Route::controller(AuthController::class)->group(function () {
Route::post('/send-otp', 'sendOTP');
Route::post('/validate-otp', 'verifyOTPAndLogin');
});
view raw otp_routes.php hosted with ❤ by GitHub

And then create a AuthController.php class like this:

<?php
namespace App\Http\Controllers;
use App\Models\User;
use Fouladgar\OTP\Exceptions\InvalidOTPTokenException;
use Fouladgar\OTP\OTPBroker as OTPService;
use Illuminate\Http\Request;
use Throwable;
class AuthController
{
public function __construct(private OTPService $OTPService)
{
}
public function sendOTP(Request $request)
{
// validate incoming requets.
try {
/** @var User $user */
$user = $this->OTPService->send($request->get('mobile'));
} catch (Throwable $ex) {
// or return a view.
return response()->json(['message'=>'An Occurred unexpected error.'], 500);
}
return response()->json(['message'=>'A token sent to:'. $user->mobile]);
}
public function verifyOTPAndLogin(Request $request)
{
// Validate incoming requests.
try {
/** @var User $user */
$user = $this->OTPService->validate($request->get('mobile'), $request->get('token'));
// and do login actions (session base or token base) ...
} catch (InvalidOTPTokenException $exception){
return response()->json(['error' => $exception->getMessage()], $exception->getCode());
} catch (Throwable $ex) {
return response()->json(['message' => 'An Occurred unexpected error.'], 500);
}
return response()->json(['message'=>'Login has been successfully.']);
}
}

Finish. Now, you can call the routes like below:


// send otp request
curl --request POST \
  --url http://localhost/api/send-otp \
  --data '{
 "mobile" : "09389599530"
}'

// validate otp request
curl --request POST \
  --url http://localhost:8585/api/validate-otp \
  --data '{
 "mobile" : "09389599530",
 "token" : "94352"
}'


Enter fullscreen mode Exit fullscreen mode

That’s it.

For more details, please check out the documentation in GitHub:

GitHub logo mohammad-fouladgar / laravel-otp

This package provides convenient methods for sending and validating OTP notifications to users for authentication.

Laravel OTP(One-Time Password)

Latest Version on Packagist Test Status Code Style Status Total Downloads

Introduction

Most web applications need an OTP(one-time password) or secure code to validate their users. This package allows you to send/resend and validate OTP for users authentication with user-friendly methods.

Version Compatibility

Laravel Laravel-OTP
11.0.x 4.2.x
10.0.x 4.0.x
9.0.x 3.0.x
6.0.x to 8.0.x 1.0.x

Basic Usage:

<?php
/*
|--------------------------------------------------------------------------
| Send OTP via SMS.
|--------------------------------------------------------------------------
*/
OTP()->send('+98900000000'); 
// Or
OTP('+98900000000');

/*
|--------------------------------------------------------------------------
| Send OTP via channels.
|--------------------------------------------------------------------------
*/
OTP()->channel(['otp_sms', 'mail', \App\Channels\CustomSMSChannel::class])
     ->send('+98900000000');
// Or
OTP('+98900000000', ['otp_sms', 'mail', \App\Channels\CustomSMSChannel::class]);

/*
|--------------------------------------------------------------------------
| Send OTP for specific user provider
|--------------------------------------------------------------------------
*/
OTP()->useProvider('
Enter fullscreen mode Exit fullscreen mode

Hope to useful this package. I’m waiting your opinions and comments.

Thank you for sharing your valuable time with me.

Retry later

Top comments (0)

Retry later
Retry later