{"id":20408347,"url":"https://github.com/brackets-by-triad/verifications","last_synced_at":"2025-08-20T00:08:22.357Z","repository":{"id":47966079,"uuid":"331240207","full_name":"BRACKETS-by-TRIAD/verifications","owner":"BRACKETS-by-TRIAD","description":"Two Factor Authentication (2FA) and code-based verification of actions (sms or email) for Laravel","archived":false,"fork":false,"pushed_at":"2023-07-25T15:49:28.000Z","size":180,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-12-30T14:31:50.905Z","etag":null,"topics":[],"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/BRACKETS-by-TRIAD.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-20T08:26:08.000Z","updated_at":"2023-01-19T16:19:42.000Z","dependencies_parsed_at":"2024-11-15T05:40:30.831Z","dependency_job_id":null,"html_url":"https://github.com/BRACKETS-by-TRIAD/verifications","commit_stats":{"total_commits":120,"total_committers":5,"mean_commits":24.0,"dds":0.6083333333333334,"last_synced_commit":"00640f489603b3b6ee3d9eb0fddb13a0285cde76"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BRACKETS-by-TRIAD%2Fverifications","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BRACKETS-by-TRIAD%2Fverifications/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BRACKETS-by-TRIAD%2Fverifications/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BRACKETS-by-TRIAD%2Fverifications/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BRACKETS-by-TRIAD","download_url":"https://codeload.github.com/BRACKETS-by-TRIAD/verifications/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241953041,"owners_count":20048116,"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":[],"created_at":"2024-11-15T05:30:16.281Z","updated_at":"2025-03-05T02:29:31.483Z","avatar_url":"https://github.com/BRACKETS-by-TRIAD.png","language":"PHP","readme":"# Verifications\nThis package should be used for a code-based verification of actions (typically routes).\n\nCurrently packages supports two channels for sending verification codes:\n\n- sms\n- email\n\nbut it's easy to extend the package to support custom channels.\n\nPackages ships also with a simple frontend (screen where user can input the code + default email/sms template) that could be easily overridden to meet your UX.\n\nPackage can help you also with a special case of a verification - the [Two-factor authentication](#markdown-header-two-factor-authentication). \n\n## Installation\n\n1. `composer require brackets/verifications`\n\n2. `php artisan verifications:install`\n\n## Usage\n\n### Implementing Verifiable\nFirst of all, you need to have an authenticated user (i.e. User model) that implements **Verifiable** interface and use **VerifiableTrait**. You need to either define attribute/s `email` and/or `phone` on the model or implement accessor methods `getPhoneAttribute()`/`getEmailAttribute()`.\n\nNote: If you need to insert **phone_number**/**email** attributes to your `user` table, you can use artisan commands `verifications:add-email {table-name}` and/or `verifications:add-phone {table-name}`. \n\n### Configuration\nThen you need to define an action that would require verification.\n\nThis can be achieved in the configuration file `/config/verifications.php`. \n \n```php\n    'enabled' =\u003e env('VERIFICATION_ENABLED', true),                     // you can enable/disable globally (i.e. disabled for tests/dev env)\n    'actions' =\u003e [\n        'my-action' =\u003e [\n            'enabled' =\u003e true,                                          // you can enable/disable single action\n            'channel' =\u003e 'sms',                                         // currently: sms, email\n            'form_template' =\u003e 'brackets/verifications::verification',  // blade name with namespace used for verification code form\n            'expires_in' =\u003e 15,                                         // specifies how many minutes does it take to require another code verification for the same action\n            'expires_from' =\u003e 'verification',                           // one of: 'last-activity' or 'verification', specifies what triggers the expiration (see expires_in)\n            'code' =\u003e [\n                'type' =\u003e 'numeric',                                    // specifies the type of verification code, can be one of: 'numeric' or 'string'\n                'length' =\u003e 6,                                          // specifies the verification code length, defaults to 6\n                'expires_in' =\u003e 10,                                     // specifies how many minutes is the code valid\n            ]\n        ]\n    ]\n```\n\n### GET request verification\nTypically you use this package to protect the entrance to some specific area of the application.\nThis can be done by protecting all the routes using **VerificationMiddleware** middleware:\n\n```php\nRoute::middleware('verifications.verify:{my-action}')\n```\n\n**Example:**  \nLet's say we want to verify the secret **money-balance** screen.\n\nDefine the action in your config:\n```php\n    'enabled' =\u003e env('VERIFICATION_ENABLED', true),\n    'actions' =\u003e [\n        'money-balance' =\u003e [\n            'enabled' =\u003e true,\n            'channel' =\u003e 'sms',\n            'form_template' =\u003e 'brackets/verifications::verification',\n            'expires_in' =\u003e 15,\n            'expires_from' =\u003e 'verification',\n            'code' =\u003e [\n                'type' =\u003e 'numeric',\n                'length' =\u003e 6,\n                'expires_in' =\u003e 10,\n            ]\n        ]\n    ]\n```\n\nAnd protect the route: \n\n```php\nRoute::get('/{account}/money-balance', 'MoneyController@moneyBalance')\n    -\u003ename('money-balance')\n    -\u003emiddleware('verifications.verify:money-balance');\n```\n\nWhen User tries to go to the `/{account}/money-balance` URL, he will be redirected to the verification screen where he is required to provide a code that was sent to him. \n\n### POST request verification\n\nVerifying POST actions is a bit more tricky because user cannot be redirected back to the POST request (this is technically impossible).\n\nOf course you can block the access to some POST action until user verifies it. Once he does verify it, everything works for him smoothly.\n\n**You should always create a GET route displaying a screen where User can perform the action and protect this GET route too (meaning protecting the entrance into the area, where he can perform the POST action).** In that case, User never experience weird behaviour of needing to click to the same action twice.   \n\nYou have two options here:\n\n1. either make sure User is always verified on some GET route *before* he performs the POST action (so limit the entrance to some area, where he can perform the POST actions),\n2. or crete a pseudo-screen with with some handy JavaScript, that will auto-run the POST request on User's behalf on load, so he doesn't have to click twice\n\nWhich option to use depends on your exact use case. But typically, if the action requires User to input some data to the form, the _showForm_ GET route should be always protected, etc.\n\n**Example:**  \nLet's continue with our MoneyApp example, but now we want to protect the **money-withdraw** action.\n\nThe protection of a POST route is very similar:\n```php\nRoute::post('/{account}/money-withdraw', 'MoneyController@moneyWithdraw')\n    -\u003ename('money-withdraw')\n    -\u003emiddleware('verifications.verify:money-withdraw');\n```\n\nThis will definitely prevent withdrawing the money for the unverified user. But it doesn't solve the redirect problem. Let's do it.\n\nIf we think about it, we actually want to protect the GET route for money withdraw feature, not only the final submit button. \n\nSo let's add a GET route:\n```php\nRoute::get('/{account}/money-withdraw', 'MoneyController@moneyWithdrawForm')\n    -\u003ename('money-withdraw-form')\n    -\u003emiddleware('verifications.verify:money-withdraw');\n\nRoute::post('/{account}/money-withdraw', 'MoneyController@moneyWithdraw')\n    -\u003ename('money-withdraw')\n    -\u003emiddleware('verifications.verify:money-withdraw');\n```\n\nMethod `moneyWithdrawForm` will display the blade view with the form that will perform the POST to `/{account}/money-withdraw` on submit. But User is verified ahead, in the GET route, so his UX will be smooth.\n\nTip: you can of course add middleware to the whole group of routes:\n```php\nRoute::middleware(['verifications.verify:money-balance'])-\u003egroup(static function () {\n    Route::get('/{account}/money-balance', 'MoneyController@moneyBalance')\n        -\u003ename('money-balance');\n        \n    Route::get('/{account}/money-withdraw', 'MoneyController@moneyWithdrawAutoConfirmator')\n        -\u003ename('money-withdraw-auto-confirmator');\n        \n    Route::post('/{account}/money-withdraw', 'MoneyController@moneyWithdraw')\n        -\u003ename('money-withdraw');\n    // ...\n});\n```\n\n### Advanced customization use case\n\nIn some scenarios you may want to use the verification on some action and needs further customization (i.e. only verify if some other conditions are met or provide a custom redirectTo method for POST actions verifications). You may use the Verification facade to manually run the verification in your controller providing the closure that will be run only after successful verification:\n\n```php\npublic function postDownloadInvoice(Invoice $invoice)\n{\n    // this code will run on the attempt before the verification and then again, after the successful verification\n    if (!$invoice-\u003eisPublished()) {\n        throw new InvoiceNotPublishedException();  \n    }  \n\n    return Verification::verify('download-invoice',             // name of the action\n                                '/invoices',                    // URL user will be redirect after verification (he must click to download the invoice again manually :( \n                                function () use ($invoice) {\n                                    // on the other hand this code will run only once, after the verification\n                                    return $invoice-\u003edownload();\n                                });\n}\n``` \n\n**Note, that even in this scenario, you need to protect the GET route before the POST, otherwise User won't be able to be redirected to the verification prompt screen, he will not be able to proceed.**\n\n### Customizing the views\n\nTo customized the default blade views you just need to publish them using:\n\n```php\nphp artisan vendor:publish --provider=\"Brackets\\Verifications\\VerificationServiceProvider\" --tag=\"views\"\n```\n\n### Conditional verification\n\nIn some cases, you may want to provide an option for your users to choose if they should verify some specific action.\nOr maybe you want to allow users with some specific role/permission to skip the verification for some specific action.\nIn these cases you just need to define the strictly named method **isVerificationRequired(string $action)**.\n\n**Example:**\n```php\nclass User extends Authenticatable implements Verifiable\n{\n    use VerifiableTrait;\n    // ...\n\n    public function isVerificationRequired($action) {\n    \n        // allow super admin to all actions\n        if ($this-\u003ehasRole('Admin') {\n            return false;\n        }\n    \n        if ($action == 'withdraw-money') {\n            // allow withdraw-money action to be optional (i.e. user can set it in their profile)\n            if (!$this-\u003ewithdraw_monoey_requires_verification) {\n                return false;\n            }        \n        }\n        \n        return true; \n    }\n```\n\n### Two factor authentication\n\nSpecial case for the use of this package is Two-Factor Authentication.\n\nImagine simple scenario when 2FA is required for all users.\n\nFirst, add new 2FA action to the config:\n\n```php\n    'actions' =\u003e [\n        '2FA' =\u003e [\n            'enabled' =\u003e true,\n            'channel' =\u003e 'sms',\n            'expires_in' =\u003e 15,\n            'expires_from' =\u003e 'last_activity', \n            'code' =\u003e [\n                // ...\n            ],\n        ],\n    ]\n```\n\nAnd then protect all your routes:\n\n```php\nRoute::middleware([‘verifications.verify:2FA’])-\u003egroup(function() {\n\n    // all your routes goes here\n    \n})\n``` \n\n## Channels\n\nThe packages ships with two default channels - email and sms.\n\n### Email\n\nThe package uses the default Laravel's [Mail](https://laravel.com/docs/mail). facade to send emails, so be sure to configure it properly.\n\n### SMS\n\nThe package ships with the one SMS provider - Twilio.\n\nTo use Twilio, you just need to provide these variables in your `.env` file:\n\n```.\nTWILIO_SID=\"INSERT YOUR TWILIO SID HERE\"\nTWILIO_AUTH_TOKEN=\"INSERT YOUR TWILIO TOKEN HERE\"\nTWILIO_NUMBER=\"INSERT YOUR TWILIO NUMBER IN [E.164] FORMAT\"\n```\n\nCheck out [this blogpost](https://www.twilio.com/blog/create-sms-portal-laravel-php-twilio) to find out more info about the Twilio integration.\n\n\n## Security\n\nIf you discover any security related issues, please email [pavol.perdik@brackets.sk](mailto:pavol.perdik@brackets.sk) instead of using the issue tracker.\n\n## Credits\n\n- [Miroslav Trnavsky](https://github.com/miroslavtrnavsky)\n- [Pavol Perdik](https://github.com/palypster)\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrackets-by-triad%2Fverifications","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrackets-by-triad%2Fverifications","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrackets-by-triad%2Fverifications/lists"}