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

Filamentv3 Turnstile Laravel Package

afatmustafa/filamentv3-turnstile

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require afatmustafa/filamentv3-turnstile
    

    Publish the config file (if needed):

    php artisan vendor:publish --provider="Afatmustafa\Filamentv3Turnstile\Filamentv3TurnstileServiceProvider" --tag="config"
    
  2. Configure Cloudflare Turnstile Add your Turnstile site key and secret to .env:

    TURNSTILE_SITE_KEY=your_site_key
    TURNSTILE_SECRET_KEY=your_secret_key
    
  3. First Use Case: Add to a Form Attach the widget to a Filament form (e.g., Create or Edit resource):

    use Afatmustafa\Filamentv3Turnstile\Widgets\Turnstile;
    
    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                // ... other fields
                Turnstile::make('turnstile')
                    ->label('Verify You Are Human')
                    ->required(),
            ]);
    }
    
  4. Verify in Blade (if needed) For non-Filament forms, use the underlying laravel-turnstile package:

    @turnstile(['sitekey' => config('services.turnstile.site_key')])
    

Implementation Patterns

Common Workflows

1. Form Validation

  • The widget automatically validates Turnstile responses via Laravel's built-in validation rules.
  • Customize validation rules in the config (config/filamentv3-turnstile.php):
    'validation' => [
        'rule' => 'required|turnstile',
        'message' => 'Please complete the Turnstile challenge.',
    ],
    

2. Dynamic Site Key

Override the site key per form or widget:

Turnstile::make('turnstile')
    ->siteKey('custom_site_key_123')
    ->label('Custom Challenge'),

3. Integration with Filament Policies

Restrict access to forms requiring Turnstile:

public static function canAccess(): bool
{
    return auth()->user()->hasRole('admin'); // Example condition
}

4. Customizing the Widget Appearance

Pass options to the underlying Turnstile script:

Turnstile::make('turnstile')
    ->options([
        'theme' => 'light',
        'size' => 'compact',
    ]),

5. Handling Failed Verifications

Redirect or show a message on validation failure:

public function rules(): array
{
    return [
        'turnstile' => ['required', 'turnstile'],
    ];
}

public function messages(): array
{
    return [
        'turnstile.turnstile' => 'Verification failed. Please try again.',
    ];
}

Integration Tips

Laravel Turnstile Middleware

Use the underlying package's middleware for API routes:

Route::middleware(['turnstile.verify'])->group(function () {
    // Protected routes
});

Testing

Mock Turnstile responses in tests:

$this->actingAs($user)
    ->post('/form', [
        'turnstile' => 'mock_success_token',
    ])
    ->assertRedirect('/success');

Multi-Language Support

Localize Turnstile labels and messages:

Turnstile::make('turnstile')
    ->label(__('filament::resources.pages.verify-human')),

Gotchas and Tips

Pitfalls

1. Missing .env Configuration

  • Issue: Turnstile widget renders but fails silently.
  • Fix: Ensure TURNSTILE_SITE_KEY and TURNSTILE_SECRET_KEY are set in .env.
  • Debug: Check config('services.turnstile') in Tinker to verify keys.

2. CORS Errors

  • Issue: Turnstile verification fails with CORS errors.
  • Fix: Ensure your Cloudflare Turnstile settings allow requests from your domain.
  • Debug: Check browser console for Access-Control-Allow-Origin errors.

3. Token Expiry

  • Issue: Turnstile tokens expire after 2 minutes (default).
  • Fix: Refresh the token if the form takes longer to submit.
  • Tip: Use JavaScript to refresh the token dynamically:
    document.getElementById('turnstile-widget').reload();
    

4. Conflicting Assets

  • Issue: Turnstile script loads twice, causing errors.
  • Fix: Disable auto-registration in config:
    'auto_register_assets' => false,
    
    Then manually include the script in your layout:
    @vite(['resources/js/turnstile.js'])
    

5. Filament Cache Issues

  • Issue: Changes to the widget don’t reflect after caching.
  • Fix: Clear Filament’s view cache:
    php artisan filament:cache-clear
    

Debugging Tips

1. Enable Turnstile Debug Mode

Add to .env:

TURNSTILE_DEBUG=true

This logs verification responses to Laravel logs.

2. Inspect Network Requests

  • Open browser dev tools (F12) and check the POST /api/turnstile/verify request.
  • Verify the response token is sent correctly.

3. Validate the Secret Key

Ensure the secret key in .env matches the one in your Cloudflare Turnstile dashboard.

4. Check for JavaScript Errors

  • Turnstile relies on JavaScript. Ensure no errors block its execution:
    console.log('Turnstile loaded:', typeof turnstile !== 'undefined');
    

Extension Points

1. Custom Validation Logic

Extend the validation rule in app/Providers/AppServiceProvider.php:

use Illuminate\Support\Facades\Validator;

Validator::extend('custom_turnstile', function ($attribute, $value, $parameters, $validator) {
    // Custom logic (e.g., IP-based checks)
    return true; // or false
});

2. Override Widget Defaults

Create a custom widget class:

namespace App\Filament\Widgets;

use Afatmustafa\Filamentv3Turnstile\Widgets\Turnstile;

class CustomTurnstile extends Turnstile
{
    protected string $defaultOptions = [
        'theme' => 'dark',
        'callback' => 'customCallback',
    ];
}

3. Add Honeypot Fallback

Combine with Laravel Honeypot for extra security:

use App\Filament\Widgets\CustomTurnstile;

Turnstile::make('turnstile')
    ->required()
    ->afterStateUpdated(function (Turnstile $widget, ?string $state) {
        if (!$state) {
            $widget->addError('turnstile', 'Please complete the challenge.');
        }
    }),

4. Log Verification Attempts

Extend the Turnstile class to log attempts:

public function handleVerification(string $response)
{
    \Log::info('Turnstile verification attempt', ['response' => $response]);
    return parent::handleVerification($response);
}

5. Disable for Specific Users

Skip Turnstile for trusted users (e.g., admins):

Turnstile::make('turnstile')
    ->visible(fn () => !auth()->user()->isAdmin()),
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.
hamzi/corewatch
minionfactory/raw-hydrator
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