scheb/2fa-totp
TOTP (Time-based One-Time Password) provider for the scheb TwoFactorBundle, enabling app-based 2FA with authenticator codes. Part of the scheb/2fa project (read-only mirror); see main repo/docs for setup.
Install Dependencies: Require the package and Symfony bridge components:
composer require scheb/2fa-totp scheb/2fa-bundle symfony/http-foundation symfony/routing
Publish Configuration: Copy the bundle’s configuration to Laravel’s config:
php artisan vendor:publish --provider="Scheb\TwoFactorBundle\SchebTwoFactorBundle" --tag="config"
Merge the published config/2fa.php with your existing config.
Set Up Database: Run migrations to add TOTP fields to your users table:
php artisan vendor:publish --provider="Scheb\TwoFactorBundle\SchebTwoFactorBundle" --tag="migrations"
php artisan migrate
First Use Case: Enable TOTP for a User Generate a secret and QR code for a user in a controller:
use Scheb\TwoFactorBundle\Security\TwoFactorAuthenticatorInterface;
public function enableTotp(TwoFactorAuthenticatorInterface $twoFactor)
{
$user = auth()->user();
$secret = $twoFactor->generateSecret();
$qrCodeUrl = $twoFactor->generateQrCodeUrl($user->email, $secret);
// Store secret in DB (e.g., $user->totp_secret = $secret)
$user->save();
return view('totp.setup', compact('qrCodeUrl'));
}
Verify TOTP in Login Flow Add middleware to check TOTP on protected routes:
// app/Http/Kernel.php
protected $routeMiddleware = [
'verify.totp' => \App\Http\Middleware\VerifyTotp::class,
];
Create VerifyTotp middleware to validate TOTP codes:
use Scheb\TwoFactorBundle\Security\TwoFactorAuthenticatorInterface;
public function handle(Request $request, Closure $next, TwoFactorAuthenticatorInterface $twoFactor)
{
if (!$request->has('totp_code')) {
return redirect()->route('login.totp');
}
$user = auth()->user();
if (!$twoFactor->checkCode($user, $request->input('totp_code'))) {
return back()->withErrors(['totp' => 'Invalid code']);
}
return $next($request);
}
TOTP Setup Flow:
TwoFactorAuthenticatorInterface::generateSecret().TwoFactorAuthenticatorInterface::generateQrCodeUrl().totp_secret, totp_algorithm).Login with TOTP:
if ($user->hasTotpEnabled()) {
return redirect()->route('login.totp', ['user' => $user]);
}
$twoFactor->checkCode($user, $request->totp_code);
Backup Codes: Generate and store backup codes for recovery:
$backupCodes = $twoFactor->generateBackupCodes();
$user->backup_codes = json_encode($backupCodes);
$user->save();
Laravel Auth Integration:
Extend Laravel’s AuthManager to support TOTP:
// app/Providers/AuthServiceProvider.php
public function boot()
{
$this->app['auth']->viaRequest('totp', function ($request) {
return $this->authenticateTotp($request);
});
}
Middleware for Protected Routes: Use middleware to enforce TOTP on sensitive routes:
Route::middleware(['auth', 'verify.totp'])->group(function () {
// Admin dashboard, financial actions, etc.
});
Custom Templates: Override Twig templates by publishing assets:
php artisan vendor:publish --provider="Scheb\TwoFactorBundle\SchebTwoFactorBundle" --tag="templates"
Then customize in resources/views/vendor/two_factor/.
Event Listeners: Listen for TOTP events to log or notify:
// app/Providers/EventServiceProvider.php
protected $listen = [
'Scheb\TwoFactorBundle\Security\TwoFactorEvent::TOTP_VERIFIED' => [
\App\Listeners\LogTotpVerification::class,
],
];
Testing: Mock TOTP verification in tests:
$twoFactor = $this->createMock(TwoFactorAuthenticatorInterface::class);
$twoFactor->method('checkCode')->willReturn(true);
$this->app->instance(TwoFactorAuthenticatorInterface::class, $twoFactor);
Symfony-Laravel Abstraction Gaps:
EventDispatcher or HttpFoundation may not work out-of-the-box.Events or wrap Symfony components:
use Symfony\Component\EventDispatcher\EventDispatcher as SymfonyDispatcher;
$dispatcher = new SymfonyDispatcher();
$dispatcher->addListener('security.totp.verified', function ($event) {
event(new \App\Events\TotpVerified($event->getUser()));
});
Database Schema Mismatches:
secret, algorithm). Laravel’s migrations may conflict.use Scheb\TwoFactorBundle\Model\TwoFactorUserInterface;
class User extends Authenticatable implements TwoFactorUserInterface
{
// Implement required methods
}
Clock Skew in TOTP:
$twoFactor->checkCode($user, $code, 60); // 60-second tolerance
Middleware Order:
Kernel.php with correct priority:
protected $middlewareGroups = [
'web' => [
// ...
\App\Http\Middleware\VerifyTotp::class,
],
];
Backup Code Security:
$user->backup_codes = encrypt(json_encode($backupCodes));
Enable Debug Logging: Configure the bundle to log TOTP events:
// config/2fa.php
'debug' => env('APP_DEBUG', false),
'log' => [
'enabled' => true,
'path' => storage_path('logs/totp.log'),
],
Test with Mock Time: Simulate TOTP code generation for testing:
$twoFactor->setTimeProvider(new \Scheb\TwoFactorBundle\Security\TimeProvider(1234567890));
Validate QR Codes: Use tools like Google Authenticator to test QR generation.
Custom TOTP Algorithms: Extend the authenticator to support additional algorithms:
use Scheb\TwoFactorBundle\Security\TwoFactorAuthenticatorInterface;
class CustomTotpAuthenticator implements TwoFactorAuthenticatorInterface
{
public function checkCode($user, $code, $timeWindow = 0)
{
// Custom logic (e.g., SHA-256 instead of SHA-1)
}
}
Dynamic Secret Rotation: Implement a cron job to rotate secrets periodically:
// app/Console/Commands/RotateTotpSecrets.php
public function handle()
{
$users = User::whereNotNull('totp_secret')->get();
foreach ($users as $user) {
$newSecret = $this->twoFactor->generateSecret();
$user->totp_secret = $newSecret;
$user->save();
// Send notification to user
}
}
Hardware Key Support:
How can I help you explore Laravel packages today?