Add Google Recaptcha in Laravel 9
To prevent bots from registering into your web app you can add a Captcha. In this tutorial, I will show you how to add Google reCAPTCHA to the register page in laravel 9
Step 1. Custom Validation Rule
We will validate the recaptcha after submitting the form. So first, we will create a custom validation rule.
php artisan make:rule Recaptcha
This will create a file app/Rules/Recaptcha.php
. In this rule we need to do:
- Send an HTTP post request to Google to verify the captcha. We need to send the
secret key
,recaptcha token
, and userIP
. - Check if the response is successful, and if the returned score is bigger then minimal is set.
- If everything passes return
true
, otherwise returnfalse
.
app/Rules/Recaptcha.php
use Illuminate\Support\Facades\Http;
class Recaptcha implements Rule
{
public function passes($attribute, $value)
{
$response = Http::asForm()->post("https://www.google.com/recaptcha/api/siteverify", [
'secret' => config('services.recaptcha.secret_key'),
'response' => $value,
'ip' => request()->ip(),
]);
if ($response->successful() && $response->json('success') && $response->json('score') > config('services.recaptcha.min_score')) {
return true;
}
return false;
}
public function message()
{
return 'Failed to validate ReCaptcha.';
}
}
We store values from Google reCAPTCHA into config/services.php
:
return [
// ...
'recaptcha' => [
'site_key' => env('RECAPTCHA_SITE_KEY'),
'secret_key' => env('RECAPTCHA_SECRET_KEY'),
'min_score' => env('RECAPTCHA_MIN_SCORE', .5),
],
];
Step 2. Prepare Layout for reCAPTCHA
To use reCAPTCHA we need to add some scripts.
resources/views/layouts/guest.blade.php:
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
<!-- Scripts -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
<script src="https://www.google.com/recaptcha/api.js?render={{ config('services.recaptcha.site_key') }}"></script>
</head>
<body>
<div class="font-sans text-gray-900 antialiased">
{{ $slot }}
</div>
@stack('scripts')
</body>
</html>
resources/views/auth/register.blade.php:
<x-guest-layout>
<form method="POST" action="{{ route('register') }}">
<form method="POST" action="{{ route('register') }}" id="registerForm">
@csrf
// ...
@push('scripts')
<script>
grecaptcha.ready(function () {
document.getElementById('registerForm').addEventListener("submit", function (event) {
event.preventDefault();
grecaptcha.execute('{{ config('services.recaptcha.site_key') }}', { action: 'register' })
.then(function (token) {
document.getElementById("recaptcha_token").value = token;
document.getElementById('registerForm').submit();
});
});
});
</script>
@endpush
</x-guest-layout>