Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Security Core Laravel Package

symfony/security-core

Symfony Security Core provides the building blocks for authentication and authorization. Use tokens, voters, role hierarchies, and an access decision manager to cleanly separate access rules from user providers and credential storage.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup in Laravel

To integrate symfony/security-core into a Laravel project, start by installing the package and setting up a basic authentication workflow:

composer require symfony/security-core

First Use Case: Role-Based Access Control

  1. Define a User Entity: Implement Symfony\Component\Security\Core\User\UserInterface in your Laravel user model (e.g., app/Models/User.php):

    use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
    use Symfony\Component\Security\Core\User\UserInterface;
    
    class User implements UserInterface, PasswordAuthenticatedUserInterface
    {
        public function getRoles(): array
        {
            return ['ROLE_USER']; // Default role
        }
    
        public function getPassword(): string
        {
            return $this->password;
        }
    
        // ... other required methods
    }
    
  2. Create a Token: Use UsernamePasswordToken to represent an authenticated user:

    use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
    
    $user = User::find(1);
    $token = new UsernamePasswordToken(
        $user,
        'main', // Firewall name
        $user->getRoles()
    );
    
  3. Check Authorization: Use AccessDecisionManager to evaluate access:

    use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
    use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
    use Symfony\Component\Security\Core\Authorization\Voter\RoleVoter;
    
    $accessDecisionManager = new AccessDecisionManager([
        new AuthenticatedVoter(),
        new RoleVoter(),
    ]);
    
    if (!$accessDecisionManager->decide($token, ['ROLE_ADMIN'])) {
        abort(403, 'Access denied');
    }
    

Where to Look First:

  • Symfony Security Component Docs
  • src/Symfony/Component/Security/Core/Authorization/ for voters and decision managers.
  • src/Symfony/Component/Security/Core/Authentication/ for token and user provider logic.

Implementation Patterns

Core Workflows

1. Authentication Workflow

  • User Providers: Implement UserProviderInterface to load users (e.g., from a database or LDAP).
    use Symfony\Component\Security\Core\User\UserProviderInterface;
    
    class EloquentUserProvider implements UserProviderInterface
    {
        public function loadUserByIdentifier(string $identifier): UserInterface
        {
            return User::where('email', $identifier)->firstOrFail();
        }
    }
    
  • Authentication: Use AuthenticationManager to authenticate tokens:
    use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
    
    $authManager = new AuthenticationManager([
        new AuthenticationProvider($userProvider),
    ]);
    $authenticatedToken = $authManager->authenticate($token);
    

2. Authorization Workflow

  • Voters: Extend Voter for custom logic (e.g., TenantVoter):
    use Symfony\Component\Security\Core\Authorization\Voter\Voter;
    
    class TenantVoter extends Voter
    {
        protected function supports(string $attribute, mixed $subject): bool
        {
            return $attribute === 'ACCESS_TENANT';
        }
    
        protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
        {
            $user = $token->getUser();
            return $user->tenantId === $subject;
        }
    }
    
  • AccessDecisionManager: Combine voters for granular control:
    $accessDecisionManager = new AccessDecisionManager([
        new AuthenticatedVoter(),
        new RoleVoter(),
        new TenantVoter(),
    ]);
    

3. Role Hierarchies

  • Define hierarchies in config/security.php:
    'role_hierarchy' => [
        'ROLE_ADMIN' => ['ROLE_USER'],
        'ROLE_SUPER_ADMIN' => ['ROLE_ADMIN'],
    ],
    
  • Use RoleHierarchyVoter to enable inheritance:
    use Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter;
    use Symfony\Component\Security\Core\Role\RoleHierarchy;
    
    $roleHierarchy = new RoleHierarchy([
        'ROLE_ADMIN' => ['ROLE_USER'],
    ]);
    $accessDecisionManager->addVoter(new RoleHierarchyVoter($roleHierarchy));
    

