Weave 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

Recaptcha Bundle Laravel Package

snipershady/recaptcha-bundle

A Laravel/PHP bundle for adding Google reCAPTCHA protection to forms and requests. It provides key configuration and server-side verification to help block bots and spam with minimal setup in your application.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: the package is a Symfony bundle, not a Laravel package. There is no service provider, no facade, no config/ publish tag, and nothing that php artisan will discover. For a Laravel developer the practical value is (a) if you also maintain a Symfony app, or (b) as a reference implementation for the reCAPTCHA server-side flow you'll re-implement as a Laravel validation rule. Don't composer require it into a Laravel app expecting it to do anything.

Where to look in the repo, in order:

  1. composer.json — the symfony/framework-bundle and php constraints tell you which Symfony versions the 2025-03-02 release actually targets. This is the whole compatibility story.
  2. DependencyInjection/Configuration.php — the canonical list of config keys (public key, secret key, locale, enabled flag, version/type settings). Trust this file over the README.
  3. DependencyInjection/*Extension.php and Resources/config/* — how the form type is wired and what parameters/services it expects.
  4. Form/Type/ — the actual field class. Note its block prefix / form type alias; that string is what you reference in a Symfony form.
  5. Resources/views/ — the Twig block that emits the widget and the Google script tag.

First use case (Symfony side): add a reCAPTCHA field to a contact or registration form — configure the key pair, attach the bundle's form type to the form, render it, and let form validation reject a failed server-side check.

First use case (Laravel side): nothing to install. Build the equivalent — a recaptcha validation rule that POSTs to https://www.google.com/recaptcha/api/siteverify, keys in config/services.php fed from .env, and a Blade partial for the widget.

Implementation Patterns

Symfony app — the intended path

// config/packages/recaptcha.yaml (key name comes from Configuration.php)
# public_key / secret_key should be env() references, never literals

// in a form type
$builder->add('recaptcha', ReCaptchaType::class, [
    'invalid_message' => 'Please confirm you are human.',
]);
  • Keep the public key and secret in env vars (.env.local in dev, real secrets in your platform's secret store). Only the public key reaches the browser.
  • Let the bundle own the script tag. If you also include the Google JS yourself elsewhere in the layout, you'll get a double render or a "reCAPTCHA already loaded" warning.
  • Register test keys for local/staging in the Google admin console per domain, rather than disabling the field in config — that way local behaves like prod.
  • If your app has several forms with reCAPTCHA, reuse the one form type and one config block; don't create per-form variants or duplicate keys.

Laravel app — the pattern to port

Because the bundle's logic is essentially "render widget + POST token to siteverify + map result to a validation error", mirror that shape:

// config/services.php
'recaptcha' => [
    'site_key'   => env('RECAPTCHA_SITE_KEY'),
    'secret_key' => env('RECAPTCHA_SECRET_KEY'),
    'min_score'  => env('RECAPTCHA_MIN_SCORE', 0.5), // only meaningful for v3
],
  • One Rule object (RecaptchaRule) that calls siteverify with the token, the secret, and the client IP. Return a clear message; log the error-codes array for debugging.
  • One Blade component that outputs the script tag and the widget/g-recaptcha-response input, with the site key injected from config.
  • Apply the rule alongside the rest of your validation; don't bundle the check into a controller if statement.
  • For v3, the token is minted per action — pass action and validate the returned action and score in the rule, not just success.
  • For tests, bind a fake HTTP client for the siteverify host (Http::fake([...])) and assert both the pass and fail paths.

Mixed-repo integration tip

If you genuinely have a Symfony service and a Laravel app in the same org, keep this bundle confined to the Symfony service. The Laravel app should not depend on it transitively — a symfony/form pull-in inside a Laravel process is dead weight and a source of conflicting psr/* constraints.

Extension point (Symfony)

The usual way to change behaviour is to decorate the form type service or override the Twig block in your app's templates, not to fork the bundle. Forking a 0-star package means you own the maintenance of every future Symfony compatibility fix.

Gotchas and Tips

  • Zero stars, zero dependents, ~one recent release. Treat this as an unvetted fork. It descends from the long-standing EWZRecaptchaBundle; diff it against upstream before adopting, and pay attention to whether it carries forward the upstream security and Symfony-version fixes. Pin the exact version in composer.json and read the changelog/commit log before bumping.
  • No Laravel affordances at all. No auto-discovery, no publishes(), no config facade. Any tutorial that says "install this in Laravel" is wrong; you want google/recaptcha or a hand-rolled rule.
  • Key confusion. The site/public key goes in the HTML; the secret key stays server-side. Swapping them produces a widget that renders and a verification that always fails, with the error buried in Google's response — log error-codes.
  • Domain mismatch is silent in the UI. A key registered for example.com on localhost will render but not solve. The classic symptom is a checkbox that never completes; check the console for ERROR for site owner: Invalid domain for site key.
  • Google's published test keys always pass. Great for CI, catastrophic in production — grep your release checklist for them.
  • Server-side verification is the only real check. The client-side response is trivially spoofed. Never branch on "the checkbox was ticked"; always call siteverify from the server.
  • Validate the response body, not the HTTP status. siteverify returns HTTP 200 with "success": false. Also verify hostname and, for v3, action and score — otherwise a token minted on another action/domain is accepted.
  • Timeouts and failure mode. siteverify is an external dependency in your request path. Set an explicit timeout (2–5s) and decide deliberately whether a network failure fails open or closed; the bundle's form type will treat a broken call as invalid by default.
  • Don't edit vendor/. The rejection message is usually the form type's invalid_message — override it as a field option in your form type. If you need different validation logic, decorate the service.
  • Check whether the release you pulled is v2 (checkbox) or supports v3 (score). They have different widgets, different config keys, and different validation semantics; assuming v3 on a v2-only integration produces a widget that never renders a token.
  • Symfony constraint drift. With a single 2025 release, the PHP/Symfony upper bounds may already be tighter than your app. Resolve with composer why-not before upgrading Symfony, not after.
  • Local caching of the script. The Google JS bundle is cached aggressively by browsers; after changing keys or options, hard-reload before concluding the config didn't take.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle