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 Cloudflare Turnstile Laravel Package

ryangjchandler/laravel-cloudflare-turnstile

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require ryangjchandler/laravel-cloudflare-turnstile
    

    Publish the config file:

    php artisan vendor:publish --provider="RyanChandler\CloudflareTurnstile\CloudflareTurnstileServiceProvider" --tag="config"
    
  2. Configure Cloudflare Turnstile Add your Turnstile site key and secret to config/services.php:

    'cloudflare-turnstile' => [
        'site_key' => env('CLOUDFLARE_TURNSTILE_SITE_KEY'),
        'secret_key' => env('CLOUDFLARE_TURNSTILE_SECRET_KEY'),
    ],
    

    Set these in your .env:

    CLOUDFLARE_TURNSTILE_SITE_KEY=your_site_key
    CLOUDFLARE_TURNSTILE_SECRET_KEY=your_secret_key
    
  3. First Use Case: Form Validation Add the validation rule to a form request or controller:

    use RyanChandler\CloudflareTurnstile\Rules\Turnstile;
    
    public function rules()
    {
        return [
            'turnstile_token' => ['required', new Turnstile],
        ];
    }
    
  4. Display the Turnstile Widget In your Blade template:

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

Implementation Patterns

Common Workflows

1. Form Integration

  • Request Validation Use the Turnstile rule in form requests or controllers:

    public function rules()
    {
        return [
            'turnstile_token' => ['required', new Turnstile],
        ];
    }
    

    Optionally, pass a custom error message:

    'turnstile_token' => ['required', new Turnstile('Invalid Turnstile token.')],
    
  • Handling Errors Customize error messages in your language files:

    'validation.turnstile' => 'The Turnstile verification failed.',
    

2. API Integration

  • Manual Verification Verify tokens programmatically (e.g., in API endpoints):

    use RyanChandler\CloudflareTurnstile\Facades\CloudflareTurnstile;
    
    $isValid = CloudflareTurnstile::verify($request->input('turnstile_token'));
    if (!$isValid) {
        return response()->json(['error' => 'Invalid Turnstile token'], 422);
    }
    
  • Async Verification For non-critical paths, use async verification with a queue job:

    CloudflareTurnstile::verifyAsync($token)->onQueue('verifications');
    

3. Dynamic Site Keys

  • Environment-Specific Keys Use different keys per environment (e.g., staging vs. production):

    'cloudflare-turnstile' => [
        'site_key' => env('CLOUDFLARE_TURNSTILE_SITE_KEY_' . app()->environment()),
        'secret_key' => env('CLOUDFLARE_TURNSTILE_SECRET_KEY_' . app()->environment()),
    ],
    
  • Multi-Tenant Keys Override keys per tenant using middleware or service providers:

    CloudflareTurnstile::setSiteKey($tenant->turnstile_site_key);
    

4. Blade Directives

  • Reusable Widgets Create a custom Blade component for consistency:

    @component('components.turnstile', ['sitekey' => config('services.cloudflare-turnstile.site_key')])
    @endcomponent
    
  • Dynamic Attributes Extend the @turnstile directive to include custom data attributes:

    @turnstile(['sitekey' => $siteKey, 'data-theme' => 'dark'])
    

5. Testing

  • Mocking Verification Use the CloudflareTurnstile facade in tests:

    CloudflareTurnstile::shouldReceive('verify')->once()->andReturn(true);
    

    Or stub the HTTP client:

    $this->mock(Http::class)->shouldReceive('post')->andReturn(Http::response(['success' => true]));
    
  • Test Helpers Create a trait for common test scenarios:

    trait TurnstileTests
    {
        protected function assertTurnstileValidation($token, $shouldPass = true)
        {
            $validator = Validator::make(['turnstile_token' => $token], ['turnstile_token' => [new Turnstile]]);
            $this->assertEquals($shouldPass, $validator->passes());
        }
    }
    

Gotchas and Tips

Pitfalls and Debugging

1. Configuration Issues

  • Missing .env Variables Ensure CLOUDFLARE_TURNSTILE_SITE_KEY and CLOUDFLARE_TURNSTILE_SECRET_KEY are set. The package won’t throw errors if these are missing, but validation will fail silently. Fix: Add validation in AppServiceProvider:

    if (empty(config('services.cloudflare-turnstile.site_key'))) {
        throw new \RuntimeException('Cloudflare Turnstile site key is not configured.');
    }
    
  • Incorrect Config Path The package expects keys under config('services.cloudflare-turnstile'). If you customize the config path, update the service provider:

    $this->app->singleton('cloudflare-turnstile', function ($app) {
        return new CloudflareTurnstile($app['config']['custom.cloudflare.turnstile']);
    });
    

2. Validation Failures

  • Silent Failures Turnstile validation errors may not bubble up as expected. Use ->sometimes() or custom messages:

    'turnstile_token' => ['required', 'sometimes', new Turnstile('Please complete the Turnstile challenge.')],
    
  • Rate Limiting Cloudflare may throttle requests. Implement retry logic:

    try {
        $isValid = CloudflareTurnstile::verify($token);
    } catch (\GuzzleHttp\Exception\RequestException $e) {
        if ($e->getCode() === 429) {
            retry()->times(3)->later(2)->try(fn() => CloudflareTurnstile::verify($token));
        }
        throw $e;
    }
    

3. CORS and API Issues

  • HTTP Client Errors If Turnstile API calls fail, verify:

    • Your secret_key is correct.
    • Cloudflare’s API endpoint (https://challenges.cloudflare.com/turnstile/v0/siteverify) is accessible.
    • No firewall/proxy is blocking the request. Debug: Enable Guzzle middleware to log requests:
    $client = Http::withOptions(['debug' => function ($config) {
        return array_merge($config, ['debug' => true]);
    }]);
    
  • IP Restrictions Ensure your server’s IP isn’t blocked by Cloudflare. Test with:

    curl -X POST "https://challenges.cloudflare.com/turnstile/v0/siteverify" \
         -d "secret=$SECRET_KEY" \
         -d "response=$TOKEN"
    

4. Blade Directive Conflicts

  • Directive Overrides If @turnstile conflicts with other packages, rename it in the service provider:

    Blade::directive('cfTurnstile', function ($expression) {
        return "<?php echo \\RyanChandler\\CloudflareTurnstile\\Blade::turnstile($expression); ?>";
    });
    

    Then use @cfTurnstile(['sitekey' => $key]) in Blade.

  • Escaping Issues If the widget HTML isn’t rendering, ensure no extra quotes or syntax errors exist in the directive call.

5. Performance Considerations

  • Async Verification Overhead Async verification adds queue processing time. Use it only for non-critical paths (e.g., newsletter signups). Alternative: Cache verification results for short-lived tokens (not recommended for security-sensitive paths).

  • Token Expiry Turnstile tokens expire quickly (typically 2 minutes). Avoid pre-verifying tokens before form submission.


Extension Points

1. Custom Verification Logic

  • Extend the Validator Create a custom rule by extending the Turnstile class:
    use RyanChandler\CloudflareTurnstile\Rules\Turnstile as BaseTurnstile;
    
    class CustomTurnstile extends BaseTurnstile
    {
        public function passed($attribute, $value)
        {
            $isValid = parent::passed($attribute, $value);
            // Add custom logic (e.g., check against a whitelist)
    
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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui