2 Factor Authentication
Identity verification using two different components, e.g.:
- Bank card and PIN
- Password and TAN
Application
- Security-critical applications
- Online portals
- Web-based services
2 Factor Authentication in Laravel
Automatic Creation of Login and Registration
$> composer require laravel/breeze --dev
$> php artisan breeze:install
// blade wählen
$> npm install
$> npm run dev
Database Configuration
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=zwei-faktor-auth
DB_USERNAME=root
DB_PASSWORD=
Database Migration
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('phone_number');
$table->boolean('phone_verified')->default(false);
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Customize Registration View in „resources/views/auth/register.blade.php"
// Phone number in das Registrierungsformular hinzufügen
<!-- Phone number -->
<div class="mt-4">
<x-input-label for="phone_number" :value="__('Phone number')" />
<x-text-input id="phone_number" class="block mt-1 w-full" type="number"
name="phone_number" :value="old('phone_number')" required />
</div>
Adjust phone number validation in registration in
„app/Http/Controllers/Auth/RegisteredUserController.php“
<?php
$request->validate([
...
'phone_number' => ['required', 'numeric', 'min:10'],
...
]);
$user = User::create([
...
'phone_number' => $request->phone_number, // Also add this to the User Model
...
]);
...
return redirect(route('verify.phone'));
?>
Redirect after login in
„app/Http/Controllers/AuthenticatedSessionController.php “
public function store(LoginRequest $request): RedirectResponse
{
$request->authenticate();
$request->session()->regenerate();
return redirect(route('verify.phone'));
}
Create a view for the verification: verify.blade.php
<html>
<head>
</head>
<body>
<form action="/verify/phone" method="post">
@csrf
<input type="text" name="code">
<input type="submit">
</form>
</body>
</html>
Route::get('/verify/phone', [VerifyPhoneController::class, 'index'])->name('verify.phone');
Route::post('/verify/phone', [VerifyPhoneController::class, ‚verifyCode'])->name('verify.phone');
Create a Controller for the Verification: VerifyPhoneController
public function connect()
{
$sid = getenv("TWILIO_ACCOUNT_SID");
$token = getenv("TWILIO_AUTH_TOKEN");
$sender = new Client($sid, $token);
return $sender;
}
public function index()
{
$sender = $this->connect();
$verification = $sender->verify
->v2
->services(getenv("TWILIO_VERIFICATION_SID"))
->verifications
->create("+".str_replace('-', '', Auth::user()->phone_number),
"sms");
return view('phone.verify');
}
public function verifyCode(Request $request)
{
$sender = $this->connect();
$check_code = $sender->verify
->v2
->services(getenv('TWILIO_VERIFICATION_SID'))
->verificationChecks
->create(
[
"to" => "+" . str_replace('-', '', Auth::user()->phone_number),
"code" => $request->code
]
);
if ($check_code->valid === true) {
User::where('id', Auth::user()->id)
->update([
'phone_verified' => $check_code->valid
]);
return redirect(route('dashboard'));
} else {
session()->flash('error', 'Verification failed');
}
}
Install Twilio SDK
composer require twilio/sdk
Create Twilio Account and a Service "Verify"
Configuration in .env
TWILIO_ACCOUNT_SID=<TWILIO_ACCOUNT_SID>
TWILIO_AUTH_TOKEN=<TWILIO_AUTH_TOKEN>
TWILIO_VERIFICATION_SID=<TWILIO_VERIFICATION_SID>
Test It