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

Laravel Honeypot Laravel Package

spatie/laravel-honeypot

Protect Laravel forms from spam using a honeypot field plus a minimum-time check. Add the Blade component (or pass values manually for Inertia) and suspicious submissions are automatically discarded.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require spatie/laravel-honeypot
    

    Publish the config (optional):

    php artisan vendor:publish --provider="Spatie\Honeypot\HoneypotServiceProvider" --tag="honeypot-config"
    
  2. Add Honeypot to a Form: In your Blade template, include the honeypot component:

    <form method="POST" action="{{ route('contact.submit') }}">
        <x-honeypot />
        <!-- Your form fields -->
        <input name="email" type="text">
        <button type="submit">Submit</button>
    </form>
    
  3. Protect the Route: Apply the middleware to your form submission route:

    Route::post('/contact', [ContactController::class, 'store'])
        ->middleware(\Spatie\Honeypot\ProtectAgainstSpam::class);
    

First Use Case

Scenario: Protect a contact form from spam submissions.

  • Add <x-honeypot /> to your form.
  • Apply the middleware to the route handling submissions.
  • Test with a bot (e.g., this tool) to verify it blocks submissions with filled honeypot fields.

Implementation Patterns

Blade Integration

  • Component/Directive: Use <x-honeypot /> or @honeypot in Blade templates. Both inject two hidden fields:

    • my_name (configurable): Should always be empty for valid submissions.
    • valid_from: Encrypted timestamp to detect rapid submissions (default: 1 second threshold).
  • Dynamic Forms: For dynamic forms (e.g., AJAX), manually include the fields:

    form.append('my_name', '');
    form.append('valid_from', '{{ $honeypot->encryptedValidFrom }}');
    

Middleware Strategies

  1. Route-Level Protection:

    Route::post('/contact', [ContactController::class, 'store'])
        ->middleware(\Spatie\Honeypot\ProtectAgainstSpam::class);
    
    • Pros: Granular control over which forms are protected.
    • Cons: Requires manual application to each route.
  2. Global Middleware: Add to app/Http/Kernel.php:

    protected $middleware = [
        // ...
        \Spatie\Honeypot\ProtectAgainstSpam::class,
    ];
    
    • Pros: Automatic protection for all forms.
    • Cons: Risk of false positives if honeypot fields are missing in some forms. Disable with honeypot_fields_required_for_all_forms: false in config.
  3. Middleware Groups: Protect specific groups (e.g., auth routes):

    Route::middleware(['web', \Spatie\Honeypot\ProtectAgainstSpam::class])->group(function () {
        Auth::routes();
    });
    

Inertia/Vue Integration

  1. Share Honeypot Data: In app/Http/Middleware/HandleInertiaRequests.php:

    public function share(Request $request): array {
        return array_merge(parent::share($request), [
            'honeypot' => new \Spatie\Honeypot\Honeypot(config('honeypot')),
        ]);
    }
    
  2. Render in Vue:

    <template>
        <div v-if="honeypot.enabled" style="display: none;">
            <input type="text" v-model="form[honeypot.nameFieldName]" :name="honeypot.nameFieldName">
            <input type="text" v-model="form[honeypot.validFromFieldName]" :name="honeypot.validFromFieldName" :value="honeypot.encryptedValidFrom">
        </div>
    </template>
    
    <script setup>
    const form = useForm({
        email: '',
        [defineProps(['honeypot']).honeypot.nameFieldName]: '',
        [defineProps(['honeypot']).honeypot.validFromFieldName]: defineProps(['honeypot']).honeypot.encryptedValidFrom,
    });
    </script>
    

Livewire Integration

  1. Add Trait and Property:

    use Spatie\Honeypot\Http\Livewire\Concerns\{UsesSpamProtection, HoneypotData};
    
    class ContactForm extends Component {
        use UsesSpamProtection;
    
        public HoneypotData $extraFields;
    
        public function mount() {
            $this->extraFields = new HoneypotData();
        }
    
        public function submit() {
            $this->protectAgainstSpam(); // Throws exception if spam
            // Process form...
        }
    }
    
  2. Blade Template:

    <form wire:submit="submit">
        <x-honeypot livewire-model="extraFields" />
        <!-- Form fields -->
    </form>
    

Custom Spam Responses

Extend the default BlankPageResponder:

use Spatie\Honeypot\SpamResponder\SpamResponder;

class CustomResponder implements SpamResponder {
    public function respond(): void {
        abort(403, 'Spam detected. Please try again.');
    }
}

Update config:

'respond_to_spam_with' => \App\SpamResponders\CustomResponder::class,

Gotchas and Tips

Pitfalls

  1. Missing Honeypot Fields:

    • If using global middleware, ensure all forms include <x-honeypot /> or @honeypot. Otherwise, legitimate submissions may fail.
    • Fix: Set 'honeypot_fields_required_for_all_forms': false in config or use route-level middleware.
  2. CSRF Token Conflicts:

    • The honeypot fields (my_name, valid_from) must not conflict with existing form fields (e.g., name, valid_from).
    • Fix: Customize field names in config:
      'name_field_name' => 'honeypot_name',
      'valid_from_field_name' => 'honeypot_timestamp',
      
  3. Livewire Property Binding:

    • Forgetting to bind livewire-model in <x-honeypot /> will cause the honeypot data to not sync with Livewire.
    • Fix: Always include livewire-model="extraFields" (or your property name).
  4. Inertia Form Submission:

    • If using Inertia, ensure the honeypot fields are included in the form data before submission. Omitting them triggers spam detection.
    • Fix: Verify the form includes:
      form[honeypot.nameFieldName]: '',
      form[honeypot.validFromFieldName]: honeypot.encryptedValidFrom,
      
  5. Time Zone Issues:

    • The valid_from timestamp uses the server's time zone. If your app uses a non-default time zone, submissions from users in other time zones might be flagged.
    • Fix: Ensure config('app.timezone') matches your expectations.
  6. CSP (Content Security Policy) Conflicts:

    • Hidden inline styles (used to hide honeypot fields) may violate CSP if not configured.
    • Fix: Enable 'with_csp': true in config and install laravel-csp.

Debugging Tips

  1. Log Spam Attempts: Extend the SpamProtection class to log blocked requests:

    use Spatie\Honeypot\SpamProtection;
    use Illuminate\Support\Facades\Log;
    
    class CustomSpamProtection extends SpamProtection {
        protected function checkForSpam(): void {
            try {
                parent::checkForSpam();
            } catch (\Spatie\Honeypot\Exceptions\SpamException $e) {
                Log::warning('Spam attempt blocked', [
                    'ip' => request()->ip(),
                    'user_agent' => request()->userAgent(),
                    'honeypot_field' => request()->honeypot_name,
                ]);
                throw $e;
            }
        }
    }
    

    Update config:

    'spam_protection' => \App\SpamProtection\CustomSpamProtection::class,
    
  2. Test with Real Bots: Use tools like Browserling Form Tester to simulate bot submissions. Fill the honeypot field manually to verify detection.

  3. Disable for Testing: Temporarily disable honeypot in config:

    'enabled' => env('HONEYPOT_ENABLED', false),
    

    Or override in .env:

    HONEYPOT_ENABLED=false
    

Extension Points

  1. Custom Validation Logic: Extend the SpamProtection class to add custom
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.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai