├── .gitignore
├── tests
├── temp
│ └── .gitignore
├── TwoFactorAuthenticationTest.php
└── BaseTestCase.php
├── .travis.yml
├── src
├── Contracts
│ └── TwoFactorAuthenticationInterface.php
├── Http
│ └── Controllers
│ │ ├── Controller.php
│ │ └── TwoFactorAuthenticationController.php
├── RedirectUsers2FA.php
├── Exceptions
│ └── TwoFactorAuthenticationExceptions.php
├── routes
│ └── routes.php
├── TwoFactorAuthenticationServiceProvider.php
└── AuthenticatesUsersWith2FA.php
├── .codeclimate.yml
├── phpunit.xml
├── LICENSE
├── database
└── migrations
│ └── 2017_01_20_160000_add_two_factor_authentication_required_fields.php
├── composer.json
├── resources
└── views
│ ├── verify.blade.php
│ └── setup.blade.php
├── config
└── 2fa-config.php
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
--------------------------------------------------------------------------------
/tests/temp/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 7.1
5 |
6 | before_script:
7 | - travis_retry composer self-update
8 | - travis_retry composer install --prefer-source --no-interaction
9 |
10 | script: phpunit
11 |
--------------------------------------------------------------------------------
/src/Contracts/TwoFactorAuthenticationInterface.php:
--------------------------------------------------------------------------------
1 | intended($this->redirectPath());
13 | }
14 | return redirect()->intended(config('2fa-config.redirect_to'));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Exceptions/TwoFactorAuthenticationExceptions.php:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 | tests
14 |
15 |
16 |
17 |
18 | src/
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tests/TwoFactorAuthenticationTest.php:
--------------------------------------------------------------------------------
1 | user = \DB::table('users')->first();
14 | $this->assertEquals(1, $this->user->id);
15 | }
16 |
17 | public function testIfColumnExists()
18 | {
19 | $this->assertTrue(Schema::hasColumn(config('2fa-config.table'), 'two_factor_provisioned_uri'));
20 | $this->assertTrue(Schema::hasColumn(config('2fa-config.table'), 'is_two_factor_enabled'));
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/routes/routes.php:
--------------------------------------------------------------------------------
1 | ['web'], 'namespace' => '\Thecodework\TwoFactorAuthentication\Http\Controllers'], function () {
4 | Route::get(config('2fa-config.verify_2fa'), 'TwoFactorAuthenticationController@verifyTwoFactorAuthentication');
5 | Route::post(config('2fa-config.verify_2fa_post'), 'TwoFactorAuthenticationController@verifyToken');
6 | Route::get(config('2fa-config.setup_2fa'), 'TwoFactorAuthenticationController@setupTwoFactorAuthentication');
7 | Route::post(config('2fa-config.enable_2fa'), 'TwoFactorAuthenticationController@enableTwoFactorAuthentication');
8 | Route::post(config('2fa-config.disable_2fa'), 'TwoFactorAuthenticationController@disableTwoFactorAuthentication');
9 | });
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 The Code Work
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/database/migrations/2017_01_20_160000_add_two_factor_authentication_required_fields.php:
--------------------------------------------------------------------------------
1 | smallInteger('is_two_factor_enabled')->nullable()->default(0)->before('created_at');
18 | $table->string('two_factor_provisioned_uri', 500)->nullable()->after('is_two_factor_enabled');
19 | });
20 | }
21 |
22 | /**
23 | * Reverse the migrations.
24 | *
25 | * @return void
26 | */
27 | public function down()
28 | {
29 | Schema::table(config('2fa-config.table'), function (Blueprint $table) {
30 | $table->dropColumn('is_two_factor_enabled');
31 | $table->dropColumn('two_factor_provisioned_uri');
32 | });
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "thecodework/two-factor-authentication",
3 | "type": "package",
4 | "description": "Two Factor Authentication (2FA) for Laravel",
5 | "license": "MIT",
6 | "keywords": [
7 | "laravel",
8 | "Laravel 5",
9 | "two-factor",
10 | "authentication",
11 | "2fa",
12 | "rfc-6238"
13 | ],
14 | "authors": [
15 | {
16 | "name": "Ashish Singh",
17 | "email": "imrealashu@gmail.com"
18 | }
19 | ],
20 | "require": {
21 | "php": ">=8.0",
22 | "spomky-labs/otphp": "^10.0.3",
23 | "paragonie/constant_time_encoding": "^2.5",
24 | "endroid/qr-code": "~4.4.8"
25 | },
26 | "autoload": {
27 | "psr-4": {
28 | "Thecodework\\TwoFactorAuthentication\\": "src/"
29 | }
30 | },
31 | "autoload-dev": {
32 | "psr-4": {
33 | "Thecodework\\TwoFactorAuthentication\\Tests\\": "tests/"
34 | }
35 | },
36 | "require-dev": {
37 | "phpunit/phpunit": "~9.5.20",
38 | "orchestra/testbench": "~7.4.0"
39 | },
40 | "scripts": {
41 | "test": "vendor/bin/phpunit"
42 | },
43 | "extra": {
44 | "laravel": {
45 | "providers": [
46 | "Thecodework\\TwoFactorAuthentication\\TwoFactorAuthenticationServiceProvider"
47 | ]
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/TwoFactorAuthenticationServiceProvider.php:
--------------------------------------------------------------------------------
1 | loadRoutesFrom(__DIR__ . '/routes/routes.php');
19 | $this->loadViewsFrom(__DIR__ . '/../resources/views', '2fa');
20 | $this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
21 |
22 | // Publishing configuration file
23 | $this->publishes([
24 | __DIR__ . '/../config/2fa-config.php' => config_path('2fa-config.php'),
25 | ], 'config');
26 |
27 | // Publishing migration
28 | $this->publishes([
29 | __DIR__ . '/../database/migrations/' => database_path('migrations'),
30 | ], 'migrations');
31 |
32 | // Publishing views
33 | $this->publishes([
34 | __DIR__ . '/../resources/views/' => resource_path('views/vendor/2fa'),
35 | ], 'views');
36 | }
37 |
38 | /**
39 | * Get User model defined in config file.
40 | *
41 | * @return string
42 | */
43 | public static function determineTwoFAModel(): string
44 | {
45 | return config('2fa-config.model');
46 | }
47 |
48 | /**
49 | * Get User Model Instance.
50 | *
51 | * @return \Illuminate\Database\Eloquent\Model
52 | */
53 | public static function getTwoFAModelInstance(): Model
54 | {
55 | $TwoFAModelClassName = self::determineTwoFAModel();
56 |
57 | return new $TwoFAModelClassName();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/resources/views/verify.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 | @section('content')
3 |
4 |
5 |
6 |
7 |

8 |
Verify Two Factor Authentication
9 |
10 |
36 |
37 |
38 |
39 |
40 | @endsection
--------------------------------------------------------------------------------
/resources/views/setup.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 | @section('content')
3 |
4 |
5 |
6 |
7 |
Verify Two Factor Authentication
8 |
9 | @if($user->is_two_factor_enabled)
10 |
41 |
42 |
43 |
44 |
45 |
46 | @endsection
--------------------------------------------------------------------------------
/tests/BaseTestCase.php:
--------------------------------------------------------------------------------
1 | setUpDatabase();
15 | }
16 |
17 | protected function getPackageProviders($app)
18 | {
19 | return [
20 | \Thecodework\TwoFactorAuthentication\TwoFactorAuthenticationServiceProvider::class,
21 | ];
22 | }
23 |
24 | protected function seedUserDetails()
25 | {
26 | \DB::table('users')->insert([
27 | 'name' => 'Test User',
28 | 'email' => 'test@user.in',
29 | 'password' => bcrypt('test'),
30 | ]);
31 | }
32 |
33 | protected function AddTwoFactorAuthenticationRequiredFields()
34 | {
35 | include_once '__DIR__' . '/../database/migrations/2017_01_20_160000_add_two_factor_authentication_required_fields.php';
36 |
37 | $this->createUsersTable();
38 | (new \AddTwoFactorAuthenticationRequiredFields())->up();
39 | }
40 |
41 | public function getTempDirectory(): string
42 | {
43 | return __DIR__ . '/temp';
44 | }
45 |
46 | protected function resetDatabase()
47 | {
48 | file_put_contents($this->getTempDirectory() . '/database.sqlite', null);
49 | }
50 |
51 | protected function setUpDatabase()
52 | {
53 | $this->resetDatabase();
54 | $this->AddTwoFactorAuthenticationRequiredFields();
55 | $this->seedUserDetails();
56 | }
57 |
58 | protected function createUsersTable()
59 | {
60 | Schema::create('users', function (Blueprint $table) {
61 | $table->increments('id');
62 | $table->string('name');
63 | $table->string('email')->unique();
64 | $table->string('password');
65 | $table->rememberToken();
66 | $table->timestamps();
67 | });
68 | }
69 |
70 | public function getEnvironmentSetUp($app)
71 | {
72 | $app['config']->set('database.default', 'sqlite');
73 | $app['config']->set('database.connections.sqlite', [
74 | 'driver' => 'sqlite',
75 | 'database' => $this->getTempDirectory() . '/database.sqlite',
76 | 'prefix' => '',
77 | ]);
78 | $app['config']->set('auth.providers.users.model', User::class);
79 | $app['config']->set('app.key', '6rE9Nz59bGRbeMATftriyQjrpF7DcOQm');
80 | $app['config']->set('2fa-config.table', 'users');
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/config/2fa-config.php:
--------------------------------------------------------------------------------
1 | '/home',
12 |
13 | /*
14 | |--------------------------------------------------------------------------
15 | | Routes
16 | |--------------------------------------------------------------------------
17 | |
18 | | Change the routes if your existing routes conflicts with default Two-Factor Authentication Routes.
19 | | Customize route name.
20 | |
21 | | Route Name => Default Route Name Used
22 | | Customize Name Example
23 | | setup_2fa => customize_route_name
24 | |
25 | */
26 | 'setup_2fa' => 'setup-2fa',
27 | 'enable_2fa' => 'enable-2fa',
28 | 'disable_2fa' => 'disable-2fa',
29 | 'verify_2fa' => 'verify-2fa', //get Route
30 | 'verify_2fa_post' => 'verify-2fa', //post
31 |
32 | /*
33 | * Account name which will be used as label to show on
34 | * authenticator mobile application.
35 | */
36 | 'account_name' => env('APP_NAME', 'Thecodework 2FA'),
37 |
38 | /*
39 | * Set Guard for 2FA
40 | * By default the `web` guard will be used but you
41 | * can define any custom guard to utilize 2FA.
42 | */
43 | 'guard' => 'web',
44 |
45 | /*
46 | * Currently Support 'Sha1'
47 | * The library works with the Google Authenticator application
48 | * for iPhone and Android. Google only supports SHA-1 digest algorithm,
49 | * 30 second period and 6 digits OTP. Other values for these parameters
50 | * are ignored by the Google Authenticator application.
51 | */
52 | 'digest_algorithm' => 'sha1',
53 |
54 | /*
55 | * Size of Base32 encoded secret key.
56 | * Default 6 Works with GA and Authy.
57 | */
58 | 'number_of_digits' => 6,
59 |
60 | /*
61 | * The Number of Seconds the code will be valid.
62 | * Default 30.
63 | * Google Authenticator only uses 30 sec period
64 | */
65 | 'period' => 30,
66 |
67 | /*
68 | * Explicitly Define Table name for the model.
69 | */
70 | 'table' => 'users',
71 |
72 | /*
73 | * User Model
74 | * By Default `\App\Models\User` Model is defined.
75 | */
76 | 'model' => '\App\Models\User',
77 |
78 | /*
79 | |--------------------------------------------------------------------------
80 | | Logo
81 | |--------------------------------------------------------------------------
82 | |
83 | | Some App like Authy Use Logo .A default company logo will be used
84 | | Note-* all apps support logo being sent.
85 | | you can use you own logo file requirements :
86 | | 1. Image File must be png
87 | | 2. Image must be public
88 | | 3. Full Uri with qualify path and protocol
89 | |
90 | */
91 | 'logo' => 'https://thecodework.com/wp-content/themes/thecodework/assets/img/thecodework_logo.png'
92 | ];
93 |
--------------------------------------------------------------------------------
/src/AuthenticatesUsersWith2FA.php:
--------------------------------------------------------------------------------
1 | is_two_factor_enabled) {
33 | $request->session()->put('2fa:user:id', encrypt($user->id));
34 | $secret = getenv('HMAC_SECRET');
35 | $signature = hash_hmac('sha256', $user->id, $secret);
36 | Auth::logout();
37 |
38 | return redirect()->intended(config('2fa-config.verify_2fa') . '?signature=' . $signature);
39 | }
40 |
41 | return $this->redirectUsers2FA();
42 | }
43 |
44 | /**
45 | * Verify token and sign in the user.
46 | *
47 | * @param \Illuminate\Http\Request $request
48 | *
49 | * @return \Illuminate\Http\RedirectResponse
50 | */
51 | public function verifyToken(Request $request)
52 | {
53 | $TwoFAModel = TwoFactorAuthenticationServiceProvider::getTwoFAModelInstance();
54 | // Pulling encrypted user id from session and getting user details
55 | $userId = $request->session()->get('2fa:user:id');
56 | $this->user = $TwoFAModel->find(decrypt($userId));
57 |
58 | // If token is not valid then custom validation error message will be shown.
59 | $messages = [
60 | 'totp_token.valid_token' => 'Security code is not valid',
61 | 'totp_token.required' => 'Security code is required',
62 | ];
63 |
64 | // Impllicitly adding an validation rule to check if token is valid or not.
65 | Validator::extendImplicit('valid_token', function ($attribute, $value) {
66 | $totp = Factory::loadFromProvisioningUri($this->user->two_factor_provisioned_uri);
67 |
68 | return $totp->verify($value);
69 | });
70 |
71 | // If Validation fails, it will return the error else sign in the user.
72 | $number_of_digits = config('2fa-config.number_of_digits');
73 | $validator = Validator::make($request->all(), [
74 | 'totp_token' => "required|digits:$number_of_digits|valid_token",
75 | ], $messages);
76 |
77 | $secret = getenv('HMAC_SECRET');
78 | $signature = hash_hmac('sha256', $this->user->id, $secret);
79 | if ($validator->fails()) {
80 | return redirect(config('2fa-config.verify_2fa') . '?signature=' . $signature)
81 | ->withErrors($validator)
82 | ->withInput();
83 | }
84 |
85 | // Flush the session.
86 | $request->session()->forget('2fa:user:id');
87 |
88 | Auth::loginUsingId($this->user->id);
89 |
90 | return $this->redirectUsers2FA();
91 | }
92 |
93 | public function setUser($user)
94 | {
95 | $this->user = $user;
96 | }
97 |
98 | public function getUser()
99 | {
100 | return $this->user;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/thecodework/two-factor-authentication)
2 | [](https://scrutinizer-ci.com/g/thecodework/two-factor-authentication/?branch=master)
3 | [](https://styleci.io/repos/85341644)
4 | [](https://packagist.org/packages/thecodework/two-factor-authentication)
5 |
6 | # Laravel Two Factor Authentication (2FA)
7 |
8 | 
9 |
10 | Two Factor Authentication or 2-Step Verification provides stronger security for your Account by requiring a second step of verification when you sign in. In addition to your password, you’ll also need a code generated by the Google Authenticator app on your phone. This package implements TOTP defined in [RFC 6238](https://tools.ietf.org/html/rfc6238)
11 |
12 | ## Requirements
13 |
14 | - PHP >= 7.1
15 | - Laravel >= 5.3
16 | - Google Authenticator [Android](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en) - [iOS](https://itunes.apple.com/in/app/google-authenticator/id388497605?mt=8) (Recommended) or [Authy](https://www.authy.com/) mobile app
17 |
18 | ## Installation
19 |
20 | **1. Composer Install**
21 |
22 | ```bash
23 | $ composer require thecodework/two-factor-authentication
24 | ```
25 |
26 | _Note_ - If your're using Laravel 5.5 or newer version then auto-discovery-pacakge would automatically update the providers and you could skip to **Step 3**
27 |
28 | **2. Add Service Provider**
29 |
30 | After requiring the package add `TwoFactorAuthenticationServiceProvider::class` into providors array in `app.php` confi file
31 |
32 | ```php
33 | [
34 | 'providers' => [
35 | //...
36 | Thecodework\TwoFactorAuthentication\TwoFactorAuthenticationServiceProvider::class
37 | ]
38 | ]
39 | ```
40 |
41 | **3. Publish the ConfigFile**
42 |
43 | Publish config file
44 |
45 | ```
46 | $ php artisan vendor:publish --provider="Thecodework\TwoFactorAuthentication\TwoFactorAuthenticationServiceProvider" --tag=config
47 | ```
48 |
49 | Once the config file is published you can navigate to config directory of your application and look for `2fa-config.php` file and change configuration as you want.
50 |
51 | **4. Run Migrations**
52 |
53 | Now run the migration
54 |
55 | ```bash
56 | $ php artisan migrate
57 | ```
58 |
59 | It will use the default User model and adds two columns `is_2fa_enabled` and `secret_key`.
60 |
61 | **5. Add `AuthenticatesUserWith2FA` trait in the LoginController**
62 |
63 | Now the config file is placed. The last thing to do is addding `AuthenticatesUsersWith2FA` trait in the `Http/Controllers/Auth/LoginController.php` file which helps to stop user at verify-2fa page to enter TOTP token after each login.
64 |
65 | The final snippet will look like this.
66 |
67 | ```php
68 | use AuthenticatesUsers, AuthenticatesUsersWith2FA {
69 | AuthenticatesUsersWith2FA::authenticated insteadof AuthenticatesUsers;
70 | }
71 | ```
72 |
73 | Note: Don't forget to include use statement `use Thecodework\TwoFactorAuthentication\AuthenticatesUsersWith2FA` in the header.
74 |
75 | **6. Setup 2FA for user**
76 |
77 | **• Enable 2FA**
78 |
79 | Now login to the application and visit `/setup-2fa/` route, which will show a barcode which can be scanned either using Google Authenticator or Authy mobile application as described above.
80 | Scan that code and click **Enable Two Factor Authentication**.
81 |
82 | **• Disable 2FA**
83 |
84 | To disable Two Factor, visit `/setup-2fa` route, which will now show a **Disable Two Factor Authentication** button. Click to disable 2FA for your account.
85 |
86 | **7. Testing 2FA**
87 |
88 | Now to test 2FA, perform logout and log back in again, it will ask you to enter Token which can be obtain from the authenticator mobile application. Enter the token and you're logged in.
89 |
90 | ### Additionally
91 |
92 | If you want to publish views, and migration as well along with config file then run
93 |
94 | ```
95 | $ php artisan vendor:publish --provider="Thecodework\TwoFactorAuthentication\TwoFactorAuthenticationServiceProvider"
96 | ```
97 |
98 | ## Contribution
99 |
100 | Feel free to create issues, submit PRs and talk about features and enhancement through proposing issue. If you find any security consideration, instead of creating an issue send an email to [imrealashu@gmail.com](mailto:imrealashu@gmail.com).
101 |
--------------------------------------------------------------------------------
/src/Http/Controllers/TwoFactorAuthenticationController.php:
--------------------------------------------------------------------------------
1 | TwoFAModel = TwoFactorAuthenticationServiceProvider::getTwoFAModelInstance();
33 |
34 | $this->middleware(function ($request, $next) {
35 | $this->setUser(\Auth::guard(config('2fa-config.guard'))->user());
36 |
37 | return $next($request);
38 | });
39 | }
40 |
41 | /**
42 | * Setup two factor authentication.
43 | *
44 | * @param \Illuminate\Http\Request
45 | * @param \Illuminate\Http\Response
46 | *
47 | * @throws \Thecodework\TwoFactorAuthentications\Exceptions\TwoFactorAuthenticationExceptions
48 | *
49 | * @return mixed
50 | */
51 | public function setupTwoFactorAuthentication(Request $request)
52 | {
53 | $user = $this->getUser();
54 | $totp = TOTP::create(
55 | $this->base32EncodedString(),
56 | config('2fa-config.period'),
57 | config('2fa-config.digest_algorithm'),
58 | config('2fa-config.number_of_digits')
59 | );
60 | $totp->setLabel(config('2fa-config.account_name'));
61 | $totp->setParameter('image', config('2fa-config.logo'));
62 |
63 | $this->updateUserWithProvisionedUri($totp->getProvisioningUri());
64 |
65 | //Generate Qr Code
66 | $writer = new PngWriter();
67 | $qrCode = QrCode::create($totp->getProvisioningUri())->setEncoding(new Encoding('ISO-8859-1'));
68 | $result = $writer->write($qrCode);
69 | $barcode = $result->getDataUri();
70 |
71 | if ($request->ajax()) {
72 | return $barcode;
73 | }
74 |
75 | return view('2fa::setup', compact('barcode', 'user'));
76 | }
77 |
78 | /**
79 | * Enable 2FA.
80 | *
81 | * @param \Illuminate\Http\Request
82 | *
83 | * @return mixed
84 | */
85 | public function enableTwoFactorAuthentication(Request $request)
86 | {
87 | $user = $this->getUser();
88 | $user->is_two_factor_enabled = 1;
89 | $user->update();
90 |
91 | if ($request->ajax()) {
92 | return [
93 | 'data' => [
94 | 'message' => 'success',
95 | 'description' => '2FA Enabled',
96 | ],
97 | ];
98 | }
99 |
100 | return $this->redirectUsers2FA();
101 | }
102 |
103 | /**
104 | * Disable 2FA.
105 | *
106 | * @param \Illuminate\Http\Request
107 | *
108 | * @return mixed
109 | */
110 | public function disableTwoFactorAuthentication(Request $request)
111 | {
112 | $user = $this->getUser();
113 | $user->is_two_factor_enabled = 0;
114 | $user->two_factor_provisioned_uri = null;
115 | $user->update();
116 |
117 | if ($request->ajax()) {
118 | return [
119 | 'data' => [
120 | 'message' => 'success',
121 | 'description' => '2FA Disabled',
122 | ],
123 | ];
124 | }
125 |
126 | return $this->redirectUsers2FA();
127 | }
128 | /**
129 | * Verify Two Factor Authentication.
130 | *
131 | * @param \Illuminate\Http\Request $request
132 | */
133 | public function verifyTwoFactorAuthentication(Request $request)
134 | {
135 | if ($request->session()->has('2fa:user:id')) {
136 | $secret = getenv('HMAC_SECRET');
137 | $signature = hash_hmac('sha256', decrypt($request->session()->get('2fa:user:id')), $secret);
138 |
139 | if (md5($signature) !== md5($request->signature)) {
140 | return redirect()->intended('login');
141 | }
142 |
143 | return view('2fa::verify');
144 | }
145 |
146 | return redirect()->back(); //shoud be configurable
147 | }
148 |
149 | /**
150 | * Encode Random String to 32 Base Transfer Encoding.
151 | *
152 | * @return string
153 | */
154 | private function base32EncodedString(): string
155 | {
156 | return trim(Base32::encodeUpper(random_bytes(128)), '=');
157 | }
158 |
159 | /**
160 | * Update User data with 2FA generated Key.
161 | *
162 | * @return void
163 | */
164 | private function updateUserWithProvisionedUri($twoFactorProvisionedUri)
165 | {
166 | $user = $this->TwoFAModel->find($this->getUser()->id);
167 | if (
168 | !Schema::hasColumn(config('2fa-config.table'), 'two_factor_provisioned_uri') ||
169 | !Schema::hasColumn(config('2fa-config.table'), 'is_two_factor_enabled')
170 | ) {
171 | throw TwoFactorAuthenticationExceptions::columnNotFound();
172 | }
173 | $user->two_factor_provisioned_uri = $twoFactorProvisionedUri;
174 | $user->update();
175 | }
176 | }
177 |
--------------------------------------------------------------------------------