elvisblanco1993/livewire-v4-recaptcha
composer require elvisblanco1993/livewire-v4-recaptcha
php artisan vendor:publish --provider="ElvisBlanco\LivewireRecaptcha\LivewireRecaptchaServiceProvider" --tag="config"
.env or config/livewire-recaptcha.php:
RECAPTCHA_V3_SITE_KEY=your_v3_site_key
RECAPTCHA_V3_SECRET_KEY=your_v3_secret_key
RECAPTCHA_V2_SITE_KEY=your_v2_site_key
RECAPTCHA_V2_SECRET_KEY=your_v2_secret_key
AppServiceProvider@boot():
Livewire::component('recaptcha', \ElvisBlanco\LivewireRecaptcha\LivewireRecaptcha::class);
Add the directive to your Livewire component’s template:
<form wire:submit.prevent="submitForm">
<!-- Your form fields -->
<x-recaptcha type="v3" />
<button type="submit">Submit</button>
</form>
Validate the response in your component:
use ElvisBlanco\LivewireRecaptcha\Traits\ValidatesRecaptcha;
class MyComponent extends Component
{
use ValidatesRecaptcha;
public function submitForm()
{
$this->validateRecaptcha('v3'); // Validates v3 score (default: 0.5)
// Proceed with form logic...
}
}
<x-recaptcha type="v3" />).0.5):
$this->validateRecaptcha('v3', 0.7); // Strict validation
type="v2" or type="invisible".$this->validateRecaptcha('v2', request('g-recaptcha-response'));
config(['livewire-recaptcha.keys.v3' => [
'site_key' => env('RECAPTCHA_V3_SITE_KEY_STAGING'),
'secret_key' => env('RECAPTCHA_V3_SECRET_KEY_STAGING'),
]]);
$this->validateRecaptcha('v3', 0.0, ['test_key' => true]);
if (!$this->isTestMode()) {
$this->validateRecaptcha('v3');
}
use ElvisBlanco\LivewireRecaptcha\Traits\ValidatesRecaptcha as BaseValidatesRecaptcha;
trait ValidatesRecaptcha extends BaseValidatesRecaptcha
{
protected function recaptchaFailed($version)
{
return "reCAPTCHA {$version} verification failed. Please try again.";
}
}
$this->validate([
'email' => 'required|email',
'recaptcha' => [$this, 'validateRecaptcha:v3'],
]);
Key Mismatch:
site_key and secret_key are correctly paired for each version (v2/v3). Mixing keys will fail silently.config('livewire-recaptcha.keys') to verify loaded keys.CORS Issues:
type="v3" first (no CORS dependency).Livewire 4 Directive Scope:
Validation Timing:
validateRecaptcha() must be called after wire:submit.prevent or wire:submit to ensure the token is captured.// ❌ Wrong: Token may not be submitted yet
public function submitForm()
{
$this->validateRecaptcha('v3'); // Fails if token isn’t sent
// ...
}
v3 Score Thresholds:
0.5 for stricter security.0.9 for admin actions).try {
$this->validateRecaptcha('v3');
} catch (\Exception $e) {
\Log::error("reCAPTCHA validation failed: " . $e->getMessage());
session()->flash('error', 'reCAPTCHA error. Please refresh and retry.');
}
6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI) and pass g-recaptcha-response as 03AHJ_Rrh0... in tests.Custom Validation Logic:
validateRecaptcha() to add business rules:
public function validateRecaptcha($version, $score = null, $options = [])
{
if ($version === 'v3' && $score > 0.9) {
$this->addError('recaptcha', 'High-risk score detected. Manual review required.');
return false;
}
return parent::validateRecaptcha($version, $score, $options);
}
Async Validation:
wire:ignore to load reCAPTCHA scripts asynchronously:
<div wire:ignore>
<x-recaptcha type="v3" />
</div>
Multi-Step Forms:
public $recaptchaToken;
public function stepOne()
{
$this->recaptchaToken = request('g-recaptcha-response');
}
public function stepTwo()
{
$this->validateRecaptcha('v2', $this->recaptchaToken);
}
.env and config/livewire-recaptcha.php. Later values override earlier ones.// config/livewire-recaptcha.php
'keys' => [
'v3' => [
'site_key' => env('RECAPTCHA_V3_SITE_KEY', 'fallback_key'),
'secret_key' => env('RECAPTCHA_V3_SECRET_KEY', 'fallback_secret'),
],
],
RECAPTCHA_ENABLED=false in .env to bypass validation entirely (useful for local/dev).How can I help you explore Laravel packages today?