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

Cloud Recaptcha Enterprise Laravel Package

google/cloud-recaptcha-enterprise

Official Google Cloud PHP client for reCAPTCHA Enterprise, letting Laravel and PHP apps create assessments, manage site keys, and verify tokens through the Google Cloud API.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a generated Google API client, not a Laravel package. There is no service provider, no facade, and no config file to publish — you wire it up yourself.

composer require google/cloud-recaptcha-enterprise

Prerequisites, in order:

  1. Enable the reCAPTCHA Enterprise API in a Google Cloud project and create a score-based site key (Console → reCAPTCHA Enterprise → Create key). Note the project_id and site_key.
  2. Create a service account with roles/recaptchaenterprise.agent (assessments) — add .admin only if you will manage keys via code. Download the JSON key and point GOOGLE_APPLICATION_CREDENTIALS at it, or pass the path explicitly.
  3. Add config:
// config/services.php
'recaptcha' => [
    'project_id'  => env('RECAPTCHA_PROJECT_ID'),
    'site_key'    => env('RECAPTCHA_SITE_KEY'),
    'credentials' => env('GOOGLE_APPLICATION_CREDENTIALS'),
    'threshold'   => (float) env('RECAPTCHA_SCORE_THRESHOLD', 0.5),
],

Where to look first: Google\Cloud\RecaptchaEnterprise\V1\Client\RecaptchaEnterpriseServiceClient — specifically createAssessment(), plus the Assessment, Event, TokenProperties, and RiskAnalysis message classes. The generated source is the real documentation here; with 0 dependents on Packagist you will not find many blog posts.

First use case — verify a login token server-side:

use Google\Cloud\RecaptchaEnterprise\V1\Client\RecaptchaEnterpriseServiceClient;
use Google\Cloud\RecaptchaEnterprise\V1\{Assessment, CreateAssessmentRequest, Event};

$client = app(RecaptchaEnterpriseServiceClient::class);

$event = (new Event())
    ->setSiteKey(config('services.recaptcha.site_key'))
    ->setToken($request->input('recaptcha_token'))
    ->setExpectedAction('login');

$assessment = $client->createAssessment(
    CreateAssessmentRequest::create([
        'parent'     => 'projects/' . config('services.recaptcha.project_id'),
        'assessment' => (new Assessment())->setEvent($event),
    ])
);

$props = $assessment->getTokenProperties();
$valid = $props->getValid()
    && $props->getAction() === 'login'
    && $assessment->getRiskAnalysis()->getScore() >= 0.5;

Older client releases expose the two-argument form createAssessment(string $parent, Assessment $assessment); check the method signature in vendor/ if the request-object style doesn't type-check.

Implementation Patterns

Bind the client as a singleton. The constructor resolves credentials and opens a gRPC channel — doing that per request is wasteful.

// app/Providers/AppServiceProvider.php
$this->app->singleton(RecaptchaEnterpriseServiceClient::class, fn () =>
    new RecaptchaEnterpriseServiceClient([
        'credentials' => config('services.recaptcha.credentials'),
    ])
);

Wrap it behind your own interface. Don't scatter createAssessment() calls through controllers. A small RecaptchaVerifier class returning a DTO (valid, score, action, invalidReason, assessmentName) gives you one place to change thresholds and one place to fake in tests.

Custom validation rule is the cleanest fit for form submissions:

class RecaptchaEnterpriseRule implements ValidationRule
{
    public function __construct(private string $action, private ?float $minScore = null) {}

    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $r = app(RecaptchaVerifier::class)->verify((string) $value, $this->action);
        if (! $r->valid)                       $fail('reCAPTCHA token is invalid.');
        if ($r->score < ($this->minScore ?? config('services.recaptcha.threshold')))
                                               $fail('reCAPTCHA score too low.');
    }
}
// $request->validate(['recaptcha_token' => [new RecaptchaEnterpriseRule('register')]]);

Middleware for route groups. Send the token in a header (X-Recaptcha-Token), verify in middleware for login, register, password/reset, checkout. Return 422 with a machine-readable code so the frontend can re-run grecaptcha.enterprise.execute() and retry once.

