implement 2fa system

This commit is contained in:
Nima8FT 2025-04-23 13:47:21 +03:30
parent 7723c70511
commit ef378d450d
15 changed files with 614 additions and 11 deletions

View File

@ -9,8 +9,18 @@ use Illuminate\Support\Facades\Auth;
class LogoutController extends Controller class LogoutController extends Controller
{ {
public $user;
public function __construct()
{
$this->user = Auth::user();
}
public function logout(Request $request) public function logout(Request $request)
{ {
$this->user->update([
'verify2fa' => 0,
]);
Auth::logout(); Auth::logout();
$request->session()->invalidate(); $request->session()->invalidate();
@ -21,13 +31,12 @@ class LogoutController extends Controller
public function deleteAccount(Request $request) public function deleteAccount(Request $request)
{ {
$user = Auth::user();
Auth::logout(); Auth::logout();
$request->session()->invalidate(); $request->session()->invalidate();
$request->session()->regenerateToken(); $request->session()->regenerateToken();
$user->delete(); $this->user->delete();
return redirect()->route('login')->with('success', 'Your account has been deleted successfully.'); return redirect()->route('login')->with('success', 'Your account has been deleted successfully.');
} }

View File

@ -0,0 +1,77 @@
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Requests\Enable2FARequest;
use App\Http\Requests\SecretCode2FARequest;
use Illuminate\Support\Facades\Auth;
class TwoFactorAuthenticationController extends Controller
{
public $google2fa;
public $user;
public function __construct()
{
$this->google2fa = app('pragmarx.google2fa');
$this->user = Auth::user();
}
public function enable2FAShow()
{
$secret = $this->google2fa->generateSecretKey();
$urlQRCode = $this->google2fa->getQRCodeInline(
config('app.name'),
$this->user->email,
$secret
);
return view("auth.enable-2fa", compact(['secret', 'urlQRCode']));
}
public function enable2FA(Enable2FARequest $request)
{
$inputs = $request->only('otp', 'secret');
$valid = $this->google2fa->verifyKey($inputs['secret'], $inputs['otp']);
if ($valid) {
$this->user->update([
'google2fa_secret' => $inputs['secret'],
]);
}
return redirect()->route('dashboard')->with('success', '2fa is verified');
}
public function disable2FA()
{
$this->user->update([
'google2fa_secret' => null,
'verify2fa' => 0,
]);
return redirect()->route('dashboard');
}
public function secretCodeShow()
{
return view('auth.secret-code');
}
public function secretCode(SecretCode2FARequest $request)
{
$secret = $this->user->google2fa_secret;
$otp = $request->only('code');
$valid = $this->google2fa->verifyKey($secret, $otp['code']);
if ($valid) {
$this->user->update([
'verify2fa' => 1,
]);
return redirect()->route('dashboard')->with('google2fa', '2fa is verify');
}
return redirect()->back()->withErrors(['code' => 'secret code is wrong']);
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class TwoFactorAuthMiddleware
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if (Auth::user()->google2fa_secret) {
if (!Auth::user()->verify2fa) {
return redirect()->route('secret.code.show');
}
}
return $next($request);
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class Enable2FARequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'otp' => 'required',
'secret' => 'required',
];
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class SecretCode2FARequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'code' => 'required'
];
}
}

View File

@ -23,7 +23,9 @@ class User extends Authenticatable implements MustVerifyEmail
'password', 'password',
'github_id', 'github_id',
'github_token', 'github_token',
'github_refresh_token' 'github_refresh_token',
'google2fa_secret',
'verify2fa'
]; ];
/** /**

View File

@ -1,17 +1,20 @@
<?php <?php
use App\Http\Middleware\TwoFactorAuthMiddleware;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions; use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware; use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__)) return Application::configure(basePath: dirname(__DIR__))
->withRouting( ->withRouting(
web: __DIR__.'/../routes/web.php', web: __DIR__ . '/../routes/web.php',
commands: __DIR__.'/../routes/console.php', commands: __DIR__ . '/../routes/console.php',
health: '/up', health: '/up',
) )
->withMiddleware(function (Middleware $middleware) { ->withMiddleware(function (Middleware $middleware) {
// $middleware->alias([
'2fa' => TwoFactorAuthMiddleware::class,
]);
}) })
->withExceptions(function (Exceptions $exceptions) { ->withExceptions(function (Exceptions $exceptions) {
// //

View File

@ -10,10 +10,12 @@
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^8.2", "php": "^8.2",
"bacon/bacon-qr-code": "^3.0",
"laravel/framework": "^12.0", "laravel/framework": "^12.0",
"laravel/socialite": "^5.20", "laravel/socialite": "^5.20",
"laravel/tinker": "^2.10.1", "laravel/tinker": "^2.10.1",
"mailersend/laravel-driver": "^2.9" "mailersend/laravel-driver": "^2.9",
"pragmarx/google2fa-laravel": "^2.3"
}, },
"require-dev": { "require-dev": {
"fakerphp/faker": "^1.23", "fakerphp/faker": "^1.23",

View File

@ -4,8 +4,62 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "cc95798219be94103b39757ba957bfb5", "content-hash": "7ec9c18ae33503f4d06a9ce3cef2e3cf",
"packages": [ "packages": [
{
"name": "bacon/bacon-qr-code",
"version": "v3.0.1",
"source": {
"type": "git",
"url": "https://github.com/Bacon/BaconQrCode.git",
"reference": "f9cc1f52b5a463062251d666761178dbdb6b544f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/f9cc1f52b5a463062251d666761178dbdb6b544f",
"reference": "f9cc1f52b5a463062251d666761178dbdb6b544f",
"shasum": ""
},
"require": {
"dasprid/enum": "^1.0.3",
"ext-iconv": "*",
"php": "^8.1"
},
"require-dev": {
"phly/keep-a-changelog": "^2.12",
"phpunit/phpunit": "^10.5.11 || 11.0.4",
"spatie/phpunit-snapshot-assertions": "^5.1.5",
"squizlabs/php_codesniffer": "^3.9"
},
"suggest": {
"ext-imagick": "to generate QR code images"
},
"type": "library",
"autoload": {
"psr-4": {
"BaconQrCode\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Ben Scholzen 'DASPRiD'",
"email": "mail@dasprids.de",
"homepage": "https://dasprids.de/",
"role": "Developer"
}
],
"description": "BaconQrCode is a QR code generator for PHP.",
"homepage": "https://github.com/Bacon/BaconQrCode",
"support": {
"issues": "https://github.com/Bacon/BaconQrCode/issues",
"source": "https://github.com/Bacon/BaconQrCode/tree/v3.0.1"
},
"time": "2024-10-01T13:55:55+00:00"
},
{ {
"name": "beberlei/assert", "name": "beberlei/assert",
"version": "v3.3.3", "version": "v3.3.3",
@ -268,6 +322,56 @@
], ],
"time": "2023-12-20T15:40:13+00:00" "time": "2023-12-20T15:40:13+00:00"
}, },
{
"name": "dasprid/enum",
"version": "1.0.6",
"source": {
"type": "git",
"url": "https://github.com/DASPRiD/Enum.git",
"reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/DASPRiD/Enum/zipball/8dfd07c6d2cf31c8da90c53b83c026c7696dda90",
"reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90",
"shasum": ""
},
"require": {
"php": ">=7.1 <9.0"
},
"require-dev": {
"phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11",
"squizlabs/php_codesniffer": "*"
},
"type": "library",
"autoload": {
"psr-4": {
"DASPRiD\\Enum\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Ben Scholzen 'DASPRiD'",
"email": "mail@dasprids.de",
"homepage": "https://dasprids.de/",
"role": "Developer"
}
],
"description": "PHP 7.1 enum implementation",
"keywords": [
"enum",
"map"
],
"support": {
"issues": "https://github.com/DASPRiD/Enum/issues",
"source": "https://github.com/DASPRiD/Enum/tree/1.0.6"
},
"time": "2024-08-09T14:30:48+00:00"
},
{ {
"name": "dflydev/dot-access-data", "name": "dflydev/dot-access-data",
"version": "v3.0.3", "version": "v3.0.3",
@ -3753,6 +3857,201 @@
], ],
"time": "2024-12-14T21:12:59+00:00" "time": "2024-12-14T21:12:59+00:00"
}, },
{
"name": "pragmarx/google2fa",
"version": "v8.0.3",
"source": {
"type": "git",
"url": "https://github.com/antonioribeiro/google2fa.git",
"reference": "6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad",
"reference": "6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad",
"shasum": ""
},
"require": {
"paragonie/constant_time_encoding": "^1.0|^2.0|^3.0",
"php": "^7.1|^8.0"
},
"require-dev": {
"phpstan/phpstan": "^1.9",
"phpunit/phpunit": "^7.5.15|^8.5|^9.0"
},
"type": "library",
"autoload": {
"psr-4": {
"PragmaRX\\Google2FA\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Antonio Carlos Ribeiro",
"email": "acr@antoniocarlosribeiro.com",
"role": "Creator & Designer"
}
],
"description": "A One Time Password Authentication package, compatible with Google Authenticator.",
"keywords": [
"2fa",
"Authentication",
"Two Factor Authentication",
"google2fa"
],
"support": {
"issues": "https://github.com/antonioribeiro/google2fa/issues",
"source": "https://github.com/antonioribeiro/google2fa/tree/v8.0.3"
},
"time": "2024-09-05T11:56:40+00:00"
},
{
"name": "pragmarx/google2fa-laravel",
"version": "v2.3.0",
"source": {
"type": "git",
"url": "https://github.com/antonioribeiro/google2fa-laravel.git",
"reference": "60f363c16db1e94263e0560efebe9fc2e302b7ef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/antonioribeiro/google2fa-laravel/zipball/60f363c16db1e94263e0560efebe9fc2e302b7ef",
"reference": "60f363c16db1e94263e0560efebe9fc2e302b7ef",
"shasum": ""
},
"require": {
"laravel/framework": "^5.4.36|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
"php": ">=7.0",
"pragmarx/google2fa-qrcode": "^1.0|^2.0|^3.0"
},
"require-dev": {
"bacon/bacon-qr-code": "^2.0",
"orchestra/testbench": "3.4.*|3.5.*|3.6.*|3.7.*|4.*|5.*|6.*|7.*|8.*|9.*|10.*",
"phpunit/phpunit": "~5|~6|~7|~8|~9|~10|~11"
},
"suggest": {
"bacon/bacon-qr-code": "Required to generate inline QR Codes.",
"pragmarx/recovery": "Generate recovery codes."
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Google2FA": "PragmaRX\\Google2FALaravel\\Facade"
},
"providers": [
"PragmaRX\\Google2FALaravel\\ServiceProvider"
]
},
"component": "package",
"frameworks": [
"Laravel"
],
"branch-alias": {
"dev-master": "0.2-dev"
}
},
"autoload": {
"psr-4": {
"PragmaRX\\Google2FALaravel\\": "src/",
"PragmaRX\\Google2FALaravel\\Tests\\": "tests/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Antonio Carlos Ribeiro",
"email": "acr@antoniocarlosribeiro.com",
"role": "Creator & Designer"
}
],
"description": "A One Time Password Authentication package, compatible with Google Authenticator.",
"keywords": [
"Authentication",
"Two Factor Authentication",
"google2fa",
"laravel"
],
"support": {
"issues": "https://github.com/antonioribeiro/google2fa-laravel/issues",
"source": "https://github.com/antonioribeiro/google2fa-laravel/tree/v2.3.0"
},
"time": "2025-02-26T19:39:35+00:00"
},
{
"name": "pragmarx/google2fa-qrcode",
"version": "v3.0.0",
"source": {
"type": "git",
"url": "https://github.com/antonioribeiro/google2fa-qrcode.git",
"reference": "ce4d8a729b6c93741c607cfb2217acfffb5bf76b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/antonioribeiro/google2fa-qrcode/zipball/ce4d8a729b6c93741c607cfb2217acfffb5bf76b",
"reference": "ce4d8a729b6c93741c607cfb2217acfffb5bf76b",
"shasum": ""
},
"require": {
"php": ">=7.1",
"pragmarx/google2fa": ">=4.0"
},
"require-dev": {
"bacon/bacon-qr-code": "^2.0",
"chillerlan/php-qrcode": "^1.0|^2.0|^3.0|^4.0",
"khanamiryan/qrcode-detector-decoder": "^1.0",
"phpunit/phpunit": "~4|~5|~6|~7|~8|~9"
},
"suggest": {
"bacon/bacon-qr-code": "For QR Code generation, requires imagick",
"chillerlan/php-qrcode": "For QR Code generation"
},
"type": "library",
"extra": {
"component": "package",
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"PragmaRX\\Google2FAQRCode\\": "src/",
"PragmaRX\\Google2FAQRCode\\Tests\\": "tests/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Antonio Carlos Ribeiro",
"email": "acr@antoniocarlosribeiro.com",
"role": "Creator & Designer"
}
],
"description": "QR Code package for Google2FA",
"keywords": [
"2fa",
"Authentication",
"Two Factor Authentication",
"google2fa",
"qr code",
"qrcode"
],
"support": {
"issues": "https://github.com/antonioribeiro/google2fa-qrcode/issues",
"source": "https://github.com/antonioribeiro/google2fa-qrcode/tree/v3.0.0"
},
"time": "2021-08-15T12:53:48+00:00"
},
{ {
"name": "psr/clock", "name": "psr/clock",
"version": "1.0.0", "version": "1.0.0",

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->text('google2fa_secret')->nullable()->after('github_refresh_token');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
//
});
}
};

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('verify2fa')->default(false)->after('google2fa_secret');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
//
});
}
};

View File

@ -0,0 +1,35 @@
@extends('layouts.app')
@section('content')
<div class="bg-[#0d1b2a] min-h-screen flex justify-center items-center space-x-4">
<div class="mt-10 bg-[#1b263b] p-6 rounded-xl shadow-xl max-w-[600px] w-full mx-auto transition-all duration-300">
<h3 class="text-2xl font-semibold text-center text-[#e0e1dd] mb-6">
Two Factor Authentication Setup
</h3>
<div class="mb-6 text-center">
<p class="text-sm text-[#e0e1dd] font-mono break-all mb-3">{{ $secret }}</p>
<div class="flex justify-center">
{!! $urlQRCode !!}
</div>
</div>
<form method="POST" action="{{ route('enable.2fa') }}" class="space-y-4">
@csrf
<input type="hidden" name="secret" value="{{ $secret }}">
<div>
<label for="otp" class="block text-[#e0e1dd] mb-1 font-semibold">OTP Code</label>
<input name="otp" type="text" placeholder="Enter your OTP code"
class="w-full px-4 py-2 rounded-md bg-[#1b263b] border border-[#e0e1dd] text-[#e0e1dd] focus:outline-none focus:ring-2 focus:ring-blue-500" />
<p class="text-red-400 mt-1 text-sm">@error('otp') {{ $message }} @enderror</p>
</div>
<button type="submit"
class="w-full cursor-pointer py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md font-semibold transition duration-300">
Verify OTP
</button>
</form>
</div>
</div>
@endsection

View File

@ -0,0 +1,29 @@
@extends('layouts.app')
@section('content')
<div class="bg-[#0d1b2a] h-screen flex justify-center items-center space-x-6">
<div
class="flex justify-center items-center p-4 flex-wrap shadow-lg rounded-xl login-form size-150 max-w-[500px] bg-[#1b263b] h-auto text-center">
<h1 class="w-full font-bold text-4xl text-[#e0e1dd]">Two Factor Secret Code</h1>
<div class="w-[90%] p-5">
<p class="text-[#e0e1dd] text-xl mb-4 font-medium">
Please enter your secret code to login
</p>
<form method="POST" action="{{route('secret.code')}}">
@csrf
<div class="text-left my-5">
<label for="code" class="font-bold text-[#e0e1dd]">Code:</label>
<input wire:model.lazy='code' name="code" type="text" placeholder="Enter your text"
class="w-full my-2 px-4 py-2 border border-[#e0e1dd] text-[#e0e1dd] rounded-md shadow-sm focus:outline-none" />
<p class="w-full text-red-500">@error('code') {{ $message }} @enderror</p>
</div>
<div class="mt-8">
<button type="submit"
class="border border-[#e0e1dd] font-medium w-full p-2 rounded-md bg-[#e0e1dd] cursor-pointer hover:opacity-85 transition duration-300 ease-in-out text-black">Submit</button>
</div>
</form>
</div>
</div>
</div>
@endsection

View File

@ -77,7 +77,7 @@
{{-- Two Factor Authentication --}} {{-- Two Factor Authentication --}}
<div class="bg-[#1b263b] rounded-xl shadow"> <div class="bg-[#1b263b] rounded-xl shadow">
@if (!$user->google2fa_secret) @if (!$user->google2fa_secret)
<form method="GET" action="#"> <form method="GET" action="{{route('enable.2fa.show')}}">
@csrf @csrf
<button type="submit" <button type="submit"
class="w-full cursor-pointer px-6 py-3 border border-blue-600 text-white font-semibold rounded-lg hover:bg-blue-700 transition ease-in-out duration-300"> class="w-full cursor-pointer px-6 py-3 border border-blue-600 text-white font-semibold rounded-lg hover:bg-blue-700 transition ease-in-out duration-300">
@ -85,7 +85,7 @@
</button> </button>
</form> </form>
@else @else
<form method="POST" action="#"> <form method="POST" action="{{route('disable.2fa')}}">
@csrf @csrf
<button type="submit" <button type="submit"
class="w-full cursor-pointer px-6 py-3 border border-red-600 text-white font-semibold rounded-lg hover:bg-red-700 transition ease-in-out duration-300"> class="w-full cursor-pointer px-6 py-3 border border-red-600 text-white font-semibold rounded-lg hover:bg-red-700 transition ease-in-out duration-300">

View File

@ -9,6 +9,7 @@ use App\Http\Controllers\Auth\LoginController;
use App\Http\Controllers\Auth\LogoutController; use App\Http\Controllers\Auth\LogoutController;
use App\Http\Controllers\Auth\PasswordController; use App\Http\Controllers\Auth\PasswordController;
use App\Http\Controllers\Auth\RegisterController; use App\Http\Controllers\Auth\RegisterController;
use App\Http\Controllers\Auth\TwoFactorAuthenticationController;
Route::get('/', function () { Route::get('/', function () {
return view('welcome'); return view('welcome');
@ -21,7 +22,7 @@ Route::get('login', [LoginController::class, 'create'])->name('login');
Route::post('login', [LoginController::class, 'store'])->name('login.store'); Route::post('login', [LoginController::class, 'store'])->name('login.store');
Route::group(['middleware' => 'auth'], function () { Route::group(['middleware' => 'auth'], function () {
Route::get('dashboard', [DashboardController::class, 'index'])->name('dashboard'); Route::get('dashboard', [DashboardController::class, 'index'])->middleware('2fa')->name('dashboard');
Route::post('logout', action: [LogoutController::class, 'logout'])->name('logout'); Route::post('logout', action: [LogoutController::class, 'logout'])->name('logout');
Route::post('delete-account', action: [LogoutController::class, 'deleteAccount'])->name('delete.account'); Route::post('delete-account', action: [LogoutController::class, 'deleteAccount'])->name('delete.account');
@ -29,6 +30,13 @@ Route::group(['middleware' => 'auth'], function () {
//verify mail //verify mail
Route::post('email/verification-notification', [MailController::class, 'notification'])->name('verification.send'); Route::post('email/verification-notification', [MailController::class, 'notification'])->name('verification.send');
Route::get('email/verify/{id}/{hash}', [MailController::class, 'verify'])->name('verification.verify'); Route::get('email/verify/{id}/{hash}', [MailController::class, 'verify'])->name('verification.verify');
//verify two factor authentication
Route::get('enable-2fa-show', [TwoFactorAuthenticationController::class, 'enable2FAShow'])->name('enable.2fa.show');
Route::post('enable-2fa', [TwoFactorAuthenticationController::class, 'enable2FA'])->name('enable.2fa');
Route::post('disable-2fa', [TwoFactorAuthenticationController::class, 'disable2FA'])->name('disable.2fa');
Route::get('secret-code-show', [TwoFactorAuthenticationController::class, 'secretCodeShow'])->name('secret.code.show');
Route::post('secret-code', [TwoFactorAuthenticationController::class, 'secretCode'])->name('secret.code');
}); });