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.
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:
project_id and site_key.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.// 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.
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>
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.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.getReasons() (enum values like AUTOMATION, UNEXPECTED_USAGE, LOW_CONFIDENCE_SCORE), and review before tightening.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).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.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.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.composer.json, and rely on IDE autocompletion over the vendored classes rather than online examples.How can I help you explore Laravel packages today?