eii / laravel-captcha
A configurable Laravel CAPTCHA layer for Cloudflare Turnstile and Google reCAPTCHA.
Requires
- php: ^8.2
- illuminate/contracts: ^11.0 || ^12.0 || ^13.0
- illuminate/http: ^11.0 || ^12.0 || ^13.0
- illuminate/support: ^11.0 || ^12.0 || ^13.0
- illuminate/validation: ^11.0 || ^12.0 || ^13.0
Requires (Dev)
- orchestra/testbench: ^9.0 || ^10.0 || ^11.0
- phpunit/phpunit: ^10.5 || ^11.0 || ^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-26 03:24:58 UTC
README
A configurable CAPTCHA integration for Laravel with Cloudflare Turnstile and Google reCAPTCHA adapters.
Development status: initial scaffold. Review and test the frontend widget lifecycle and Livewire integration before using this package in production. The package is intentionally fail-closed during server verification, but a scaffold is not a security audit.
Requirements
- PHP 8.2+
- Laravel 11, 12, or 13
- Livewire is optional; install a compatible Livewire version if you want the Livewire component.
Install
composer require eii/laravel-captcha php artisan vendor:publish --tag=eii-captcha-config
Configure .env:
EII_CAPTCHA_ENABLED=true EII_CAPTCHA_PROVIDER=turnstile EII_CAPTCHA_VERIFY_HOSTNAME=false EII_CAPTCHA_STRICT=false TURNSTILE_SITE_KEY= TURNSTILE_SECRET_KEY= # Or use Google reCAPTCHA: # EII_CAPTCHA_PROVIDER=recaptcha # RECAPTCHA_VERSION=v2 # RECAPTCHA_SITE_KEY= # RECAPTCHA_SECRET_KEY= # RECAPTCHA_SCORE_THRESHOLD=0.5
Optional defense-in-depth settings:
# Secondary hostname verification in your Laravel app (off by default) EII_CAPTCHA_VERIFY_HOSTNAME=false EII_CAPTCHA_ALLOWED_HOSTNAMES=example.com,www.example.com # Optional success-event logging for audit trails EII_CAPTCHA_LOG_SUCCESS=false
Do not use test credentials in production. Use provider-documented test keys or HTTP fakes in local development and automated tests. Never disable server-side verification merely because APP_ENV=local.
Blade
<form method="POST" action="{{ route('contact.store') }}"> @csrf <input name="email" type="email" required> <x-eii-captcha name="captcha" /> <button type="submit">Send</button> </form>
Include a scripts stack in your layout:
@stack('scripts')
Controller:
use Eii\Captcha\Rules\CaptchaRule; use Illuminate\Http\Request; public function store(Request $request) { $request->validate([ 'email' => ['required', 'email'], 'captcha' => ['required', new CaptchaRule()], ]); // Continue processing only after validation succeeds. }
Manual verification
use Eii\Captcha\Facades\Captcha; if (! Captcha::verify($request->input('captcha'), $request->ip())) { abort(422, 'CAPTCHA verification failed.'); }
Livewire
If Livewire is installed, a component is registered as eii-captcha-widget. Example:
<form wire:submit="save"> <input type="email" wire:model="email"> <livewire:eii-captcha-widget field="captcha" /> <button type="submit">Send</button> </form>
In the Livewire component, validate the submitted token on the server with the CaptchaManager or CaptchaRule; do not trust a client-side success event alone. This integration is an initial scaffold and needs browser-level tests and lifecycle hardening before production use.
Diagnostic command
php artisan eii-captcha:check
The command checks common local configuration errors. It cannot inspect allowed hostnames or keys configured in the Google or Cloudflare dashboards. For production, configure a hostname allowlist and enable EII_CAPTCHA_VERIFY_HOSTNAME=true.
To use hostname verification, add this to the published config (if you prefer config over env):
'verify_hostname' => true, 'allowed_hostnames' => ['example.com', 'www.example.com'],
Security notes
- Provider secrets are server-side only.
- Verification failures and provider outages fail closed.
- Do not trust a client-side widget's success state.
- Use separate development and production provider credentials.
- Configure allowed hostnames in both the provider dashboard and this package config when
verify_hostnameis enabled. - A localhost domain in a provider dashboard does not itself bypass server verification; accidentally accepting unverified tokens does.
- Verify reCAPTCHA v3 score and expected action for each protected operation.
- Review and test multiple widgets, Livewire DOM morphing, expired tokens, retries, CSP, and script loading before production deployment.