symfony/security
Symfony Security provides authentication, authorization, password hashing, firewalls, voters, and user providers for PHP apps. Supports modern security standards, multiple guards, access control rules, CSRF protection, and seamless integration with the Symfony ecosystem.
Installation
Add via Composer (Laravel already includes Symfony Security components via laravel/framework):
composer require symfony/security-bundle
(Note: Laravel’s built-in auth scaffolding uses Symfony Security under the hood, so this is often pre-configured.)
First Use Case: Basic Authentication
auth() helper or Auth facade to check authentication:
if (auth()->check()) {
$user = auth()->user();
}
Route::middleware(['auth'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});
Where to Look First
app/Http/Middleware/Authenticate.php: Core middleware leveraging Symfony’s AuthenticationProviderManager.Auth facade uses Symfony’s Guard system. Extend guards for custom logic:
// app/Providers/AuthServiceProvider.php
protected function guards()
{
return [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token', // Uses Symfony’s TokenGuard
'provider' => 'users',
],
];
}
Symfony\Component\Security\Core\User\UserProviderInterface:
class CustomUserProvider implements UserProviderInterface {
public function loadUserByIdentifier($identifier) {
return User::where('email', $identifier)->firstOrFail();
}
// ... other required methods
}
Voter interface for granular permissions:
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
class PostVoter extends Voter {
protected function supports(string $attribute, $subject): bool {
return $attribute === 'EDIT';
}
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool {
return $token->getUser()->id === $subject->user_id;
}
}
// app/Providers/AuthServiceProvider.php
protected $policies = [
Post::class => PostPolicy::class,
];
(Laravel’s Policy class extends Symfony’s Voter.)SessionAuthenticationStrategyInterface for stateless APIs or custom session handling.form_login, http_basic) in Laravel’s app/Http/Kernel.php or via middleware.@csrf directive uses Symfony’s CsrfTokenManager. Override token generation in app/Providers/AppServiceProvider:
public function register()
{
$this->app->singleton(Symfony\Component\Security\Csrf\CsrfTokenManagerInterface::class, function () {
return new CustomCsrfTokenManager();
});
}
InteractiveLoginEvent, AuthenticationSuccessEvent) via Laravel’s event system:
// app/Listeners/LogSuccessfulLogin.php
public function handle(AuthenticationSuccessEvent $event) {
Log::info('User logged in', ['user' => $event->getUser()]);
}
Register in EventServiceProvider.Session Fixation
session.regenerate() is called after login (Laravel’s AuthenticatesUsers trait handles this by default).AlwaysStoreSessionInterface can help enforce this.Token Expiry in Stateless APIs
User model:
public function tokens()
{
return $this->hasMany(Spatie\LaravelPermission\Models\Token::class);
}
TokenStorage to clear tokens on logout.Circular Dependencies in Voters
Voter::vote(). Cache results or use DTOs.Middleware Order Matters
auth middleware before throttle or custom middleware that might short-circuit requests.Enable Symfony’s Security Debug Tool:
// config/app.php
'providers' => [
Symfony\Bundle\DebugBundle\DebugBundle::class,
],
(Adds a security tab in Laravel Debugbar.)
Log Authentication Events:
// config/logging.php
'channels' => [
'security' => [
'driver' => 'single',
'path' => storage_path('logs/security.log'),
'level' => 'debug',
],
],
Then log events in listeners.
Dump Token Data:
dd(auth()->user(), auth()->token(), auth()->getLastAttempted());
Custom Authentication Providers
Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface for OAuth, LDAP, or custom backends.Firewall Layers
main, api) in app/Http/Kernel.php:
protected $middlewareGroups = [
'web' => [
// ...
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Symfony\Component\Security\Http\Firewall::class, // Symfony Firewall
],
];
Password Reset with Symfony’s UserCheckerInterface
Symfony\Component\Security\Core\User\UserChecker to validate users before password changes:
class CustomUserChecker implements UserCheckerInterface {
public function checkPreAuth(UserInterface $user) {
if (!$user->isActive()) {
throw new DisabledException('User account is disabled.');
}
}
}
Two-Factor Authentication (2FA)
TwoFactorAuthenticatorInterface or integrate with Laravel’s laravel-2fa package (which uses Symfony’s components).file/database session drivers work with Symfony Security, but redis requires additional config:
// config/session.php
'driver' => 'redis',
'connection' => 'cache',
SESSION_DOMAIN in .env to match Symfony’s SameSite cookie policies:
SESSION_DOMAIN=.yourdomain.com
Symfony\Component\Security\Core\User\UserProviderInterface::refreshUser() to avoid loading users unnecessarily.class CachedVoterDecorator implements VoterInterface {
private $decorated;
private $cache;
public function vote(TokenInterface $token, $object, array $attributes) {
$cacheKey = md5($token->getUser().serialize($object).$attributes[0]);
if ($this->cache->has($cacheKey)) {
return $this->cache->get($cacheKey);
}
$result = $this->decorated->vote($token, $object, $attributes);
$this->cache->put($cacheKey, $result, 3600);
return $result;
}
}
How can I help you explore Laravel packages today?