Search by

justin991q / cloudflare-turnstile

Justin991q

Cloudflare Turnstile captcha module for Laravel

Package info

gitlab.com/Justin991q/laravel-cloudflare-turnstile

Issues

pkg:composer/justin991q/cloudflare-turnstile

Statistics

Installs: 5

Dependents: 0

Suggesters: 0

Stars: 0

1.0.0 2026-10-25 13:06 UTC

This package is auto-updated.

Last update: 2026-10-25 12:29:28 UTC


README

A Laravel module for Cloudflare Turnstile, the privacy-friendly CAPTCHA alternative. It provides a Blade directive for the script, a widget view and a validation rule.

Requirements

  • PHP 8.3+
  • Laravel 11, 12 or 13

Installation

The package isn't published on Packagist, add one of the following repositories to your composer.json first.

GitLab package registry

Tagged releases are published to the GitLab Composer package registry, which is accessed at the group level:

"repositories": [
    {
        "type": "composer",
        "url": "https://gitlab.com/api/v4/group/<group_id>/-/packages/composer/packages.json"
    }
]

The registry requires authentication, use a personal access token (read_api scope) or a deploy token (read_package_registry scope):

composer config gitlab-token.gitlab.com <token>

Git repository

"repositories": [
    {
        "type": "vcs",
        "url": "https://gitlab.com/Justin991q/laravel-cloudflare-turnstile.git"
    }
]

Then require it:

composer require justin991q/cloudflare-turnstile

The service provider is registered automatically via package discovery.

Configuration

Add your Turnstile keys (from the Cloudflare dashboard) to your .env file:

CLOUDFLARE_TURNSTILE_SITE=your-site-key
CLOUDFLARE_TURNSTILE_SECRET=your-secret-key
VariableRequiredDefaultDescription
CLOUDFLARE_TURNSTILE_SITEYes—Site key, rendered in the widget
CLOUDFLARE_TURNSTILE_SECRETYes—Secret key, used to verify tokens server-side
CLOUDFLARE_TURNSTILE_VERIFY_URLNohttps://challenges.cloudflare.com/turnstile/v0/siteverifySiteverify endpoint
CLOUDFLARE_TURNSTILE_SCRIPT_URLNohttps://challenges.cloudflare.com/turnstile/v0/api.jsClient script URL
CLOUDFLARE_TURNSTILE_TIMEOUTNo5Verification request timeout in seconds

To customise the config file or the widget view, publish them:

php artisan vendor:publish --tag=turnstile-config
php artisan vendor:publish --tag=turnstile-views

Usage

Script

Load the Turnstile script with the @turnstile directive, typically in your layout's <head>. The argument is used as the script's CSP nonce:

@turnstile({{ app('csp-nonce') }})

Renders:

<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" defer nonce="..."></script>

Widget

Include the widget inside your form. It uses the configured site key and the application locale:

<form method="POST" action="/register">
    @csrf
    {{-- ... --}}
    @include('turnstile::widget')
</form>

Optionally pass the name of a global JavaScript function, called when the challenge succeeds:

@include('turnstile::widget', ['callback' => 'onTurnstileSuccess'])

The widget adds a cf-turnstile-response field to the form.

Validation

Validate the token with the Turnstile rule:

use Justin991q\CloudflareTurnstile\Rules\Turnstile;

$request->validate([
    'cf-turnstile-response' => ['required', new Turnstile()],
]);

The rule sends the token and the client IP to Cloudflare's siteverify endpoint and fails with "Captcha is invalid. Please try again." (translatable) when the token is rejected, the secret key is missing or Cloudflare is unreachable.

Verification is only enforced in production. In any other environment (APP_ENV other than production) the rule always passes, so local development and tests don't need real keys.

Verifying manually

The TurnstileVerifier is registered as a singleton and can be used directly:

use Justin991q\CloudflareTurnstile\TurnstileVerifier;

$valid = app(TurnstileVerifier::class)->verify($token, $request->ip());

Unlike the rule, the verifier always contacts Cloudflare, regardless of the environment.

Testing

composer install
composer test

The GitLab CI pipeline runs the test suite on PHP 8.3, 8.4 and 8.5 against Laravel 11 (PHP 8.3 and 8.4 only), 12 and 13.

Releasing

Push a semver tag, after the tests pass the pipeline publishes it to the GitLab package registry:

git tag v1.0.0
git push origin v1.0.0

License

The MIT License (MIT). See LICENSE for details.