sylius-labs/polyfill-symfony-security
PolyfillSymfonySecurity provides compatibility shims for Symfony Security, helping apps and libraries bridge differences across Symfony versions. Useful when supporting multiple Symfony releases without changing your codebase or adding hard dependencies.
Installation Add the package via Composer:
composer require sylius-labs/polyfill-symfony-security
No additional configuration is required for basic usage—it’s a polyfill, so it works transparently.
First Use Case
If you’re working on a Laravel project that needs Symfony Security components (e.g., Security, TokenStorage, UserProvider, or Voter interfaces) but can’t use Symfony’s full framework, this package bridges the gap.
Example:
use Symfony\Component\Security\Core\Security;
use SyliusLabs\PolyfillSymfonySecurity\Security as LaravelSecurity;
// In a Laravel service or controller:
$security = new LaravelSecurity(app('auth'));
$user = $security->getUser(); // Works like Symfony's Security component
Where to Look First
src/Security.php (core class).tests/ for edge cases (e.g., anonymous users, token storage).Use the polyfill to adopt Symfony’s security abstractions in Laravel. Common patterns:
Authentication:
use SyliusLabs\PolyfillSymfonySecurity\Security;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
$security = new Security(app('auth'));
$token = $security->getToken(); // Returns a TokenInterface-compatible object
if ($token && $token->getUser()) { ... }
Authorization (Voters):
Implement Symfony’s VoterInterface and integrate with Laravel’s gates/policies:
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use SyliusLabs\PolyfillSymfonySecurity\Authorization\Voter\LaravelVoter;
class CustomVoter extends LaravelVoter implements VoterInterface { ... }
User Providers:
Wrap Laravel’s UserProvider to match Symfony’s UserProviderInterface:
use SyliusLabs\PolyfillSymfonySecurity\User\LaravelUserProvider;
$provider = new LaravelUserProvider(app('auth')->createUserProvider());
$user = $provider->loadUserByUsername('john_doe');
Token Storage:
Use LaravelTokenStorage to bridge Symfony’s TokenStorageInterface:
use SyliusLabs\PolyfillSymfonySecurity\Security\LaravelTokenStorage;
$tokenStorage = new LaravelTokenStorage(app('auth'));
$tokenStorage->setToken($authToken); // Laravel's auth token
Event Dispatching: Forward Laravel’s auth events to Symfony’s event system (if needed):
use SyliusLabs\PolyfillSymfonySecurity\Event\LaravelEventDispatcher;
$dispatcher = new LaravelEventDispatcher(app('events'));
$dispatcher->dispatch(new InteractiveLoginEvent($user, $response));
Adapt Symfony’s Guard or AccessControl logic to Laravel middleware:
use SyliusLabs\PolyfillSymfonySecurity\Http\Middleware\SymfonyAuthMiddleware;
$middleware = new SymfonyAuthMiddleware(
app('auth'),
app('router')
);
app('router')->pushMiddleware($middleware);
Mock the polyfill in tests to isolate Symfony-specific logic:
$this->partialMock(Security::class, ['getUser'])
->method('getUser')
->willReturn($user);
Token Storage Inconsistencies
Auth::user() and Symfony’s TokenStorage may not always sync. Explicitly set/get tokens:
// Avoid:
$user = $security->getUser(); // May return null if token isn’t set
// Do:
$token = $security->getToken();
$user = $token ? $token->getUser() : null;
User Object Mismatches
User model implements Symfony’s UserInterface or AdvancedUserInterface where required. Use LaravelUser as a base:
use SyliusLabs\PolyfillSymfonySecurity\User\LaravelUser;
class AppUser extends LaravelUser { ... }
Event System Gaps
app('events')->dispatch(new \Illuminate\Auth\Events\Authenticated($user));
CSRF Protection
@csrf directive or csrf_token() helper.if (!$security->getToken()) {
throw new \RuntimeException('No authentication token found.');
}
\Log::debug('User loaded:', ['user' => $user, 'provider' => get_class($provider)]);
instanceof checks to confirm objects match expected interfaces:
if (!$token instanceof TokenInterface) {
throw new \InvalidArgumentException('Token must implement TokenInterface.');
}
Custom Voters
Extend LaravelVoter to add Laravel-specific logic to Symfony’s voter system:
class RoleVoter extends LaravelVoter {
protected function supports($attribute, $subject) {
return $attribute === 'ROLE_ADMIN' && $subject instanceof User;
}
protected function voteOnAttribute($attribute, $subject, TokenInterface $token) {
return $token->getUser()->hasRole('admin');
}
}
Authentication Providers
Create a LaravelAuthenticationProvider to integrate Laravel’s guards with Symfony’s AuthenticationProviderInterface.
Event Listeners Subscribe to Symfony events via Laravel’s event system:
app('events')->listen(
\Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent::class,
function ($event) {
\Log::info('Auth success:', ['user' => $event->getAuthenticationToken()->getUser()]);
}
);
security.yaml: This polyfill doesn’t replace Symfony’s configuration. Manually map settings (e.g., roles, providers) to Laravel’s config/auth.php.file, database, or redis).How can I help you explore Laravel packages today?