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

Recaptcha2 Bundle Proxyable Laravel Package

jakreiter/recaptcha2-bundle-proxyable

A Symfony/PHP bundle that integrates Google reCAPTCHA v2 and adds proxy support for verification requests. Configure keys, render the widget, and validate form submissions through a proxy when required, making spam protection easier to deploy in restricted network environments.

View on GitHub
Deep Wiki
Context7

Getting Started

First, level-set: this is a Symfony bundle, not a Laravel package. There is no RecaptchaServiceProvider, no facade, no auto-discovery. jakreiter/recaptcha2-bundle-proxyable is a fork of beelab/recaptcha2-bundle whose only reason to exist is a configurable outbound HTTP proxy for the server-to-Google verification call. Everything else — form type, Twig widget, validator, service wiring — is Symfony-shaped and largely useless in a Laravel app.

Day-one checklist

  1. Read the upstream README first (BeelabRecaptcha2Bundle), not the fork's. The fork inherits its config keys, form type, and validator almost verbatim; the only delta you care about is the proxy option. Check src/DependencyInjection/Configuration.php in the fork to see the exact key name (proxy, http_proxy, or a DSN) and whether it is optional.
  2. Decide whether you actually need the bundle. In Laravel you almost never do. You need google/recaptcha plus a proxy-aware RequestMethod. The bundle is ~3 service definitions and a constraint validator; porting that is 30–60 lines.
  3. If you do install it, pin an exact version. The fork has 0 stars, 0 dependents, and is explicitly "in progress" — you do not want a floating constraint resolving to an untested commit.

Minimal Laravel wiring

composer require jakreiter/recaptcha2-bundle-proxyable google/recaptcha
// config/services.php
'recaptcha' => [
    'site_key'   => env('RECAPTCHA_SITE_KEY'),
    'secret_key' => env('RECAPTCHA_SECRET_KEY'),
    'proxy'      => env('RECAPTCHA_PROXY'), // http://user:[email protected]:3128
],
// app/Services/RecaptchaVerifier.php
namespace App\Services;

use ReCaptcha\ReCaptcha;
use ReCaptcha\RequestMethod\CurlPost;

class RecaptchaVerifier
{
    public function verify(?string $token, ?string $ip = null): bool
    {
        if (blank($token)) {
            return false;
        }

        // NOTE: verify this constructor signature against the installed
        // google/recaptcha version; proxy support has moved between
        // CurlPost::__construct() and ReCaptcha::setHttpClient() over time.
        $method = new CurlPost(config('services.recaptcha.proxy'));

        $response = (new ReCaptcha(config('services.recaptcha.secret_key'), $method))
            ->setExpectedHostname(request()->getHost())
            ->verify($token, $ip ?? request()->ip());

        if (! $response->isSuccess()) {
            logger()->warning('recaptcha rejected', ['codes' => $response->getErrorCodes()]);
        }

        return $response->isSuccess();
    }
}

First use case: a public contact form or registration form with a visible v2 checkbox. Render the widget in Blade, post g-recaptcha-response, verify server-side before persisting. The proxy matters only in the server→Google direction; the widget script is still fetched by the end user's browser from www.google.com.

Implementation Patterns

