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

Livewire Rate Limiting Laravel Package

danharrin/livewire-rate-limiting

Add rate limiting to Laravel Livewire actions to stop spam and brute-force clicks. Configure limits per component or method, with customizable keys, decay times, and responses when limits are exceeded—simple protection that feels native to Livewire.

Deep Wiki
Context7

Getting Started

First Steps

  1. Installation

    composer require danharrin/livewire-rate-limiting
    

    Publish the config file (if needed):

    php artisan vendor:publish --provider="DanHarrin\LivewireRateLimiting\LivewireRateLimitingServiceProvider"
    
  2. Basic Setup

    • Ensure your Livewire component has a rateLimited() method or uses the RateLimited trait.
    • Define rate limits in config/livewire-rate-limiting.php (e.g., 5/minute for a form submission).
  3. First Use Case Apply rate limiting to a Livewire action:

    use DanHarrin\LivewireRateLimiting\WithRateLimiting;
    
    class MyComponent extends Component
    {
        use WithRateLimiting;
    
        public function submitForm()
        {
            $this->rateLimited('submitForm', 5); // 5 requests per minute
            // Rest of the logic...
        }
    }
    

Implementation Patterns

Common Workflows

  1. Per-Action Rate Limiting Use rateLimited() on specific actions to enforce throttling:

    public function deleteItem()
    {
        $this->rateLimited('deleteItem', 3); // 3 deletes per minute
        // Delete logic...
    }
    
  2. Global Rate Limiting Apply a default limit to all actions in the component:

    use DanHarrin\LivewireRateLimiting\WithRateLimiting;
    
    class MyComponent extends Component
    {
        use WithRateLimiting;
    
        protected $rateLimits = [
            '*' => 10, // 10 requests per minute for all actions
        ];
    }
    
  3. Dynamic Limits Fetch limits from a database or API:

    public function submitForm()
    {
        $limit = UserRateLimit::forUser(auth()->id())->getLimit();
        $this->rateLimited('submitForm', $limit);
    }
    
  4. Custom Storage Override the default storage (e.g., Redis) by binding a custom RateLimitStore:

    $this->app->bind(\DanHarrin\LivewireRateLimiting\RateLimitStore::class, function () {
        return new \DanHarrin\LivewireRateLimiting\Stores\RedisStore();
    });
    
  5. User-Specific Limits Scope limits by user or IP:

    $this->rateLimited('submitForm', 5, 'user:' . auth()->id());
    

Integration Tips

  • Livewire Events: Combine with wire:click or wire:submit to trigger actions.
  • Frontend Feedback: Use Livewire’s wire:message or custom JS to show rate-limit notifications:
    @if ($this->exceededRateLimit('submitForm'))
        <div class="alert">Too many requests. Try again later.</div>
    @endif
    
  • Logging: Log exceeded attempts for analytics:
    if ($this->exceededRateLimit('submitForm')) {
        \Log::warning('Rate limit exceeded for submitForm', ['user' => auth()->id()]);
    }
    

Gotchas and Tips

Pitfalls

  1. Cache Invalidation

    • If using Redis/Memcached, ensure the store is properly flushed or TTLs are set to avoid stale limits.
    • Fix: Configure default_ttl in config/livewire-rate-limiting.php (e.g., 60 seconds).
  2. Key Collisions

    • Custom keys (e.g., user:123) must be unique. Reusing keys for unrelated actions can cause false limits.
    • Fix: Use descriptive keys like user:123:submitForm.
  3. Livewire Server-Side Rendering

    • Rate limits are enforced per user session, not per request. Shared sessions (e.g., tab switching) may bypass limits.
    • Fix: Use IP-based limits or session binding if needed:
      $this->rateLimited('submitForm', 5, 'ip:' . request()->ip());
      
  4. Testing Quirks

    • Mock the RateLimitStore in tests to avoid hitting real limits:
      $this->app->instance(RateLimitStore::class, new MockStore());
      
  5. Concurrent Requests

    • Livewire’s server-side nature means actions may execute concurrently. Rate limits are checked before execution.
    • Fix: Use sync on the component or adjust limits for high-traffic actions.

Debugging

  1. Check Limits Inspect the store directly:

    $store = app(RateLimitStore::class);
    $remaining = $store->remaining('user:123:submitForm');
    
  2. Enable Logging Add debug logs in config/livewire-rate-limiting.php:

    'debug' => env('RATE_LIMIT_DEBUG', false),
    
  3. Common Errors

    • Call to undefined method: Ensure the WithRateLimiting trait is used.
    • RateLimitStore not bound: Register the store in AppServiceProvider:
      $this->app->bind(RateLimitStore::class, function () {
          return new \DanHarrin\LivewireRateLimiting\Stores\CacheStore();
      });
      

Extension Points

  1. Custom Stores Implement DanHarrin\LivewireRateLimiting\Contracts\RateLimitStore for databases or external APIs:

    class DatabaseStore implements RateLimitStore {
        public function remaining(string $key): int { ... }
        public function increment(string $key): void { ... }
    }
    
  2. Middleware Apply rate limiting globally via middleware:

    public function handle(Request $request, Closure $next) {
        if ($request->wireable) {
            $this->app->make(WithRateLimiting::class)->checkRateLimits();
        }
        return $next($request);
    }
    
  3. Event Listeners Trigger events on rate limit exceeded:

    event(new RateLimitExceeded($key, $remaining));
    
  4. UI Customization Extend the default RateLimited view or use Alpine.js for dynamic counters:

    <span x-text="remainingAttempts"></span>
    <script>
        document.addEventListener('livewire:init', () => {
            Livewire.on('rateLimitUpdated', ({ remaining }) => {
                this.remainingAttempts = remaining;
            });
        });
    </script>
    
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