asgarihope/pretty-otp

Maintainers

Package info

github.com/asgarihope/pretty-otp

pkg:composer/asgarihope/pretty-otp

Transparency log

Statistics

Installs: 4

Dependents: 0

Suggesters: 0

Stars: 3

Open Issues: 0

V1.0.0 2024-12-21 14:47 UTC

This package is auto-updated.

Last update: 2026-06-22 10:15:41 UTC


README

PrettyOtp is a Laravel package designed to simplify the implementation of OTP (One-Time Password) mechanisms for authentication and other secure actions.

Requirements

  • PHP >= 8.2
  • Laravel 6.x – 13.x

The package is tested against Laravel 6 through 13. Laravel 11+ requires PHP 8.2+, which is the minimum PHP version for this package.

Installation

Install the package via Composer:

composer require asgarihope/pretty-otp

The service provider (PrettyOtp\Laravel\Providers\PrettyOtpServiceProvider) is auto-discovered by Laravel. If you have disabled package discovery, register it manually in config/app.php (Laravel 10 and below) under providers.

Configuration

Publish the package configuration file:

php artisan vendor:publish --tag=otp-config

This will create a configuration file at config/otp.php:

return [
    'otp_expiry'     => 5,  // OTP validity time in minutes
    'otp_attempts'   => 5,  // Maximum allowed validation attempts per OTP
    'otp_length'     => 6,  // Number of digits in the generated OTP
    'otp_retry_time' => 2,  // Cooldown (in minutes) before a new OTP can be requested
];
Key Description
otp_expiry How long (in minutes) a generated OTP stays valid.
otp_attempts Maximum number of failed validation attempts before the user is locked out and must request a new OTP.
otp_length The number of digits used when generating the OTP.
otp_retry_time Minimum wait time (in minutes) between two OTP requests for the same segment/mobile.

Middleware

The package provides an otp middleware alias backed by OtpMiddleware to secure routes.

Example Usage

In your routes/web.php or routes/api.php, apply the middleware:

use Illuminate\Support\Facades\Route;

Route::middleware(['otp:mobile,login'])->group(function () {
    Route::post('/secure-action', [SecureController::class, 'handle']);
});

Middleware Parameters

The middleware accepts up to three comma-separated parameters: otp:key,segment,lifetimeInHours

  • key (required): The request input name that holds the identifier (e.g. mobile).
  • segment (required): A string identifying the OTP usage context (e.g. login, reset-password).
  • lifetimeInHours (optional): How many hours access is granted after a successful validation. When omitted (or null), access is granted indefinitely until explicitly revoked.
// Access granted for 3 hours after a valid OTP
Route::middleware(['otp:mobile,login,3'])->post('/secure-action', ...);

Response Metadata

When the middleware short-circuits (OTP required, invalid, locked, etc.), it returns a JSON response that includes two helpful fields alongside the message/error:

{
    "message": "OTP sent to 0912xxxxxxx. Please verify.",
    "time_remain": 120,
    "remain_attempt": 5
}
  • time_remain: seconds left before a new OTP can be requested.
  • remain_attempt: remaining validation attempts for the current OTP.

Events and Listeners

The package dispatches an OtpRequested event whenever an OTP is requested. Listen to this event to define your custom delivery logic (SMS, email, etc.).

OtpRequested Event

Event Properties

  • $mobile: The identifier (e.g. mobile number) for which the OTP is requested.
  • $key: The request parameter key used for the identifier.
  • $segment: The OTP usage context.

Implementing a Listener

The package ships an abstract SendOtpListener that already generates the OTP (via OtpService) and builds the message. You only need to implement the sendNotification method:

namespace App\Listeners;

use PrettyOtp\Laravel\Listeners\SendOtpListener;

class MyOtpListener extends SendOtpListener
{
    public function sendNotification(string $key, string $inputValue, string $message): void
    {
        // Send $message to $inputValue via your SMS/email provider.
        SmsGateway::send($inputValue, $message);
    }
}

Note: SendOtpListener::handle() calls OtpService::generateOtp(), which both stores the OTP in cache and records its sent-at timestamp. You should not generate or store the OTP yourself.

If you want to use your own listener instead, register it for PrettyOtp\Laravel\Events\OtpRequested in your EventServiceProvider and call $otpService->generateOtp($event->mobile, $event->segment) inside it.

Service Provider

The PrettyOtpServiceProvider automatically:

  • Registers the otp middleware alias.
  • Registers the OtpRequestedSendOtpListener binding.
  • Merges the default otp config.
  • Publishes the configuration and translation files.

Translation

Package translations are registered under the pretty-otp namespace and work out of the box without publishing. The middleware uses keys like trans('pretty-otp::otp.invalid_otp').

To customize the messages, publish the translations:

php artisan vendor:publish --tag=otp-translations

Published files land in lang/vendor/pretty-otp/<locale>/otp.php (or resources/lang/vendor/pretty-otp/... on older Laravel versions) and override the package defaults.

Available locales: en, fa.

Example Flow

  1. Request OTP — A request to a protected route without a valid otp input triggers the OtpRequested event. The configured listener generates and delivers the OTP.
  2. Validate OTP — The client sends the same request again, now including the otp input. The middleware validates it and grants access on success.
  3. Access Grant — On success, access is granted for the configured lifetimeInHours (or indefinitely when omitted). Subsequent requests within the lifetime skip OTP validation.

Cache Storage

The package uses Laravel's cache to store OTPs, attempt counters, sent-at timestamps, and access grants. Configure your preferred cache driver in config/cache.php.

Contribution

Contributions are welcome! Feel free to submit a pull request or report issues in the repository.

License

This package is open-sourced software licensed under the MIT license.