1. Validation rule wrapper (the Laravel analogue of the bundle's Recaptcha2 constraint).

class RecaptchaRule implements \Illuminate\Contracts\Validation\ValidationRule
{
    public function __construct(private RecaptchaVerifier $verifier) {}

    public function validate(string $attribute, mixed $value, \Closure $fail): void
    {
        if (! $this->verifier->verify($value)) {
            $fail('Please confirm you are not a robot.');
        }
    }
}

Then 'g-recaptcha-response' => ['required', new RecaptchaRule(app(RecaptchaVerifier::class))] in a FormRequest. This gives you the same ergonomics the Symfony bundle gets from its Recaptcha2Validator — one attribute, one constraint, no controller clutter.

2. Middleware for repeat offenders. For login and password-reset endpoints, put the check in a small middleware so you don't have to remember it in every controller. Keep it opt-in via route groups; captchas on every request wreck UX for authenticated users.

3. Invisible v2 with callback. The bundle's Twig theme handles this for Symfony; in Blade you write it yourself:

<div class="g-recaptcha" data-sitekey="{{ config('services.recaptcha.site_key') }}"
     data-callback="onRecaptcha"></div>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>

4. Config-driven disabling. The upstream bundle exposes enabled: false for test environments and the fork inherits it. In Laravel, mirror this with a config flag and a RecaptchaVerifier::verify() that short-circuits to true when app()->environment('testing', 'local') or config('services.recaptcha.enabled') === false. This is the single most valuable thing you take from the bundle — otherwise your feature tests all need a fake token.

5. Proxy via container config, not code. Whatever the fork's key is called, surface it as an env var and let ops set it per-environment. Do not hardcode a proxy DSN; corporate egress proxies rotate and you will be redeploying.

6. Front-end integration tips. Load api.js with async defer, put the widget below the fold for long forms, and always give the user a visible error path — Google returning timeout-or-duplicate should look like "please try again", not "you are a bot".

Gotchas and Tips

  • Symfony baggage. Installing this pulls symfony/http-kernel, symfony/form, symfony/validator, and symfony/config into your vendor/. That's hundreds of classes and a second DI container you will never use. If your only requirement is "call Google through a proxy", install google/recaptcha directly and save yourself the conflicts.
  • The fork lags upstream. With 0 stars and 0 dependents, it may miss upstream bug and security fixes. Diff it against beelab/recaptcha2-bundle before adopting, and check whether its composer.json declares replace on the upstream package — if it does, you can't have both installed, and any other package depending on upstream will silently get the fork.
  • Zero dependents means zero battle-testing. The last release: 2025-02-27 is recent, but "in progress" in the description is doing real work here. Treat the proxy path as unproven: write an integration test that hits a local proxy and asserts the request went through it (or at least that a bad proxy produces a network failure, not a "captcha invalid").
  • Distinguish network failure from user failure. ReCaptcha\Response::isSuccess() is false for both a bad token and a connection timeout through the proxy. getErrorCodes() will be empty on transport failure. Log the difference and show a retry message, or you will be debugging "the captcha is broken" tickets that are actually firewall tickets.
  • The proxy does not apply to the browser. Users still need to reach www.google.com to render the widget. In an air-gapped or China-style egress-restricted network, a server-side proxy solves exactly half the problem. Consider reCAPTCHA Enterprise's separate domains or an alternative if the browser side is also blocked.
  • remoteip behind load balancers. request()->ip() only works if TrustProxies is configured for your LB. Passing the LB's IP to Google weakens the check and pollutes their risk signals.
  • Token lifecycle. Tokens are single-use and expire in ~2 minutes. Verify once, store the result, not the token. Never verify in a queue job that may run after expiry.
  • Credentials in DSNs leak. A proxy DSN like http://user:pass@host:3128 will show up in config:cache output, exception traces, and any debug toolbar that dumps config. Prefer separate env vars and inject them where possible.
  • Testing. In phpunit.xml, set RECAPTCHA_ENABLED=false and have your RecaptchaRule honour it. For a true end-to-end test, bind a fake RecaptchaVerifier in the container rather than mocking Guzzle internals.
  • License. LGPL-3.0, not MIT. For a server-side Composer dependency used unmodified, that's usually fine, but if you fork it or statically link it into a distributed binary, get legal to look. MIT-licensed google/recaptcha plus your own ~40 lines avoids the question entirely.
  • Extension points if you stay on Symfony. Decorate Beelab\Recaptcha2Bundle\Recaptcha\RecaptchaService rather than subclassing; override the form type with a compiler pass only if you need custom widget attributes. For Laravel, the equivalent extension point is a container binding for RecaptchaVerifier, which is exactly what the code above gives you.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package