buzz/laravel-google-captcha
Laravel integration for Google reCAPTCHA v2 and v3, adding validation rules, Blade directives and helpers to render and verify captchas. Configurable site/secret keys, score thresholds and error messages help protect forms from spam and bots with minimal setup.
What it actually is: A thin Laravel adapter around Google's reCAPTCHA. Concretely: a service provider, a config file (config/captcha.php), a Captcha class that calls Google's siteverify endpoint, a Blade directive to render the widget, and a custom validation rule (captcha). There is no database, no migration, no queue, no persistence, and no background work. It is a stateless HTTP convenience wrapper.
Architecture fit: Strong on convention, weak on necessity. It follows standard Laravel package auto-discovery and imposes no structural constraints on the host application — no service container gymnastics, no event contracts, no model assumptions. Removal is an afternoon's work, which is the right risk profile for a peripheral concern like bot mitigation. The genuine architectural decision is not "this package or another," it's "is Google reCAPTCHA in the submit path of every form?" That choice introduces an external dependency, a privacy/data-residency question, and an availability dependency into flows (registration, checkout, password reset) that are otherwise first-party.
Build vs. buy vs. vendor: The package is on the order of a few hundred lines. At 208 stars, zero indexed dependents, a single maintainer, and a composite score of 2.13, the community-scrutiny and bus-factor signals are weak. Adoption buys ergonomics — the Blade directive and the validation rule — not capability. A credible alternative is to inline the ~20-line Http::post('https://www.google.com/recaptcha/api/siteverify', ...) call behind your own validation rule and keep the widget markup in a Blade component. That eliminates the supply-chain question entirely and costs maybe half a day more. This should be an explicit decision, not a default.
Technical risk is asymmetric: blast radius is low (one validation rule, easily bypassed by removing it), but supply-chain risk is medium (one maintainer, low dependents, no commercial backing, uncertain support for future Laravel majors). The dangerous failure is not the package breaking loudly — it's a silent version constraint conflict during a framework upgrade that forces either a fork or a rushed removal on someone else's timeline.
Key questions to resolve before adoption:
action and score verification exposed, or only pass/fail?hostname and action, or only the boolean success? Verifying success alone is a meaningful weakening of v3.false, or silent pass?env() directly in the config file (breaks under config:cache) or only in config/captcha.php via env() at config-load time (correct)?composer.json versus our target matrix.Stack fit: Clean for a conventional Laravel monolith rendering Blade forms. Install via Composer with auto-discovery, publish the config, set NOCAPTCHA_SITEKEY / NOCAPTCHA_SECRET in the environment, drop @captcha in the form, add 'g-recaptcha-response' => 'required|captcha' to the FormRequest. It fits Inertia/SPA and mobile clients only partially — you'd render the widget client-side yourself and use the package solely for server-side verification, which is roughly half its value.
Migration path: Two directions worth naming.
anhskohbo/no-captcha) or hand-rolled verification: the API shapes differ enough that every form and every FormRequest rule needs touching. Do not treat this as a drop-in swap; it's a mechanical but broad edit. The mitigation is to never call the package directly from controllers — wrap it in our own ValidRecaptcha rule from day one, so the package is an implementation detail behind a seam we control.Compatibility checks before writing code: confirm the Laravel constraint against our current and next major; confirm config:cache safety; confirm the widget's script sources (google.com/recaptcha, gstatic.com) against our Content-Security-Policy; confirm test/staging domain registration in the Google admin console. CSP is the most common cause of "it works locally, invisible in production."
Sequencing:
Maintenance: Ongoing cost is genuinely low — a few hours per year — provided upstream keeps pace with Laravel majors. That is the one assumption to underwrite. If it lags, the fallback is a fork (small, tractable) or removal (also small). Budget an explicit check at each framework upgrade rather than discovering it during one.
Support: Community only. No SLA, no vendor to escalate to, README-level documentation. When something breaks, the practical escalation path is Google's reCAPTCHA documentation and a careful read of a few hundred lines of package source. Acceptable for a peripheral concern; unacceptable if anyone mistakenly treats captcha as a primary security control.
Scaling: One outbound HTTPS request per form submission, added to the critical path of that request. Negligible at low volume; at high volume it becomes a latency contributor and a rate-limit consideration against Google's quota, with no ability to cache (tokens are single-use). Connection pooling and keep-alive help. If submit volume is high or spiky, consider verifying asynchronously where the UX allows, or accept a short timeout with a fail-open policy.
Failure modes to design for:
Ramp-up: For a competent Laravel developer, two to four hours to a working integration, half a day including tests and CSP work. The costly part is not engineering — it is the cross-functional policy work (privacy notice, data processing implications, accessibility review, fail-open/closed decision, score-threshold ownership), which realistically takes a day or two of review across legal, security, and growth. Plan for that as the critical path, and treat the package itself as the easy part.
How can I help you explore Laravel packages today?