Per-action thresholds. A contact form at 0.5 is fine; account creation at 0.7 and checkout at 0.8 reduce fraud without blocking real users. Store them in config/services.php keyed by action rather than hard-coding.

Annotate after the outcome. Persist $assessment->getName() on the user session or a recaptcha_assessments table, then call annotateAssessment() when you learn the truth (PASSWORD_CORRECT, PASSWORD_INCORRECT, LEGAL, SUSPICIOUS_ACTIVITY, or Reason::CHARGEBACK_FRAUD). This is what trains the model for your site — it's the highest-leverage thing you can do long term.

Account Defender. Set ->setAccountId($user->id) on the Event for authenticated flows; then use listRelatedAccountGroups() / searchRelatedAccountGroupMemberships() to detect clusters of abusive accounts.

Key management from code (createKey, listKeys, updateKey) is useful for spinning up per-environment keys with testingOptions->setTestingScore(1.0) in staging/CI and never touching production keys by hand. Firewall policy methods (createFirewallPolicy) exist too, but they target Cloud Armor/WAF — not Laravel.

Frontend contract:

<script src="https://www.google.com/recaptcha/enterprise.js?render={{ config('services.recaptcha.site_key') }}"></script>
<script>
grecaptcha.enterprise.ready(async () => {
  const token = await grecaptcha.enterprise.execute('{{ config('services.recaptcha.site_key') }}', { action: 'login' });
  document.querySelector('#recaptcha-token').value = token;
});
</script>

Gotchas and Tips

  • Auth is the service account, not the site key. Could not construct ApplicationDefaultCredentials means GOOGLE_APPLICATION_CREDENTIALS is unset or the path is wrong after a config cache. Pass ['credentials' => storage_path(...)] explicitly if the env var is unreliable.
  • parent is projects/{project}, not the key. The site key belongs on Event::setSiteKey(). Passing the key name as parent yields a confusing INVALID_ARGUMENT.
  • Tokens are single-use and expire in ~2 minutes. Never verify the same token twice (e.g. in both FormRequest and middleware), and never retry createAssessment on failure — a retried token is already burned. Note that generated clients sometimes have built-in retry config; override retrySettings for createAssessment if you see duplicate attempts.
  • valid is not the whole story. Always check getValid(), getAction() === $expectedAction (case-sensitive), getHostname(), and getCreateTime() recency. A high score with the wrong action means someone reused a token from another form.
  • Scores are not probabilities of "human." Set thresholds per action, log the raw score + getReasons() (enum values like AUTOMATION, UNEXPECTED_USAGE, LOW_CONFIDENCE_SCORE), and review before tightening.
  • gRPC dependency. The client prefers gRPC; without ext-grpc you get Could not find the grpc extension. Either install it or force REST: new RecaptchaEnterpriseServiceClient(['transport' => 'rest', ...]) (transport option name varies by version — check ClientOptions in the vendored source).
  • Laravel Octane. A gRPC channel held in a singleton across worker forks can misbehave. Re-resolve the client per request via a scoped binding, or use the REST transport in Octane.
  • Error handling. Catch Google\ApiCore\ApiException: 400 = malformed token (frontend wiring / wrong key), 401/403 = IAM role missing, 429 = quota, 5xx = Google-side. Decide explicitly whether to fail-open (log and allow) or fail-closed for each route; 429 during a launch spike shouldn't take down login.
  • Testing. Bind a fake RecaptchaVerifier in tests rather than hitting the API. If you must exercise the real client, use a key configured with testingOptions->setTestingScore(1.0), and make sure that key never ships to production.
  • Don't confuse it with google/recaptcha. That package is the v2 checkbox siteverify call. This one is Enterprise-only and requires a GCP project. If all you need is "checkbox + yes/no," this is overkill; the value here is score, reasons, account defender, and annotations.
  • Low ecosystem footprint (13 stars, 0 dependents). Generated code changes shape between minor versions (request objects vs. positional args). Pin the version in composer.json, and rely on IDE autocompletion over the vendored classes rather than online examples.
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.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
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