Handle OTP Auth via your own source code

Laravel OTP AUTH

This package allows you to authenticate with one time password access (OTP).

https://github.com/cuongnd88/otp-auth

Example Usage:

Route::get(“/notify”, function(){
return App\Models\User::find(1)->notify(new App\…


This content originally appeared on DEV Community and was authored by Ngo Dinh Cuong

Laravel OTP AUTH

This package allows you to authenticate with one time password access (OTP).

https://github.com/cuongnd88/otp-auth

Example Usage:

Route::get("/notify", function(){
    return App\Models\User::find(1)->notify(new App\Authentication\SendOtp('mail', 4, 10));
});

Route::get("/auth-otp/{otp}", function(){
    return App\Models\User::authByOtp(request()->otp, '84905279285');
});

Route::get("/check-otp/{otp}", function(){
    return App\Models\User::find(1)->checkOtp(request()->otp);
});

Contents

Installation

1- Add the package to your dependencies.

$ composer require cuongnd88/otp-auth

2- Run the command:

php artisan auth:otp {ClassName}

Example:

php artisan auth:otp Authentication/SendOtp

SendOtp class and HasOtpAuth trait are auto-generated at app/Authentication directory.

CreateNotificationsTable class is alseo auto-generated at app/database/migrations.

3- Apply the migrations:

It will create a table called notifications to store generated OTP information.

$ php artisan migrate

Usage

Generate OTP

You can generate OTP via email or SMS

Route::get("/notify", function(){
    return App\Models\User::find(1)->notify(new App\Authentication\SendOtp(['mail', 'nexmo']));
});

This package allows you to alter OTP length and lifetime

Route::get("/notify", function(){
    $length = 4;
    $liftime = 10; //minutes
    return App\Models\User::find(1)->notify(new App\Authentication\SendOtp(['mail', 'nexmo']), $length, $liftime);
});

OTP default length: The default length is 6.

OTP default lifetime: The default lifetime is 1 minute.

There is the detail of auto-generate SentOTP class:

<?php

namespace App\Authentication;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Cuongnd88\DeliveryChannel\Messages\TwilioMessage;

class SendOtp extends Notification
{
    use Queueable;

    protected $defaultChannels = ['database'];

    protected $otp;

    protected $lifeTime;

    const OPT_LIFETIME = 1;

    const OPT_LENGTH = 6;

    /**
     * Construct
     *
     * @param array|string $channels
     * @param integer|string $otpLength
     * @param integer|string $lifeTime
     */
    public function __construct($channels = null, $otpLength = null, $lifeTime = null)
    {
        $this->otp = $this->generateOtp($otpLength ?? self::OPT_LENGTH);
        $this->lifeTime = $lifeTime ?? self::OPT_LIFETIME;
        $this->defaultChannels = $this->verifyChannels($channels);
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return $this->defaultChannels;
    }

    /**
     * Get the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        return (new MailMessage)
                    ->line('Your OTP is '.$this->otp)
                    ->line('Thank you for using our application!');
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            'otp' => $this->otp,
            'expired_at' => now()->addMinutes($this->lifeTime)->toDateTimeString(),
        ];
    }

    /**
     * Get the Nexmo / SMS representation of the notification.
     *
     * @param  mixed  $notifiable
     *
     * @return mixed
     */
    public function toTwilio($notifiable)
    {
        return (new TwilioMessage)
                    ->to("+8439xxxxxxx")
                    ->from("+xxxxxxxxxx")
                    ->body('OTP AUTH is '.$this->otp);
    }

    /**
     * Generate OTP
     *
     * @param integer|string $n
     *
     * @return string
     */
    public function generateOtp($n)
    {
        $generator = "0987654321";
        $result = "";

        for ($i = 1; $i <= $n; $i++) {
            $result .= substr($generator, (rand()%(strlen($generator))), 1);
        }
        return $result;
    }

    /**
     * Verify channels
     *
     * @param string|array $channels
     *
     * @return array
     */
    public function verifyChannels($channels)
    {
        if ($channels && is_array($channels)) {
            return array_merge($this->defaultChannels, $channels);
        }
        if ($channels && is_string($channels)) {
            array_push($this->defaultChannels, $channels);
        }
        return $this->defaultChannels;
    }
}

toTwilio: This method is implemented by importing delivery-channels.

Verify OTP

After sent OTP via your configed methods, you call authByOtp to authenticate

Route::get("/auth-otp/{otp}", function(){
    return App\Models\User::authByOtp(request()->otp, '84905123456');
});

Based on your credentials, you might authenticate with email or phone number

Set up the credentials:

In this case, you can apply User model which must use HasOtpAuth trait

. . . .
use App\Authentication\HasOtpAuth;

class User extends Authenticatable
{
    use Notifiable;
    use HasOtpAuth;

    protected $credential = 'mobile';

. . . .

Let see more detail HasOtpAuth trait

<?php

namespace App\Authentication;

trait HasOtpAuth
{
    /**
     * Check OTP
     *
     * @return bool
     */
    public function checkOtp($otp)
    {
        $authenticator = $this->otp();
        return $this->validateOtp($authenticator, $otp);
    }

    /**
     * Get OTP data
     *
     * @return \Illuminate\Notifications\DatabaseNotification
     */
    public function otp()
    {
        return $this->notifications()
                ->where('type', 'LIKE', '%SendOtp%')
                ->whereNull('read_at')
                ->first();
    }

    /**
     * Validate OTP
     *
     * @param \Illuminate\Notifications\DatabaseNotification $authenticator
     * @param mixed $otp
     *
     * @return void
     */
    public function validateOtp($authenticator, $otp)
    {
        $result = false;
        if (is_null($authenticator)) {
            return response()->json($result,200);
        }
        if ($authenticator
            && now()->lte($authenticator->data['expired_at'])
            && $authenticator->data['otp'] == $otp
        ) {
            $result = true;
        }
        $authenticator->markAsRead();
        return response()->json($result,200);
    }

    /**
     * Authenticate by OTP
     *
     * @param string $otp
     * @param string $credentialValue
     * @return void
     */
    public static function authByOtp($otp, $credentialValue)
    {
        $model = new static;
        $credentialName = property_exists($model,'credential') ? $model->credential : 'email';

        $authenticator = $model->where($credentialName, '=', $credentialValue)->first();
        if (is_null($authenticator)) {
            return response()->json(false,200);
        }

        $authenticator = $authenticator->notifications()
                    ->where('type', 'LIKE', '%SendOtp%')
                    ->whereNull('read_at')
                    ->first();

        return $model->validateOtp($authenticator, $otp);
    }
}

Basic identification

In some cases, you just need to identify the right access, you might need to execute checkOtp method

Route::get("/check-otp/{otp}", function(){
    return auth()->user->checkOtp(request()->otp);
});

Demo

This is demo soure code.
Laravel Colab

Credits

  • Ngo Dinh Cuong

LinkedIn


This content originally appeared on DEV Community and was authored by Ngo Dinh Cuong


Print Share Comment Cite Upload Translate Updates
APA

Ngo Dinh Cuong | Sciencx (2021-08-17T01:38:44+00:00) Handle OTP Auth via your own source code. Retrieved from https://www.scien.cx/2021/08/17/handle-otp-auth-via-your-own-source-code/

MLA
" » Handle OTP Auth via your own source code." Ngo Dinh Cuong | Sciencx - Tuesday August 17, 2021, https://www.scien.cx/2021/08/17/handle-otp-auth-via-your-own-source-code/
HARVARD
Ngo Dinh Cuong | Sciencx Tuesday August 17, 2021 » Handle OTP Auth via your own source code., viewed ,<https://www.scien.cx/2021/08/17/handle-otp-auth-via-your-own-source-code/>
VANCOUVER
Ngo Dinh Cuong | Sciencx - » Handle OTP Auth via your own source code. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/08/17/handle-otp-auth-via-your-own-source-code/
CHICAGO
" » Handle OTP Auth via your own source code." Ngo Dinh Cuong | Sciencx - Accessed . https://www.scien.cx/2021/08/17/handle-otp-auth-via-your-own-source-code/
IEEE
" » Handle OTP Auth via your own source code." Ngo Dinh Cuong | Sciencx [Online]. Available: https://www.scien.cx/2021/08/17/handle-otp-auth-via-your-own-source-code/. [Accessed: ]
rf:citation
» Handle OTP Auth via your own source code | Ngo Dinh Cuong | Sciencx | https://www.scien.cx/2021/08/17/handle-otp-auth-via-your-own-source-code/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.