Installation
composer require draw/user-bundle
Add the bundle to config/bundles.php:
return [
// ...
Draw\UserBundle\DrawUserBundle::class => ['all' => true],
];
Configure User Entity
Extend your User entity with TwoFactorAuthenticationUserTrait:
use Draw\UserBundle\Entity\TwoFactorAuthenticationUserTrait;
class User implements TwoFactorAuthenticationUserInterface
{
use TwoFactorAuthenticationUserTrait;
// ...
}
Enable 2FA for Admin
Follow the README’s 2FA setup (requires scheb/2fa-bundle). Key steps:
composer require scheb/2fa-bundle scheb/2fa-totp scheb/2fa-qr-code
scheb_two_factor (see README) and update security.yaml to include the admin firewall with two_factor.First Use Case Trigger 2FA setup for an admin user via a controller:
use Draw\UserBundle\Service\TwoFactorAuthenticator;
public function enable2FA(User $user, TwoFactorAuthenticator $authenticator)
{
$authenticator->generateSecret($user);
return $this->render('DrawUser/security/2fa_setup.html.twig', [
'secret' => $user->getTwoFactorSecret(),
]);
}
User Provisioning
Use the UserManager service to create/update users with 2FA capabilities:
$user = $userManager->createUser([
'email' => 'admin@example.com',
'roles' => ['ROLE_ADMIN'],
'twoFactorEnabled' => false, // Default
]);
2FA Integration
scheb/2fa-qr-code), and store it in the user entity.
$secret = $authenticator->generateSecret($user);
$qrCodeUrl = $qrCodeGenerator->getUrl($secret, 'Draw', 'admin@example.com');
scheb/2fa-bundle's built-in forms (admin_2fa_login) for TOTP validation.Role-Based Access
Restrict 2FA routes in security.yaml:
access_control:
- { path: ^/admin/2fa, roles: ROLE_ADMIN }
Event Listeners Extend functionality via events (e.g., log 2FA changes):
// config/services.yaml
Draw\UserBundle\EventListener\TwoFactorListener:
tags:
- { name: kernel.event_listener, event: draw.user.two_factor.enabled, method: onTwoFactorEnabled }
templates/DrawUser/security/.TwoFactorAuthenticator to validate tokens in API endpoints:
$isValid = $authenticator->validateToken($user, $token);
User table includes:
/**
* @ORM\Column(type="string", nullable=true)
*/
private $twoFactorSecret;
/**
* @ORM\Column(type="boolean")
*/
private $twoFactorEnabled = false;
Missing Trait/Interface
Forgetting to implement TwoFactorAuthenticationUserInterface or use TwoFactorAuthenticationUserTrait will cause runtime errors. Verify with:
if (!$user instanceof TwoFactorAuthenticationUserInterface) {
throw new \RuntimeException('User must implement TwoFactorAuthenticationUserInterface');
}
Secret Storage
The twoFactorSecret must be persisted before rendering the QR code. Failure to save the entity will result in a lost secret.
Firewall Configuration
Misconfigured two_factor in security.yaml (e.g., wrong provider or paths) will break admin login. Test with:
php bin/console debug:firewall
Dependency Conflicts
scheb/2fa-bundle requires Symfony 4.4+. Ensure compatibility:
composer require symfony/security-bundle:^4.4
2FA Not Triggering:
Check if the admin firewall is correctly configured with two_factor and the IS_AUTHENTICATED_2FA_IN_PROGRESS role is applied to /admin/2fa.
php bin/console debug:security
Token Validation Failing:
Verify the TwoFactorAuthenticationUserInterface methods (getTwoFactorSecret(), isTwoFactorEnabled()) return correct values. Log the user entity:
\Log::debug('User 2FA secret:', [$user->getTwoFactorSecret()]);
Custom Providers
Extend TwoFactorAuthenticator to support alternative 2FA methods (e.g., YubiKey):
class CustomTwoFactorAuthenticator extends TwoFactorAuthenticator
{
public function validateCustomToken(UserInterface $user, string $token): bool
{
// Custom logic
}
}
Event Dispatching
Trigger custom events for 2FA actions (e.g., draw.user.two_factor.verified):
$event = new TwoFactorVerifiedEvent($user);
$this->eventDispatcher->dispatch($event);
Template Overrides Customize 2FA flows by overriding Twig templates:
templates/
└── DrawUser/
└── security/
├── 2fa_login.html.twig # Override login form
└── 2fa_setup.html.twig # Override QR code setup
Database Schema
Add custom fields to the User entity for 2FA recovery (e.g., backup codes):
/**
* @ORM\Column(type="json", nullable=true)
*/
private $twoFactorBackupCodes = [];
How can I help you explore Laravel packages today?