{"id":26292391,"url":"https://github.com/cuongdinhngo/otp-auth","last_synced_at":"2025-10-26T13:37:15.629Z","repository":{"id":49733143,"uuid":"375565282","full_name":"cuongdinhngo/otp-auth","owner":"cuongdinhngo","description":"The OTP Auth package allows you to authenticate with one time password access (OTP)","archived":false,"fork":false,"pushed_at":"2021-09-06T14:32:01.000Z","size":33,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-08T05:44:48.387Z","etag":null,"topics":["authentication","laravel","otp","self"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cuongdinhngo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-06-10T04:05:31.000Z","updated_at":"2023-05-25T14:20:04.000Z","dependencies_parsed_at":"2022-09-01T05:02:48.185Z","dependency_job_id":null,"html_url":"https://github.com/cuongdinhngo/otp-auth","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cuongdinhngo%2Fotp-auth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cuongdinhngo%2Fotp-auth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cuongdinhngo%2Fotp-auth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cuongdinhngo%2Fotp-auth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cuongdinhngo","download_url":"https://codeload.github.com/cuongdinhngo/otp-auth/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253009843,"owners_count":21839713,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","laravel","otp","self"],"created_at":"2025-03-15T01:35:38.097Z","updated_at":"2025-10-26T13:37:15.530Z","avatar_url":"https://github.com/cuongdinhngo.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Laravel OTP AUTH\n\nThis package allows you to authenticate with one time password access (OTP).\n\nExample Usage:\n\n```php\nRoute::get(\"/notify\", function(){\n    return App\\Models\\User::find(1)-\u003enotify(new App\\Authentication\\SendOtp('mail', 4, 10));\n});\n\nRoute::get(\"/auth-otp/{otp}\", function(){\n    return App\\Models\\User::authByOtp(request()-\u003eotp, '84905.......');\n});\n\nRoute::get(\"/check-otp/{otp}\", function(){\n    return App\\Models\\User::find(1)-\u003echeckOtp(request()-\u003eotp);\n});\n```\n\n## Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n\t- [Generate OTP](#generate-otp)\n\t- [Verify OTP](#verify-otp)\n\t- [Basic identification](#basic-identification)\n    - [Demo](#demo)\n- [Credits](#credits)\n\n\n## Installation\n\n1- Add the package to your dependencies.\n\n```\n$ composer require cuongdinhngo/otp-auth\n```\n\n2- Run the command:\n\n```php\nphp artisan auth:otp {ClassName}\n```\n\nExample:\n\n```php\nphp artisan auth:otp Authentication/SendOtp\n```\n\n_`SendOtp` class and `HasOtpAuth` trait are auto-generated at `app/Authentication` directory._\n\n_`CreateNotificationsTable` class is alseo auto-generated at `app/database/migrations`._\n\n\n3- Apply the migrations:\n\n_It will create a table called `notifications` to store generated OTP information._\n\n```\n$ php artisan migrate\n```\n\n\n## Usage\n\n### Generate OTP\n\nYou can generate OTP via email or SMS\n\n```php\nRoute::get(\"/notify\", function(){\n    return App\\Models\\User::find(1)-\u003enotify(new App\\Authentication\\SendOtp(['mail', 'nexmo']));\n});\n```\n\nThis package allows you to alter OTP length and lifetime\n\n```php\nRoute::get(\"/notify\", function(){\n\t$length = 4;\n\t$liftime = 10; //minutes\n    return App\\Models\\User::find(1)-\u003enotify(new App\\Authentication\\SendOtp(['mail', 'nexmo']), $length, $liftime);\n});\n```\n\n\n**OTP default length**: The default length is `6`.\n\n**OTP default lifetime**: The default lifetime is `1` minute.\n\nThere is the detail of auto-generate `SentOTP` class:\n\n```php\n\u003c?php\n\nnamespace App\\Authentication;\n\nuse Illuminate\\Bus\\Queueable;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Notifications\\Messages\\MailMessage;\nuse Illuminate\\Notifications\\Notification;\nuse Cuongnd88\\DeliveryChannel\\Messages\\TwilioMessage;\n\nclass SendOtp extends Notification\n{\n    use Queueable;\n\n    protected $defaultChannels = ['database'];\n\n    protected $otp;\n\n    protected $lifeTime;\n\n    const OPT_LIFETIME = 1;\n\n    const OPT_LENGTH = 6;\n\n    /**\n     * Construct\n     *\n     * @param array|string $channels\n     * @param integer|string $otpLength\n     * @param integer|string $lifeTime\n     */\n    public function __construct($channels = null, $otpLength = null, $lifeTime = null)\n    {\n        $this-\u003eotp = $this-\u003egenerateOtp($otpLength ?? self::OPT_LENGTH);\n        $this-\u003elifeTime = $lifeTime ?? self::OPT_LIFETIME;\n        $this-\u003edefaultChannels = $this-\u003everifyChannels($channels);\n    }\n\n    /**\n     * Get the notification's delivery channels.\n     *\n     * @param  mixed  $notifiable\n     * @return array\n     */\n    public function via($notifiable)\n    {\n        return $this-\u003edefaultChannels;\n    }\n\n    /**\n     * Get the mail representation of the notification.\n     *\n     * @param  mixed  $notifiable\n     * @return \\Illuminate\\Notifications\\Messages\\MailMessage\n     */\n    public function toMail($notifiable)\n    {\n        return (new MailMessage)\n                    -\u003eline('Your OTP is '.$this-\u003eotp)\n                    -\u003eline('Thank you for using our application!');\n    }\n\n    /**\n     * Get the array representation of the notification.\n     *\n     * @param  mixed  $notifiable\n     * @return array\n     */\n    public function toArray($notifiable)\n    {\n        return [\n            'otp' =\u003e $this-\u003eotp,\n            'expired_at' =\u003e now()-\u003eaddMinutes($this-\u003elifeTime)-\u003etoDateTimeString(),\n        ];\n    }\n\n    /**\n     * Get the Nexmo / SMS representation of the notification.\n     *\n     * @param  mixed  $notifiable\n     *\n     * @return mixed\n     */\n    public function toTwilio($notifiable)\n    {\n        return (new TwilioMessage)\n                    -\u003eto(\"+8439xxxxxxx\")\n                    -\u003efrom(\"+xxxxxxxxxx\")\n                    -\u003ebody('OTP AUTH is '.$this-\u003eotp);\n    }\n\n    /**\n     * Generate OTP\n     *\n     * @param integer|string $n\n     *\n     * @return string\n     */\n    public function generateOtp($n)\n    {\n        $generator = \"09xxxxxxx\";\n        $result = \"\";\n\n        for ($i = 1; $i \u003c= $n; $i++) {\n            $result .= substr($generator, (rand()%(strlen($generator))), 1);\n        }\n        return $result;\n    }\n\n    /**\n     * Verify channels\n     *\n     * @param string|array $channels\n     *\n     * @return array\n     */\n    public function verifyChannels($channels)\n    {\n        if ($channels \u0026\u0026 is_array($channels)) {\n            return array_merge($this-\u003edefaultChannels, $channels);\n        }\n        if ($channels \u0026\u0026 is_string($channels)) {\n            array_push($this-\u003edefaultChannels, $channels);\n        }\n        return $this-\u003edefaultChannels;\n    }\n}\n\n```\n\n**toTwilio**: This method is implemented by importing [delivery-channels](https://github.com/cuongdinhngo/delivery-channels).\n\n### Verify OTP\n\nAfter sent OTP via your configed methods, you call `authByOtp` to authenticate\n\n```php\nRoute::get(\"/auth-otp/{otp}\", function(){\n    return App\\Models\\User::authByOtp(request()-\u003eotp, '84905123456');\n});\n```\nBased on your credentials, you might authenticate with email or phone number\n\n#### Set up the credentials:\n\nIn this case, you can apply `User` model which must use `HasOtpAuth` trait\n\n```php\n. . . .\nuse App\\Authentication\\HasOtpAuth;\n\nclass User extends Authenticatable\n{\n    use Notifiable;\n    use HasOtpAuth;\n\n    protected $credential = 'mobile';\n\n. . . .\n```\n\nLet see more detail `HasOtpAuth` trait\n\n```php\n\u003c?php\n\nnamespace App\\Authentication;\n\ntrait HasOtpAuth\n{\n    /**\n     * Check OTP\n     *\n     * @return bool\n     */\n    public function checkOtp($otp)\n    {\n        $authenticator = $this-\u003eotp();\n        return $this-\u003evalidateOtp($authenticator, $otp);\n    }\n\n    /**\n     * Get OTP data\n     *\n     * @return \\Illuminate\\Notifications\\DatabaseNotification\n     */\n    public function otp()\n    {\n        return $this-\u003enotifications()\n                -\u003ewhere('type', 'LIKE', '%SendOtp%')\n                -\u003ewhereNull('read_at')\n                -\u003efirst();\n    }\n\n    /**\n     * Validate OTP\n     *\n     * @param \\Illuminate\\Notifications\\DatabaseNotification $authenticator\n     * @param mixed $otp\n     *\n     * @return void\n     */\n    public function validateOtp($authenticator, $otp)\n    {\n        $result = false;\n        if (is_null($authenticator)) {\n            return response()-\u003ejson($result,200);\n        }\n        if ($authenticator\n            \u0026\u0026 now()-\u003elte($authenticator-\u003edata['expired_at'])\n            \u0026\u0026 $authenticator-\u003edata['otp'] == $otp\n        ) {\n            $result = true;\n        }\n        $authenticator-\u003emarkAsRead();\n        return response()-\u003ejson($result,200);\n    }\n\n    /**\n     * Authenticate by OTP\n     *\n     * @param string $otp\n     * @param string $credentialValue\n     * @return void\n     */\n    public static function authByOtp($otp, $credentialValue)\n    {\n        $model = new static;\n        $credentialName = property_exists($model,'credential') ? $model-\u003ecredential : 'email';\n\n        $authenticator = $model-\u003ewhere($credentialName, '=', $credentialValue)-\u003efirst();\n        if (is_null($authenticator)) {\n            return response()-\u003ejson(false,200);\n        }\n\n        $authenticator = $authenticator-\u003enotifications()\n                    -\u003ewhere('type', 'LIKE', '%SendOtp%')\n                    -\u003ewhereNull('read_at')\n                    -\u003efirst();\n\n        return $model-\u003evalidateOtp($authenticator, $otp);\n    }\n}\n```\n\n### Basic identification\n\nIn some cases, you just need to identify the right access, you might need to execute `checkOtp` method\n\n```php\nRoute::get(\"/check-otp/{otp}\", function(){\n    return auth()-\u003euser-\u003echeckOtp(request()-\u003eotp);\n});\n```\n\n### Demo\n\nThis is demo soure code.\n[Laravel Colab](https://github.com/cuongdinhngo/lara-colab/blob/master/alpha/routes/web.php)\n\n## Credits\n\n- Ngo Dinh Cuong\n\n[LinkedIn](https://www.linkedin.com/in/ngodinhcuong/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcuongdinhngo%2Fotp-auth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcuongdinhngo%2Fotp-auth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcuongdinhngo%2Fotp-auth/lists"}