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

Login Gate Bundle Laravel Package

41man/login-gate-bundle

Symfony bundle that detects brute-force login attacks and temporarily blocks offending clients. Configurable max attempts, ban timeout and watch period, with ORM/session/MongoDB storage options and an event to hook custom handlers. Includes a checker service for allow/deny and clearing attempts.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle

    composer require anyx/login-gate-bundle
    

    Ensure your config/bundles.php includes:

    Anyx\LoginGateBundle\AnyxLoginGateBundle::class => ['all' => true],
    
  2. Configure Basic Settings Add to config/packages/login_gate.yaml (or config.yml for Symfony <5):

    login_gate:
        storages: ['orm']  # Default storage (ORM, session, or MongoDB)
        options:
            max_count_attempts: 3  # Lock after 3 failed attempts
            timeout: 600           # Ban duration in seconds (10 mins)
            watch_period: 3600     # For ORM storage: how long to keep attempts (1 hour)
    
  3. First Use Case: Protect Login Endpoint Inject BruteForceChecker into your login controller/service:

    use Anyx\LoginGateBundle\Service\BruteForceChecker;
    
    public function login(Request $request, BruteForceChecker $checker)
    {
        if (!$checker->canLogin($request)) {
            return $this->json(['error' => 'Too many attempts. Try again later.'], 429);
        }
        // Proceed with authentication...
    }
    

Implementation Patterns

Core Workflow: Brute-Force Detection

  1. Pre-Authentication Check Call canLogin($request) before processing login credentials. Example:

    if (!$checker->canLogin($request)) {
        $this->addFlash('error', 'Account locked due to brute-force attempts.');
        return $this->redirectToRoute('login');
    }
    
  2. Post-Failure Handling After a failed login, the bundle auto-increments attempts. Manually clear on success:

    try {
        $authenticator->authenticate($request);
        $checker->getStorage()->clearCountAttempts($request);
    } catch (AuthenticationException $e) {
        // Attempts are auto-tracked; no action needed.
    }
    
  3. Custom Storage Integration For non-ORM storage (e.g., session), ensure your Request has a unique identifier (e.g., session_id or user_ip). Example:

    login_gate:
        storages: ['session']
    

Advanced Patterns

  • IP-Based vs. User-Based Locking The bundle defaults to IP-based tracking. For user-specific locks (e.g., after account creation), extend the storage:

    $checker->getStorage()->setUserIdentifier($request, $user->getEmail());
    
  • Event-Driven Extensions Listen for security.brute_force_attempt to log or notify admins:

    services:
        App\EventListener\BruteForceLogger:
            tags:
                - { name: kernel.event_listener, event: security.brute_force_attempt, method: onAttempt }
    
    public function onAttempt(BruteForceAttemptEvent $event) {
        if ($event->getAttempts() >= 3) {
            Mailer::sendAlert($event->getIp());
        }
    }
    
  • Dynamic Thresholds Override max_count_attempts per route/user:

    $checker->setMaxAttempts($request, 5); // Temporarily allow 5 attempts
    

Gotchas and Tips

Pitfalls

  1. Storage Mismatches

    • ORM Storage: Requires a User entity with failedAttempts and lastAttempt fields. Run migrations if using auto-generated tables.
    • Session Storage: Fails if session_start() isn’t called before canLogin(). Ensure middleware/session config is correct.
    • MongoDB: Needs mongodb PHP extension and a login_attempts collection.
  2. Request Identifier Conflicts The bundle uses $request->getClientIp() by default. For shared IPs (e.g., cloud hosting), override:

    $checker->setRequestIdentifier($request, $request->get('user_agent') . $request->getClientIp());
    
  3. Race Conditions High-traffic sites may see false positives due to concurrent requests. Use watch_period to purge stale attempts:

    watch_period: 1800  # Keep attempts relevant for 30 mins
    
  4. Event Ordering The security.brute_force_attempt event fires after the attempt is counted. Avoid modifying $event->getAttempts() directly—use setMaxAttempts() for dynamic rules.

Debugging Tips

  • Log Attempts Enable debug mode to log brute-force events:
    $checker->getStorage()->logAttempt($request, true); // Force log
    
  • Clear Attempts Manually For testing, reset counts via:
    $checker->getStorage()->clearCountAttempts($request);
    
  • Check Storage Data Inspect raw storage (e.g., DB) to verify attempts are recorded:
    SELECT * FROM user WHERE failed_attempts > 0;
    

Extension Points

  1. Custom Storage Implement Anyx\LoginGateBundle\Storage\StorageInterface for new backends (e.g., Redis):

    class RedisStorage implements StorageInterface {
        public function countAttempts(Request $request) { /* ... */ }
        public function incrementAttempts(Request $request) { /* ... */ }
        // ...
    }
    

    Register it in config/packages/login_gate.yaml:

    login_gate:
        storages: ['redis']
    
  2. Override Default Logic Extend BruteForceChecker to add logic (e.g., whitelist IPs):

    class CustomBruteForceChecker extends BruteForceChecker {
        protected function isAllowed(Request $request) {
            if ($this->isWhitelisted($request)) {
                return true;
            }
            return parent::isAllowed($request);
        }
    }
    

    Bind it in services.yaml:

    Anyx\LoginGateBundle\Service\BruteForceChecker: '@App\Service\CustomBruteForceChecker'
    
  3. Two-Factor Workarounds If using 2FA, bypass brute-force checks for 2FA endpoints:

    if ($request->getPathInfo() === '/login/2fa') {
        return true; // Skip check
    }
    return $checker->canLogin($request);
    
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.
yandex/translate-api
voku/simple_html_dom
league/flysystem-vfs
bkwld/upchuck
filament/spatie-laravel-tags-plugin
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php