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

Turnstile Laravel Package

lambda-studio/turnstile

Laravel package for Cloudflare Turnstile captcha validation. Includes a ValidTurnstile validation rule to verify the cf-turnstile-response token in requests, plus a simple Blade form example using your configured site key and Turnstile script.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require lambda-studio/turnstile
    
  2. Publish Config

    php artisan vendor:publish --provider="LambdaStudio\Turnstile\TurnstileServiceProvider"
    

    Update .env with:

    TURNSTILE_SITE_KEY=your_site_key
    TURNSTILE_SECRET_KEY=your_secret_key
    
  3. First Validation Add the rule to a form request in app/Http/Requests:

    use LambdaStudio\Turnstile\Rules\ValidTurnstile;
    
    public function rules()
    {
        return [
            'cf-turnstile-response' => [
                'required',
                'string',
                new ValidTurnstile,
            ],
        ];
    }
    
  4. Frontend Integration Include the Turnstile widget in your Blade template:

    <div class="cf-turnstile" data-sitekey="{{ config('turnstile.site_key') }}"></div>
    <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
    

Implementation Patterns

Core Workflows

1. Form Validation

Pattern: Use the ValidTurnstile rule in form requests or controllers.

// In a controller
$request->validate([
    'cf-turnstile-response' => [new ValidTurnstile],
]);

Pro Tip: Extend the rule for custom logic:

use LambdaStudio\Turnstile\Rules\ValidTurnstile as BaseValidTurnstile;

class CustomValidTurnstile extends BaseValidTurnstile
{
    public function passes($attribute, $value)
    {
        // Add custom logic (e.g., IP whitelisting)
        return parent::passes($attribute, $value);
    }
}

2. Middleware Protection

Pattern: Apply ValidateTurnstile middleware to routes or globally.

// In app/Http/Kernel.php
protected $middleware = [
    \LambdaStudio\Turnstile\Http\Middleware\ValidateTurnstile::class,
];

Use Case: Protect admin routes or high-risk endpoints (e.g., password resets).

Customization: Override the middleware to exclude specific routes:

public function handle($request, Closure $next)
{
    if ($request->is('api/*')) {
        return $next($request);
    }
    return parent::handle($request, $next);
}

3. Facade/Service Usage

Pattern: Use the facade for direct API calls (e.g., in services).

use LambdaStudio\Turnstile\Facades\Turnstile;

public function verifyToken($token)
{
    return Turnstile::verify($token);
}

Use Case: Validate tokens outside form requests (e.g., API endpoints).

4. Error Handling

Pattern: Catch TurnstileException for graceful failures.

try {
    Turnstile::verify($token);
} catch (\LambdaStudio\Turnstile\Exceptions\TurnstileException $e) {
    return response()->json(['error' => 'CAPTCHA verification failed'], 400);
}

Custom Messages: Override translations in resources/lang/en/validation.php:

'turnstile' => [
    'invalid' => 'The CAPTCHA verification failed. Please try again.',
],

Integration Tips

Laravel Ecosystem

  • Form Requests: Prefer ValidTurnstile in form requests for clean separation.
  • Livewire/Inertia: Include the Turnstile script in your layout or component.
    @stack('scripts')
    @push('scripts')
        <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
    @endpush
    
  • API Routes: Use middleware or facade for non-form submissions.

Testing

  • Mocking Responses:
    use LambdaStudio\Turnstile\Facades\Turnstile;
    
    public function testValidation()
    {
        Turnstile::shouldReceive('verify')
            ->once()
            ->andReturn(true);
    
        $response = $this->post('/submit', ['cf-turnstile-response' => 'valid_token']);
        $response->assertRedirect('/success');
    }
    
  • Frontend Testing: Use Playwright/Puppeteer to simulate CAPTCHA completion.

Performance

  • Middleware: Apply only to necessary routes to avoid latency.
  • Caching: Cache failed tokens if retries are common (not built-in; implement manually).

Gotchas and Tips

Pitfalls

  1. Missing Frontend Script

    • Issue: CAPTCHA widget won’t render if the script is omitted.
    • Fix: Always include:
      <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
      
  2. Key Mismatch

    • Issue: site_key/secret_key mismatch causes silent failures.
    • Fix: Validate keys in a test route:
      Route::get('/test-turnstile', function () {
          return Turnstile::verify('invalid_token'); // Should return false
      });
      
  3. Null Values

    • Issue: Empty tokens may pass validation if not explicitly checked.
    • Fix: Add 'required' to the rule:
      'cf-turnstile-response' => ['required', new ValidTurnstile],
      
  4. Middleware Overhead

    • Issue: Global middleware adds latency to all routes.
    • Fix: Restrict to specific routes:
      Route::middleware(['turnstile'])->group(function () {
          Route::post('/contact');
      });
      
  5. PHP Version

    • Issue: Requires PHP 8.1+. Older versions will fail.
    • Fix: Upgrade or fork the package for older PHP.
  6. Rate Limiting

    • Issue: Cloudflare’s API has rate limits.
    • Fix: Monitor usage and implement retries with exponential backoff.

Debugging Tips

  1. Enable Logging Add to config/turnstile.php:

    'debug' => env('TURNSTILE_DEBUG', false),
    

    Logs will appear in storage/logs/laravel.log.

  2. Raw API Responses Use the service directly to inspect responses:

    $response = Turnstile::service()->verify($token);
    dd($response->getBody()->getContents());
    
  3. Common Errors

    • invalid: Token failed Cloudflare’s validation.
    • missing-input-secret: secret_key is missing or incorrect.
    • timeout-or-duplicate: Token expired or was already used.

Extension Points

  1. Custom Validation Logic Extend the ValidTurnstile rule:

    class CustomValidTurnstile extends \LambdaStudio\Turnstile\Rules\ValidTurnstile
    {
        public function passes($attribute, $value)
        {
            if (str_contains($value, 'test')) {
                return false; // Block test tokens
            }
            return parent::passes($attribute, $value);
        }
    }
    
  2. Blade Macros (Todo) Implement manually until the package adds them:

    use Illuminate\Support\Facades\Blade;
    
    Blade::directive('turnstile', function ($siteKey) {
        return <<<EOT
    <div class="cf-turnstile" data-sitekey="$siteKey"></div>
    @push('scripts')
        <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
    @endpush
    EOT;
    });
    

    Usage:

    @turnstile(config('turnstile.site_key'))
    
  3. Service Extensions Add custom methods to the service:

    namespace App\Services;
    
    use LambdaStudio\Turnstile\TurnstileService;
    
    class ExtendedTurnstileService extends TurnstileService
    {
        public function verifyWithRetry($token, $retries = 3)
        {
            for ($i = 0; $i < $retries; $i++) {
                try {
                    return parent::verify($token);
                } catch (\Exception $e) {
                    if ($i === $retries - 1) throw $e;
                    sleep(1);
                }
            }
        }
    }
    
  4. Event Listeners Listen for validation events (not built-in; use Laravel’s events):

    use Illuminate\Support\Facades\Event;
    use Illuminate\Validation\Events\ValidationFailed;
    
    Event::
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky