symfony/security-bundle
Symfony SecurityBundle integrates the Security component into the Symfony full-stack framework, providing authentication, authorization, and related security features with seamless configuration and framework tooling.
Installation:
composer require symfony/security-bundle
Add to config/bundles.php:
return [
// ...
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
];
Basic Configuration (config/packages/security.yaml):
security:
enable_authenticator_manager: true
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
firewalls:
main:
lazy: true
provider: app_user_provider
form_login: ~
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
First Use Case:
User entity with UserInterface and PasswordAuthenticatedUserInterface.use Symfony\Component\Security\Http\Attribute\IsGranted;
#[IsGranted('ROLE_USER')]
public function secureAction(): Response
{
return new Response('Secure content');
}
config/packages/security.yaml: Core configuration.src/Security/LoginFormAuthenticator.php: Custom authenticator example.src/Entity/User.php: User entity with roles/credentials.# config/packages/security.yaml
firewalls:
main:
form_login:
login_path: app_login
check_path: app_login
enable_csrf: true
app_login with AuthenticationUtils to handle login errors:
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
public function login(AuthenticationUtils $authenticationUtils): Response
{
$error = $authenticationUtils->getLastAuthenticationError();
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/login.html.twig', [
'error' => $error,
'last_username' => $lastUsername,
]);
}
Extend AbstractAuthenticator for OAuth, API tokens, or custom logic:
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
class CustomAuthenticator extends AbstractAuthenticator
{
public function supports(Request $request): ?bool
{
return $request->headers->has('X-API-TOKEN');
}
public function authenticate(Request $request): Passport
{
$token = $request->headers->get('X-API-TOKEN');
return new Passport(new ApiKeyAuthenticator($token));
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
return new RedirectResponse('/dashboard');
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
return new JsonResponse(['error' => $exception->getMessage()], 401);
}
}
Register in security.yaml:
firewalls:
api:
pattern: ^/api
stateless: true
custom_authenticator: app.custom_authenticator
# config/packages/security.yaml
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/profile, roles: ROLE_USER }
#[IsGranted('ROLE_ADMIN')]
public function adminDashboard(): Response
{
return new Response('Admin Panel');
}
Create a voter for complex logic (e.g., "can edit own profile"):
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
class ProfileVoter extends Voter
{
protected function supports(string $attribute, mixed $subject): bool
{
return $attribute === 'EDIT_PROFILE' && $subject instanceof User;
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
$user = $token->getUser();
return $user === $subject || $user->hasRole('ROLE_ADMIN');
}
}
Register in security.yaml:
security:
access_decision_manager:
strategy: affirmative
voters:
App\Security\ProfileVoter: ~
firewalls:
main:
lazy: true # Loads only when accessed
provider: app_user_provider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api:
pattern: ^/api
stateless: true
jwt: ~
main:
pattern: ^/
form_login: ~
# config/packages/security.yaml
security:
firewalls:
api:
pattern: ^/api
stateless: true
jwt: ~
providers:
api_user_provider:
entity:
class: App\Entity\User
property: apiToken
lexik/jwt-authentication-bundle for JWT generation/validation.# config/packages/security.yaml
security:
firewalls:
main:
oauth:
resource_owners:
google: ~
login_path: /connect/google
use_forward: false
failure_path: /login
Invalid CSRF token on form submission.enable_csrf: true in form_login and the form includes {{ form_row(form._token) }}.symfony/security-bundle:debug:firewall for active firewalls./contact).lazy: true carefully:
firewalls:
main:
lazy: true
remember_me:
secret: '%kernel.secret%'
lifetime: 86400
path: /login
ROLE_ADMIN not inheriting ROLE_USER permissions.security.yaml:
security:
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_USER: ROLE_GUEST
php bin/console debug:security:role-hierarchy
php bin/console debug:security:firewall
php bin/console debug:security:voter App\Entity\Post 1 EDIT
Enable debug logging in config/packages/monolog.yaml:
monolog:
handlers:
security:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.security.log"
level: debug
channels: ["security"]
hide_user_not_found (Symfony 8+).
authentication_failure_path with a custom handler.security:
oidc:
trusted_hosts:
- example.com
security:oidc-token:generate to debug token issues:
php bin/console security:oidc-token:generate
# config/packages/security.yaml
providers:
custom_provider:
id: App\Security\CustomUserProvider
UserProviderInterface:
class CustomUserProvider implements UserProviderInterface
{
public function loadUserByIdentifier(string $
How can I help you explore Laravel packages today?