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

Icon Recaptcha Bundle Laravel Package

tbaronnat/icon-recaptcha-bundle

A Symfony bundle that integrates Google reCAPTCHA into forms, with configuration for API keys, a reusable form type, and server-side validation to help protect applications from spam and automated submissions.

View on GitHub
Deep Wiki
Context7

Getting Started

First, calibrate expectations: tbaronnat/icon-recaptcha-bundle is a Symfony bundle, not a Laravel package. It ships a Bundle class, DependencyInjection/Configuration.php, and Resources/config/services.* — none of which Laravel autoloads. As a Laravel dev you are evaluating it either because you maintain a Symfony app alongside Laravel, or because you want to borrow the integration pattern.

Where to look first, in this order:

  1. composer.json — confirm type: symfony-bundle, the required Symfony version constraint, and the last commit date. A 0-star bundle with no recent activity is a reference implementation, not a dependency.
  2. DependencyInjection/Configuration.php — this is the actual contract: which config keys (public_key, private_key, theme, size, lang, etc.) the bundle accepts and whether they map to env vars.
  3. Form/Type/ and Validator/Constraints/ — the two integration surfaces. Everything else is glue.
  4. Resources/views/ — the Twig snippet that renders the widget and injects the Google script tag.

Minimal Symfony install (if you actually are on Symfony):

composer require tbaronnat/icon-recaptcha-bundle
// config/bundles.php
Icon\ReCaptchaBundle\IconReCaptchaBundle::class => ['all' => true],
# config/packages/icon_recaptcha.yaml
icon_recaptcha:
    public_key:  '%env(RECAPTCHA_PUBLIC_KEY)%'
    private_key: '%env(RECAPTCHA_PRIVATE_KEY)%'
// Form
$builder->add('captcha', ReCaptchaType::class);

First use case: a contact or registration form. Register your Google keys, add the type to a form, submit, and confirm the server-side siteverify call succeeds — that round trip is the whole value of the package.

If you are on Laravel, do not install this. You will get an autoloaded Bundle class that never boots, a Symfony Configuration tree Laravel ignores, and zero ServiceProvider. Treat the repo purely as documentation for the reCAPTCHA flow and implement the ~30 lines yourself (see next section).

Implementation Patterns

Form-type composition (Symfony). The idiomatic use is adding the type to an existing form builder rather than calling the API directly. The type renders the widget and its constraint fires on POST:

$form = $this->createFormBuilder($contact)
    ->add('name', TextType::class)
    ->add('email', EmailType::class)
    ->add('captcha', ReCaptchaType::class)   // adds widget + constraint
    ->add('submit', SubmitType::class)
    ->getForm();

Standalone constraint. If you have a non-form entry point (JSON API, Livewire-style component, artisan-invoked job), instantiate the constraint and validate the token yourself instead of dragging in a Symfony form.

Config-first key handling. Always bind public/private keys through env vars, never hardcode. Distinguish the two: the public key is safe in the rendered page and cacheable; the private key must never leave the server and must be excluded from any cache-busting build step.

Laravel port — the pattern you actually want. The bundle's server-side logic is a single POST to Google. Reimplement it as a validation rule, which fits Laravel's day-to-day far better:

// app/Rules/Recaptcha.php
public function passes($attribute, $value)
{
    $res = Http::asForm()->timeout(5)->post(
        'https://www.google.com/recaptcha/api/siteverify',
        [
            'secret'   => config('services.recaptcha.secret'),
            'response' => $value,
            'remoteip' => request()->ip(),
        ]
    );

    if (! $res->ok() || ! $res->json('success')) {
        return false;
    }

    // v3 only: enforce score + action
    return ($res->json('score') ?? 1.0) >= 0.5
        && ($res->json('action') ?? 'submit') === 'submit';
}

Use it as 'g-recaptcha-response' => ['required', new Recaptcha], and render the widget in Blade with @push('scripts') so the Google <script> loads once per page.

Verification of v3 vs v2. Decide early. v2 (checkbox/invisible) is pass/fail — a single boolean. v3 returns a score 0.0–1.0 and an action string; you must check both, and the action check is what prevents a token harvested on /login being replayed on /checkout.

Integration into an existing pipeline. For AJAX/SPA flows, keep the widget mounted and regenerate tokens on demand (grecaptcha.execute for v3, grecaptcha.reset for v2) — tokens are single-use, so a failed validation must reset before the user retries.

Gotchas and Tips

  • It's Symfony-only and effectively unmaintained. Zero stars, no dependents, no Laravel service provider. Do not put it in a Laravel composer.json; you get dead weight and a class that never boots.
  • Tokens are single-use and expire (~2 minutes). Any retry, double-submit, or long-lived form will fail validation with a stale token. Always grecaptcha.reset() in the error path.
  • remoteip is optional but useful. Passing the client IP helps Google flag abuse; note it becomes wrong behind a proxy unless TrustProxies / setTrustedProxies is configured.
  • v3 score/action validation is the usual bug. Many integrations check success only, which means a score of 0.1 still passes. Always enforce a threshold (0.5 is Google's default suggestion) and match action.
  • Test keys vs real keys. Google's public test pair always passes/fails predictably; wire it into CI so you're not asserting against live reCAPTCHA. But keep the private key out of test fixtures committed to the repo.
  • No caching, no rate limiting. Every submission hits siteverify synchronously. Wrap the call in a short timeout (Google occasionally lags) and degrade gracefully — a 5s hang on your contact form is worse than a soft-fail.
  • CSP. The widget requires https://www.google.com/recaptcha/, https://www.gstatic.com/recaptcha/, and a frame-src for https://www.google.com. Missing directives produce a silently blank widget that looks like a backend bug.
  • Key placement. The bundle's Configuration will complain if public_key/private_key are missing, but it won't validate that they're the right version (v2 vs v3) — a mismatched key gives invalid-input-secret, not a helpful config error.
  • GDPR/consent. Loading the reCAPTCHA script sets Google cookies on page load. Gate the widget behind consent or use the invisible/v3 variant with an explicit disclosure.
  • Extension points are thin. If you're on Symfony, the realistic extension is swapping the HTTP client used for siteverify via a service override — otherwise you're editing the bundle. That's another reason to own the 30-line implementation yourself.
  • Debugging. When validation fails, decode the siteverify body — error-codes (missing-input-response, timeout-or-duplicate, invalid-input-secret) tells you precisely which layer broke, and it's the fastest way to distinguish a frontend rendering failure from a key or network problem.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin