How to Integrate Google reCAPTCHA v3 in a Laravel Project

Learn how to integrate Google reCAPTCHA v3 in Laravel project for spam protection. Step-by-step guide with custom validation, and form integration.

How to Integrate Google reCAPTCHA v3 in a Laravel Project Image

Step 1: Create Google reCAPTCHA Credentials (Site Key & Secret Key)

Step 2: Set Up a Laravel Project

First, create a new Laravel project using the following command:

laravel new google-v3-reCAPTCHA

This will generate a fresh Laravel installation in a directory named google-v3-reCAPTCHA.

Step 3: Configure .env

Open the .env file and update the database configuration with your database credentials:

RECAPTCHA_URL=https://www.google.com/recaptcha/api/siteverify
V3_RECAPTCHA_SITE_KEY=**************************
V3_RECAPTCHA_SECRET_KEY=**************************

Step 4: Update config/services.php

Add the reCAPTCHA configuration to the config/services.php file:

'recaptcha' => [
        'url' => env('RECAPTCHA_URL'),
        'v3-recaptcha-site-key' => env('V3_RECAPTCHA_SITE_KEY'),
        'v3-recaptcha-secret-key' => env('V3_RECAPTCHA_SECRET_KEY'),
    ],

Step 5: Create a Migration File

Generate a migration file for the contacts table:

php artisan make:migration create_contacts_table

Update the migration file to define the table schema. For example:

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('contacts', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email');
            $table->timestamps();
        });
    }
    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('contacts');
    }
};

Run the migration to create the table:

php artisan migrate

Step 6: Create a Model

Generate a model for the Contact table:

php artisan make:model Contact

Update the model file if necessary, such as defining fillable fields:

App/Models/Contact.php

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Contact extends Model
{
    protected $guarded = [];
}

Step 7: Update the Routes

Define routes for the contact form in routes/web.php:

<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ContactController;
Route::get('/', function () {
    return view('welcome');
});
Route::get('contact', [ContactController::class, 'index'])->name('contactPage');
Route::post('contact', [ContactController::class, 'submit'])->name('contact');

Step 8: Create a Controller

Generate a controller for handling contact form submissions:

php artisan make:controller ContactController

Update the controller to include methods for displaying the form and processing submissions. For example:

App/Http/Controllers/ContactController.php

<?php
namespace App\Http\Controllers;
use App\Models\Contact;
use App\Http\Requests\ContactRequest;
class ContactController extends Controller
{
    public function index()
    {
        return view('contact');
    }
    public function submit(ContactRequest $request)
    {
        $data = $request->validated();
        unset($data['recaptcha']);
        Contact::create($data);
        return redirect(route('contactPage'))->with('success', 'Contact details save successfully');
    }
}

Step 9: Create a Form Request File

Generate a form request for validation:

php artisan make:request ContactRequest

Update the App/Http/Requests/ContactRequest.php file to include validation rules:

<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ContactRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        return true;
    }
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
     */
    public function rules(): array
    {
        $rules = [
            'name' => ['required', 'string'],
            'email' => ['required', 'string'],
            'recaptcha' => ['required', 'V3captcha'],
        ];
        return $rules;
    }
    public function messages()
    {
        return [
            'recaptcha' => 'Invalid Captcha Please try again',
        ];
    }
}

Step 10: Create a Custom Validator

Create a custom validator for reCAPTCHA v3. Save the file at app/Validators/V3Captcha.php:

<?php
namespace App\Validators;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
class V3Captcha
{
    /**
     * @throws GuzzleException
     */
    public function validate($attribute, $value, $parameters, $validator): bool
    {
        $client = new Client;
        $remoteIp = $_SERVER['REMOTE_ADDR'];
        $response = $client->post(
            config('services.recaptcha.url'),
            [
                'form_params' => [
                    'secret' => config('services.recaptcha.v3-recaptcha-secret-key'),
                    'response' => $value,
                    'remoteip' => $remoteIp,
                ],
            ]
        );
        $body = json_decode((string) $response->getBody());
        if (! $body->success) {
            return false;
        }
        if ($body->score >= 0.5) {
            return true;
        } else {
            return false;
        }
    }
}

Register the custom validator in the App\Providers\AppServiceProvider:

<?php
namespace App\Providers;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }
    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Validator::extend('V3captcha', 'App\\Validators\\V3Captcha@validate');
    }
}

Step 11: Add reCAPTCHA to the contact Form

Include the reCAPTCHA script and a hidden input field in your form:

resources/views/contact.blade.php:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Contact Us</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container mt-5">
        <div class="row justify-content-center">
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header bg-primary text-white text-center">
                        <h4>Contact Us</h4>
                    </div>
                    <div class="card-body">
                        @if (session('success'))
                            <div class="text-success">{{session('success')}}</div>
                        @endif
                        <form action="{{route('contact')}}" method="post">
                            @csrf
                            <div class="mb-3">
                                <input type="hidden" name="recaptcha" id="recaptcha">
                                @error('recaptcha')
                                    <div class="text-danger">{{$message}}</div>
                                @enderror
                            </div>
                            <div class="mb-3">
                                <label for="name" class="form-label">Name</label>
                                <input type="text" name="name" class="form-control" id="name" value="{{old('name') ?? ''}}" placeholder="Enter your name" />
                                @error('name')
                                <div class="text-danger">{{$message}}</div>
                                @enderror
                            </div>
                            <div class="mb-3">
                                <label for="email" class="form-label">Email</label>
                                <input type="email" name="email" class="form-control" id="email" value="{{old('email') ?? ''}}" placeholder="Enter your email" />
                                @error('email')
                                <div class="text-danger">{{$message}}</div>
                                @enderror
                            </div>
                            <button type="submit" class="btn btn-primary w-100">Submit</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script src="https://www.google.com/recaptcha/api.js?render={{ config('services.recaptcha.v3-recaptcha-site-key') }}"></script>
    <script>
        grecaptcha.ready(function() {
            grecaptcha.execute("{{ config('services.recaptcha.v3-recaptcha-site-key') }}", {action: 'submit'}).then(function(token) {
                if (token) {
                    document.getElementById('recaptcha').value = token;
                }
            });
        });
    </script>
</body>
</html>

 

Step 13: Run the Project

Start the Laravel development server:

php artisan serve

Note: Before testing, ensure that your project’s domain is added to the Google reCAPTCHA admin console.

Output:

google reCaptcha

Conclusion

By following these steps, you’ve successfully integrated Google reCAPTCHA v3 into your Laravel project. This will help protect your forms from spam and abuse while providing a seamless user experience. If you have any questions or run into issues, feel free to leave a comment below!

Happy coding! 🚀

Do you Like?