⭐ Found this useful? Give it a star on GitHub! It helps us maintain and improve the project.
Symfony bundle for login throttling using native Symfony login_throttling feature with pre-configured settings.
This bundle replaces deprecated bundles like anyx/login-gate-bundle by using Symfony's native login throttling feature introduced in Symfony 5.2.
- ✅ Native Symfony
login_throttlingintegration - ✅ Pre-configured settings with sensible defaults
- ✅ Automatic configuration file generation
- ✅ Command to automatically configure
security.yaml - ✅ Multiple firewalls support - Configure independent throttling for each firewall
- ✅ Database storage support - Store login attempts in database for auditing
- ✅ Custom rate limiter support
- ✅ Compatible with Symfony 6.0, 7.0, and 8.0
- ✅ Easy migration from
anyx/login-gate-bundle - ✅ Same configuration options as the deprecated bundle
- ✅ Complete test suite with 100% coverage requirement
- ✅ Comprehensive documentation
- ✅ Demo project included
- ✅ GitHub Actions CI/CD
composer require nowo-tech/login-throttle-bundleThen, register the bundle in your config/bundles.php:
<?php
return [
// ...
Nowo\LoginThrottleBundle\NowoLoginThrottleBundle::class => ['all' => true],
];Note: If you're using Symfony Flex, the bundle will be registered automatically and a default configuration file will be created at
config/packages/nowo_login_throttle.yaml.
When installed, a default configuration file is automatically created at config/packages/nowo_login_throttle.yaml (if not using Flex, it will be created on first bundle boot).
You can configure the login throttling settings:
Single Firewall Configuration (Simple):
nowo_login_throttle:
enabled: true
max_count_attempts: 3
timeout: 600 # Ban period in seconds (600 = 10 minutes)
watch_period: 3600 # See docs: affects DB limiter service name / sharing; counting window is `timeout`
firewall: 'main' # Firewall name where login_throttling should be applied
storage: 'cache' # Storage backend: 'cache' (default) or 'database'
rate_limiter: null # Optional: Custom rate limiter service ID
cache_pool: 'cache.rate_limiter' # Cache pool for rate limiter state (only when storage=cache)
lock_factory: null # Optional: Lock factory service ID (only when storage=cache)Multiple Firewalls Configuration (Advanced):
nowo_login_throttle:
firewalls:
main:
enabled: true
max_count_attempts: 3
timeout: 600
storage: 'cache'
api:
enabled: true
max_count_attempts: 5
timeout: 300
storage: 'database'See Configuration Documentation for more details on multiple firewalls configuration.
| Option | Type | Default | Description |
|---|---|---|---|
enabled |
bool |
true |
Enable or disable login throttling |
max_count_attempts |
int |
3 |
Maximum number of login attempts before throttling (maps to max_attempts in Symfony login_throttling) |
timeout |
int |
600 |
Ban period in seconds (maps to interval in Symfony login_throttling, e.g., 600 = 10 minutes) |
watch_period |
int |
3600 |
With storage: database, part of the generated limiter service ID and shared-limiter grouping. Counting/ban window uses timeout. For pruning old DB rows, call LoginAttemptRepository::cleanup($watchPeriod) from your own scheduled task (see DATABASE_STORAGE.md). |
firewall |
string |
'main' |
Firewall name where login_throttling should be applied |
storage |
string |
'cache' |
Storage backend: 'cache' (uses Symfony cache) or 'database' (stores in database via Doctrine ORM). See DATABASE_STORAGE.md for details. |
rate_limiter |
string|null |
null |
Custom rate limiter service ID (optional). If not provided, Symfony will use default login throttling rate limiter, or database rate limiter if storage=database |
cache_pool |
string |
'cache.rate_limiter' |
Cache pool to use for storing the limiter state (only used when storage=cache) |
lock_factory |
string|null |
null |
Lock factory service ID for rate limiter (optional, only used when storage=cache). Set to null to disable locking |
Important: The bundle does NOT automatically configure security.yaml. You must run the command below or manually configure login_throttling in security.yaml.
After installing and configuring the bundle, you need to configure your security.yaml file with the login_throttling settings.
Run the provided command to automatically configure security.yaml:
php bin/console nowo:login-throttle:configure-securityThis command will:
- Read your
nowo_login_throttle.yamlconfiguration - Add or update
login_throttlingin yoursecurity.yaml - Configure all firewalls specified in your bundle configuration (single or multiple)
- Automatically set the correct rate limiter service IDs (especially important for database storage)
Note: If login_throttling is already configured in security.yaml, the command will skip it unless you use the --force option.
What Symfony uses: Symfony's security system reads security.yaml directly. The login_throttling configuration in security.yaml is what actually controls throttling behavior.
What happens if configurations differ:
- If
security.yamlhaslogin_throttlingconfigured butnowo_login_throttle.yamlhas different values, Symfony will use what's insecurity.yaml. - The bundle configuration (
nowo_login_throttle.yaml) is only used by the command as a template to updatesecurity.yaml. - To sync them, run:
php bin/console nowo:login-throttle:configure-security --force
Best Practice: Configure the bundle in nowo_login_throttle.yaml and run the command to keep security.yaml in sync.
Alternatively, you can manually add the login_throttling configuration to your config/packages/security.yaml:
security:
firewalls:
main:
login_throttling:
max_attempts: 3
interval: '10 minutes'The interval value is automatically converted from seconds (in your bundle config) to a human-readable format (e.g., 600 seconds = '10 minutes').
Important: When configuring manually, ensure the configuration matches nowo_login_throttle.yaml to avoid confusion. For database storage, you must also ensure the rate limiter service IDs are correct (they are automatically generated by the bundle when processing configuration).
This bundle is designed as a drop-in replacement for anyx/login-gate-bundle. The configuration options are compatible:
- Remove old bundle:
composer remove anyx/login-gate-bundle- Install new bundle:
composer require nowo-tech/login-throttle-bundle- Update configuration:
Before (anyx/login-gate-bundle):
# config/packages/login_gate.yaml
login_gate:
storages: ['orm']
options:
max_count_attempts: 3
timeout: 600
watch_period: 3600After (nowo-tech/login-throttle-bundle):
# config/packages/nowo_login_throttle.yaml
nowo_login_throttle:
enabled: true
max_count_attempts: 3
timeout: 600
watch_period: 3600
firewall: 'main'- Configure security:
php bin/console nowo:login-throttle:configure-security- Clear cache:
php bin/console cache:clearFor detailed migration instructions, including storage migration, code changes, and troubleshooting, see the complete migration guide.
This bundle uses Symfony's native login_throttling feature, which:
- Tracks failed login attempts per IP address and username combination
- Blocks further attempts when the maximum number of attempts is reached
- Automatically resets after the specified interval
- Uses Symfony's rate limiter component for efficient tracking
The throttling is handled automatically by Symfony's security system - you don't need to add any code to your controllers or authentication logic.
- PHP >= 8.1, < 8.6
- Symfony >= 6.0 || >= 7.0 || >= 8.0
- Symfony Security Bundle
- Symfony Rate Limiter component
Automatically configures security.yaml with login_throttling settings:
php bin/console nowo:login-throttle:configure-securityOptions:
--forceor-f: Force update even iflogin_throttlingis already configured
# Start the container
make up
# Install dependencies
make install
# Run tests
make test
# Run tests with coverage
make test-coverage
# Run all QA checks
make qacomposer install
composer test
composer test-coverage
composer qa- Makefile: Simplifies Docker commands for development
- PHP-CS-Fixer: Enforces PSR-12 code style
- PHPUnit: Complete test suite with coverage
- GitHub Actions: Automated CI/CD pipeline
The bundle includes comprehensive tests with 100% code coverage requirement. All tests are located in the tests/ directory.
# Run all tests
composer test
# Run tests with coverage report
composer test-coverageThe bundle requires 100% code coverage. The CI/CD pipeline validates this requirement automatically.
The bundle uses PHP-CS-Fixer to enforce code style (PSR-12).
# Check code style
composer cs-check
# Fix code style
composer cs-fixThe GitHub Actions CI/CD pipeline automatically:
- Checks code style on pull requests
- Applies code style fixes on push to main/master
- Validates 100% test coverage
- Runs tests on multiple PHP and Symfony versions
- Tests: PHPUnit (PHP)
- PHP: 51.74%
- TS/JS: N/A
- Python: N/A
The MIT License (MIT). Please see LICENSE for more information.
Contributions are welcome! Please feel free to submit a Pull Request.
Created by Héctor Franco Aceituno at Nowo.tech
For detailed examples of service configurations for different deployment scenarios:
- Local Development: File-based cache
- Docker Containers: Redis for shared state
- Kubernetes: Redis with lock factory for distributed systems
- Multiple Environments: Environment-specific configurations
See docs/SERVICES.md for complete examples.
A complete demo project is included in the demo/ directory demonstrating:
- Login throttling in action
- Configuration examples
- Docker setup for easy testing
- Complete authentication system
cd demo
make up-symfony7Access the demo at: http://localhost:8001
See demo/README.md for detailed instructions.
FrankenPHP worker mode: Supported and documented for demos in docs/DEMO-FRANKENPHP.md.