4. Integration with Laravel Middleware

  • Create a middleware to wrap AccessDecisionManager:
    namespace App\Http\Middleware;
    
    use Closure;
    use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
    
    class AuthorizeMiddleware
    {
        public function __construct(
            protected AccessDecisionManagerInterface $decisionManager
        ) {}
    
        public function handle($request, Closure $next)
        {
            $token = auth()->user() ? auth()->user()->getToken() : null;
            if (!$this->decisionManager->decide($token, ['ROLE_ADMIN'])) {
                abort(403);
            }
            return $next($request);
        }
    }
    
  • Register in app/Http/Kernel.php:
    protected $routeMiddleware = [
        'admin' => \App\Http\Middleware\AuthorizeMiddleware::class,
    ];
    

5. Attribute-Based Access Control (ABAC)

  • Use VoteResult::ABSTAIN and extraData in voters for dynamic checks:
    protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
    {
        $attributes = $subject->getAttributes();
        if ($attributes['max_price'] > $token->getUser()->budget) {
            return false;
        }
        return true;
    }
    

Integration Tips

  1. Leverage Laravel’s Auth Facade: Extend Laravel’s Auth facade to use Symfony’s AuthenticationManager:

    use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
    
    class SymfonyAuthServiceProvider extends ServiceProvider
    {
        public function register()
        {
            $this->app->singleton(AuthenticationManagerInterface::class, function ($app) {
                return new AuthenticationManager([...]);
            });
        }
    }
    
  2. Caching Role Hierarchies: Cache the role hierarchy to improve performance:

    $roleHierarchy = new RoleHierarchy($roles, CacheInterface::class);
    
  3. Testing: Use Symfony’s TestUser for unit tests:

    use Symfony\Component\Security\Core\Authentication\Test\TestUser;
    
    $user = new TestUser(['ROLE_ADMIN'], 'john@example.com', ['name' => 'John']);
    $token = new UsernamePasswordToken($user, 'main', $user->getRoles());
    
  4. OAuth2 Introspection: Integrate with OAuth2 providers using OAuth2IntrospectionEndpoint:

    use Symfony\Component\Security\Core\Authentication\Provider\OAuth2IntrospectionProvider;
    
    $provider = new OAuth2IntrospectionProvider(
        $client,
        'https://oauth-provider.com/introspect'
    );
    

Gotchas and Tips

Pitfalls

  1. Token Serialization:

    • Issue: Tokens may not serialize correctly if roles or user data are not marked as public or serialized explicitly.
    • Fix: Implement Serializable interface or use serialize()/unserialize():
      public function serialize(): string
      {
          return serialize([
              $this->user->getRoles(),
              $this->credentials,
          ]);
      }
      
      public function unserialize(string $serialized): void
      {
          [$roles, $credentials] = unserialize($serialized);
          $this->user->setRoles($roles);
          $this->credentials = $credentials;
      }
      
  2. Role Hierarchy Caching:

    • Issue: Role hierarchies may not update in real-time if cached aggressively.
    • Fix: Use a cache with a short TTL or invalidate manually:
      $roleHierarchy = new RoleHierarchy($roles, CacheInterface::class, 300); // 5-minute TTL
      
  3. Voter Order Matters:

    • Issue: Voters are evaluated in order, and the first ACCESS_GRANTED or ACCESS_DENIED result stops further evaluation.
    • Fix: Place more specific voters (e.g., TenantVoter) before generic ones (e.g., RoleVoter).
  4. PHPUnit Mocking:

    • Issue: Avoid using PHPUnit mocks without expectations (deprecated in Symfony 7.4+).
    • Fix: Use createMock() with configured expectations or prefer self::assertInstanceOf():
      $mockUser = $this->createMock(UserInterface::class);
      $mockUser->method('getRoles')->willReturn(['ROLE_USER']);
      
  5. Remember-Me Cookies:

    • **
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4