symfony/security-core
Symfony Security Core provides the foundation for authentication tokens, roles, voters, role hierarchies, and access decision management. Use it to build flexible authorization logic decoupled from user providers and integrate fine-grained access checks into apps.
To integrate symfony/security-core into a Laravel project, start by installing the package:
composer require symfony/security-core
Leverage the AccessDecisionManager to validate user permissions in controllers or services:
use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
use Symfony\Component\Security\Core\Authorization\Voter\RoleVoter;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
// In a Laravel service or controller
$accessDecisionManager = new AccessDecisionManager([
new RoleVoter(),
]);
$user = auth()->user(); // Laravel's authenticated user
$token = new UsernamePasswordToken($user, 'main', $user->getRoles());
if (!$accessDecisionManager->decide($token, ['ROLE_ADMIN'])) {
abort(403, 'Unauthorized');
}
UsernamePasswordToken or AnonymousToken for token creation.AccessDecisionManager + RoleVoter for role-based access.UserProviderInterface for custom user loading logic.User model with roles (e.g., ROLE_ADMIN, ROLE_EDITOR).RoleVoter and AuthenticatedVoter in AccessDecisionManager.$accessDecisionManager->decide($token, ['ROLE_ADMIN']); // Returns bool
public function handle(Request $request, Closure $next)
{
$user = auth()->user();
$token = new UsernamePasswordToken($user, 'main', $user->getRoles());
if (!$this->accessDecisionManager->decide($token, ['ROLE_ADMIN'])) {
abort(403);
}
return $next($request);
}
Extend VoterInterface for attribute-based checks (e.g., "can_edit_post"):
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
class PostVoter extends Voter
{
protected function supports(string $attribute, $subject): bool
{
return in_array($attribute, ['CAN_EDIT', 'CAN_DELETE']) && $subject instanceof Post;
}
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
$user = $token->getUser();
return $user->id === $subject->user_id; // Example logic
}
}
symfony/security-core alongside Laravel’s Auth facade for hybrid auth logic.public function handle($request, Closure $next)
{
if (!$this->accessDecisionManager->decide($request->user()->token, ['ROLE_USER'])) {
abort(403);
}
return $next($request);
}
AccessDecisionManager as a singleton in AppServiceProvider:
$this->app->singleton(AccessDecisionManager::class, function () {
return new AccessDecisionManager([new RoleVoter()]);
});
Token Lifecycle:
Role Hierarchy:
RoleHierarchyVoter requires explicit role inheritance configuration:
$roleHierarchy = new RoleHierarchy([
'ROLE_ADMIN' => ['ROLE_USER', 'ROLE_EDITOR'],
]);
User Providers:
loadUserByIdentifier() in custom providers. Laravel’s User model must implement UserInterface:
class User implements UserInterface
{
public function getRoles(): array { return $this->roles; }
public function eraseCredentials() { /* ... */ }
}
Deprecations:
eraseCredentials() in Symfony 8+. Use UserInterface without it or implement a no-op method.AccessDecisionManager to log votes:
$accessDecisionManager = new AccessDecisionManager([...], new DebugAccessDecisionVoter());
dd($token->getUser(), $token->getRoles(), $token->getCredentials());
ROLE_A → ROLE_B → ROLE_A).Custom Attributes:
Use #[IsGranted] with custom attributes (Symfony 7.3+):
#[IsGranted('CAN_MANAGE_USERS')]
public function sensitiveAction()
Register a voter to handle CAN_MANAGE_USERS.
Impersonation:
Extend AbstractGuardAuthenticator to support impersonation tokens:
$token = new UsernamePasswordToken($impersonatedUser, 'impersonate', ['ROLE_USER']);
$this->authenticator->authenticate($request, $token);
Performance:
Cache role hierarchies if using RoleHierarchyVoter:
$roleHierarchy = new RoleHierarchy([...], new ArrayCache());
TokenStorage is not directly compatible with Laravel’s Auth. Use middleware to bridge gaps:
$token = new UsernamePasswordToken(auth()->user(), 'main', auth()->user()->getRoles());
PersistentToken is not needed in Laravel; use Laravel’s session driver instead.How can I help you explore Laravel packages today?