Symfony Security
Authentication Library
Symfony Security
Overview
Symfony Security is the core security component of the Symfony framework. It provides a comprehensive system for authentication and authorization, integrating features like firewalls, authentication providers, and access control to enable secure web application development.
Details
Symfony Security offers flexible and extensible security features through modular design. Centered around the firewall system, it provides authentication mechanisms, role-based access control (RBAC), CSRF protection, two-factor authentication support, and other enterprise-level security requirements.
Key Components
- Firewall: Request filtering and authentication functionality
- Authenticator: Middleware that defines authentication methods
- User Provider: User information retrieval and loading
- Access Control: URL-based authorization rules
- Guard Middleware: Enforced authentication checks
Authentication Methods
- Form Login: Form-based authentication
- HTTP Basic: Basic authentication
- Bearer Token: JWT, API token authentication
- JSON Login: JSON format login
- X.509: Client certificate authentication
- Remote User: External authentication system integration
Advanced Security Features
- 2FA (Two-Factor Authentication): TOTP, SMS authentication
- Remember Me: Persistent login functionality
- CSRF Protection: Cross-site request forgery prevention
- Security Voters: Custom authorization logic
Pros and Cons
Pros
- Comprehensive Security: Complete coverage from authentication to authorization
- Flexible Configuration: Detailed configuration via YAML, XML, PHP
- Multiple Authentication Methods: Rich authentication options
- Enterprise Ready: Applicable to large-scale systems
- Community Support: Rich documentation and support
- Modular Design: Use only required features
Cons
- Learning Curve: Complex configuration requiring time to master
- Performance: Processing overhead due to multiple features
- Symfony Dependency: Exclusive to Symfony framework
- Configuration Complexity: Detailed settings required, difficult initial setup
Reference Links
- Symfony Security Documentation - Official documentation
- Symfony Security Configuration Reference - Configuration reference
- Symfony Security Best Practices - Security best practices
Code Examples
Basic Configuration (security.yaml)
# config/packages/security.yaml
security:
enable_authenticator_manager: true
password_hashers:
App\Entity\User:
algorithm: auto
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
form_login:
login_path: app_login
check_path: app_login
logout:
path: app_logout
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/profile, roles: ROLE_USER }
Custom Authentication Provider
<?php
// src/Security/ApiKeyAuthenticator.php
namespace App\Security;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
class ApiKeyAuthenticator extends AbstractAuthenticator
{
public function supports(Request $request): ?bool
{
return $request->headers->has('X-API-TOKEN');
}
public function authenticate(Request $request): Passport
{
$apiToken = $request->headers->get('X-API-TOKEN');
if (null === $apiToken) {
throw new CustomUserMessageAuthenticationException('No API token provided');
}
return new SelfValidatingPassport(new UserBadge($apiToken));
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
$data = [
'message' => strtr($exception->getMessageKey(), $exception->getMessageData())
];
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
}
Bearer Token Authentication Configuration
# config/packages/security.yaml
security:
firewalls:
api:
pattern: ^/api/
stateless: true
bearer_token:
token_handler: App\Security\AccessTokenHandler
main:
lazy: true
form_login:
login_path: app_login
check_path: app_login
Access Token Handler
<?php
// src/Security/AccessTokenHandler.php
namespace App\Security;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
class AccessTokenHandler implements AccessTokenHandlerInterface
{
public function getUserBadgeFrom(string $accessToken): UserBadge
{
// Token validation and user identification
if (!$this->isValidToken($accessToken)) {
throw new BadCredentialsException('Invalid credentials.');
}
$userIdentifier = $this->getUserIdentifierFromToken($accessToken);
return new UserBadge($userIdentifier);
}
private function isValidToken(string $token): bool
{
// Token validation logic
return hash('sha256', 'your-secret') === $token;
}
private function getUserIdentifierFromToken(string $token): string
{
// Get user identifier from token
return '[email protected]';
}
}
Multiple Authentication Methods Combination
# config/packages/security.yaml
security:
firewalls:
main:
lazy: true
provider: app_user_provider
# Enable multiple authentication methods simultaneously
form_login:
login_path: app_login
check_path: app_login
custom_authenticators:
- App\Security\SocialConnectAuthenticator
- App\Security\ApiKeyAuthenticator
# Explicitly specify entry point
entry_point: form_login
Guard Middleware Usage Example
<?php
// src/Controller/AdminController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class AdminController extends AbstractController
{
#[Route('/admin', name: 'admin_dashboard')]
#[IsGranted('ROLE_ADMIN')]
public function dashboard(): Response
{
// Only accessible to administrators
return $this->render('admin/dashboard.html.twig');
}
#[Route('/admin/users', name: 'admin_users')]
public function users(): Response
{
// Programmatic role verification
$this->denyAccessUnlessGranted('ROLE_ADMIN');
return $this->render('admin/users.html.twig');
}
}
CSRF Protection Implementation
<?php
// src/Form/LoginType.php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class LoginType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', TextType::class)
->add('password', PasswordType::class)
->add('login', SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'csrf_protection' => true,
'csrf_field_name' => '_token',
'csrf_token_id' => 'authenticate',
]);
}
}
User Entity Example
<?php
// src/Entity/User.php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
#[ORM\Entity]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private int $id;
#[ORM\Column(type: 'string', length: 180, unique: true)]
private string $email;
#[ORM\Column(type: 'json')]
private array $roles = [];
#[ORM\Column(type: 'string')]
private string $password;
public function getUserIdentifier(): string
{
return $this->email;
}
public function getRoles(): array
{
$roles = $this->roles;
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function getPassword(): string
{
return $this->password;
}
public function eraseCredentials(): void
{
// Clear temporary sensitive data
}
}