romanzipp/laravel-turnstile
Laravel package for integrating Cloudflare Turnstile into your forms. Includes validation rules, middleware, and a Blade component to protect against bots and spam with a privacy-friendly captcha alternative to reCAPTCHA.
Architecture fit. The package is a thin, stateless adapter — a service provider, a config file, a validation rule, and a Blade component that renders the Turnstile widget and calls Cloudflare's siteverify endpoint. It introduces no database schema, no migrations, no queue workers, and no background jobs. That is the right shape for this problem: bot mitigation is a request-time gate, not a domain concern, and it belongs in the validation layer where Laravel already centralizes form-input trust decisions. It composes cleanly with FormRequest classes and existing rule sets, so it does not fight the framework's idioms.
Integration feasibility. High. The work is composer require, publish config, set TURNSTILE_SITEKEY / TURNSTILE_SECRET in env, add the rule to the relevant FormRequest, and drop the component into the corresponding Blade form. Cloudflare publishes dummy sitekeys (always-pass, always-block, forced-interactive) that let us exercise every branch in CI and staging without touching production keys. Realistic effort: half a day for the first form including test coverage, then minutes per additional form.
Technical risk. The dominant risk is not code quality — it is stewardship. 32 stars, 0 dependents, and a single maintainer means: no security disclosure process, no release cadence guarantee, no downstream ecosystem acting as a canary, and a bus factor of one. The code is small enough (MIT-licensed, a few hundred lines) that this is mitigable rather than disqualifying — we can fork or vendor it and own it outright at trivial cost. The second risk is that this sits on the authentication/registration hot path, so the package's failure semantics matter more than its features. Specifically: does the rule fail closed when Cloudflare is unreachable, and what is the HTTP timeout? A default Guzzle timeout on a login form is an outage vector. Third, a Laravel major upgrade may strand the package if the maintainer goes quiet; that is a scheduled, predictable risk, not a surprise one.
Framing note. The low opportunity score is correct here: this package is a convenience wrapper, not a strategic dependency. The substantive product decision is "adopt Cloudflare Turnstile as our bot-mitigation vendor" (privacy posture, data residency, ToS, free-tier terms). The library decision is a trivially reversible one-line swap. Do not let the library's low adoption block a vendor decision that is independently sound.
Key questions.
composer.json constraints — which Laravel and PHP majors are supported today, and is there an open PR for the next major?siteverify call, and is it configurable? What happens on connection exception — validation failure or pass?action/cdata and explicit render mode, or only implicit rendering?illuminate/*, and do they clear composer audit?Stack fit. Assumes a conventional Laravel app on PHP 8.1+ with the framework HTTP client available. No Node build step, no asset pipeline changes — the widget is a Cloudflare-hosted script loaded directly by the component. Fits both Blade-rendered forms and, with minor manual work, Inertia/Livewire forms where the token must be pulled from the widget callback into the request payload.
Migration path. If we are currently on reCAPTCHA or a honeypot, the swap is per-form and reversible: keep the old rule in place, add Turnstile behind a config flag, compare block rates for a week, then remove the old rule. If we have no mitigation today, ship to the lowest-risk form first (contact/newsletter), not to login or signup.
Compatibility checks before committing.
challenges.cloudflare.com must be allowed in script-src and frame-src, or the widget silently fails to render and every submission fails validation.challenges.cloudflare.com (this is the most common staging/prod divergence)..env.Sequencing.
composer audit against the fork. (Do this first — it converts the stewardship risk into a non-issue.)siteverify latency separately from application errors.Maintenance. Low steady-state, with two recurring obligations: track Laravel majors (annual-ish) and track Cloudflare's siteverify API version. Owning the fork makes both a same-day fix rather than a wait on a stranger's GitHub notifications. Budget roughly one engineer-day per year plus upgrade-cycle attention.
Support. No vendor SLA, no paid support, GitHub issues only. Acceptable precisely because we own the code. Escalation path for Cloudflare-side incidents is Cloudflare's status page and our account support tier, not the package.
Scaling. Adds one outbound HTTPS round trip (~100–300ms) per protected submission. Negligible against form-submission volume; would only matter if applied to a high-QPS API endpoint, which it should not be. No shared state, so horizontal scaling is unaffected. Watch connection-pool exhaustion only under a bot flood — ironically, the scenario the widget exists to prevent, and the one where you must ensure the verification call itself is rate-limited and short-timeout.
Failure modes.
| Failure | Effect | Mitigation |
|---|---|---|
| Cloudflare outage | Fail-closed blocks all forms; fail-open admits spam | Explicit config policy per form; kill switch; short timeout |
| HTTP timeout too long | Thread/worker starvation under load | Pin timeout ~2–3s, verify configurable |
CSP missing frame-src |
Widget never renders, all submissions rejected | CSP test in staging; smoke test in CI |
| Blocked egress | Silent failure in one environment only | Egress check in deploy smoke test |
| Token expired (>300s) | Legitimate user sees validation error after idle | Clear, actionable error copy; client-side refresh |
| Maintainer abandons package | Stranded on next Laravel major | Fork/vendor; small enough to patch in-house |
| Secret leakage / rotation | Verification fails or is bypassed | Secret manager + rotation runbook |
Ramp-up. Very low. Any Laravel developer can read this package end-to-end in under an hour. The real ramp-up cost is organizational: getting the CSP change, egress allowance, and secret provisioning through platform/security review — that, not the code, is the critical path. Plan for two sprints of calendar time to clear those reviews and one sprint of actual engineering.
How can I help you explore Laravel packages today?