How to Add Google reCAPTCHA v3 to form in Laravel

Google reCaptcha v3 is a new version of reCaptcha where user doesn’t have to interact. It returns a score for each request which use to restrict form.

At the bottom of the page “protected by reCAPTCHA” icon is visible if integrated successfully.

In this tutorial, I show how you can add Google reCaptcha v3 to the form using the Laravel reCaptcha package in Laravel 9.

How to Add Google reCAPTCHA v3 to form in Laravel


Contents

  1. Get reCAPTCHA Keys
  2. Update .env
  3. Install Laravel reCAPTCHA Package
  4. Publish package
  5. Update recaptcha.php
  6. Clear caches
  7. Route
  8. Controller
  9. View
  10. Output
  11. Conclusion

1. Get reCAPTCHA Keys

  • Navigate to the following link and login into your account if not logged in.
  • Following page will display.

Google reCAPTCHA create form

  • Here, enter label, select reCAPTCHA v3 from the reCAPTCHA type, enter your domain name without https e.g. makitweb.com. You can also specify localhost if you want to test it on your local system.
  • Check the Accept the reCAPTCHA Terms of Service and click the Submit button.

Google recaptcha v3 details

  • Copy the site and secret keys.

Google recaptcha v3 site and secret keys


2. Update .env

  • Open .env file.
  • Create 2 variables for Google reCaptcha –
    • RECAPTCHA_SITE_KEY – Assign copied site key.
    • RECAPTCHA_SECRET_KEY – Assign copied secret key.
RECAPTCHA_SITE_KEY=6LdP-nIhAAAAAA6rzq7BTh_jKqIYeKMoaALxkKte
RECAPTCHA_SECRET_KEY=6LdV-nIhAAAAAL-uFI4w9kQUaqMkeU2K3KojlXyE

3. Install Laravel reCAPTCHA Package

Install the package using composer –

composer require biscolab/laravel-recaptcha

4. Publish package

Run the command –

php artisan vendor:publish --provider="Biscolab\ReCaptcha\ReCaptchaServiceProvider"

5. Update recaptcha.php

  • Open config/recaptcha.php file.
  • Update 'version' value from v2 to v3 if it is not set.
'version' => 'v3',

6. Clear caches

Run the following command –

php artisan config:cache

7. Route

  • Open routes/web.php file.
  • Define 2 routes –
    • / – Load index view.
    • pages/store – Handle form submit.

Completed Code

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PagesController;

Route::get('/', [PagesController::class, 'index']);
Route::post('pages/store', [PagesController::class, 'store'])->name('pages.store');

8. Controller

  • Create PagesController Controller.
php artisan make:controller PagesController
  • Include Validator – use Illuminate\Support\Facades\Validator;
  • Create 2 methods –
    • index() – Load index view.
    • store() – Handle form submission.

If validated successfully then set SESSION flash and redirect to / route otherwise return to the page with the error.

Completed Code

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Session;

class PagesController extends Controller
{
    public function index(){ 
       return view('index');
    }

    public function store(Request $request){

       $validator = Validator::make($request->all(), [
           'name' => 'required',
           'email' => 'required|email',
           'message' => 'required',
       ]);

       if ($validator->fails()) {
          return redirect()->Back()->withInput()->withErrors($validator);

       }else{
          Session::flash('message','Form submit Successfully.');
       }
       return redirect('/');
    }
}

9. View

Create index.blade.php file in resources/views/ folder.

HTML

Add <meta name="csrf-token"> to store csrf_token() in content attribute.

Display Bootstrap alert if SESSION is set.

Create <form action="{{ route('pages.store') }}" method="post" id="contactForm"> and add some elements.


reCaptcha Script

Add JavaScript code in <head> section.

Add {!! htmlScriptTagJsApi() !!} . Set  'callback_then' => 'callbackThen', and 'callback_catch' => 'callbackCatch'.

Create 2 functions –

  • callbackThen – Check recaptcha response. If the status is true and score is >= 0.6 means recaptcha is validated successfully otherwise display an error alert message and stop the page from submitting.
  • callbackCatch – For handling errors.

Completed Code

<!DOCTYPE html>
<html lang="en">
<head>
   <title>How to Add Google reCAPTCHA v3 to form in Laravel</title>
   <meta charset="utf-8">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <meta name="csrf-token" content="{{ csrf_token() }}">
   <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
   <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
   <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js"></script>

   <!-- Include script -->
   <script type="text/javascript">
   function callbackThen(response) {

     // read Promise object
     response.json().then(function(data) {
       console.log(data);
       if(data.success && data.score >= 0.6) {
          console.log('valid recaptcha');
       } else {
          document.getElementById('contactForm').addEventListener('submit', function(event) {
             event.preventDefault();
             alert('recaptcha error');
          });
       }
     });
   }

   function callbackCatch(error){
      console.error('Error:', error)
   }
   </script>

   {!! htmlScriptTagJsApi([
      'callback_then' => 'callbackThen',
      'callback_catch' => 'callbackCatch',
   ]) !!}
</head>
<body>
​
   <!-- Alert message (start) -->
   @if(Session::has('message'))
   <div class="alert alert-success">
       {{ Session::get('message') }}
   </div>
   @endif
   <!-- Alert message (end) -->

   <div class="container">
      <h2>Contact form</h2>
      <form action="{{ route('pages.store') }}" method="post" id="contactForm">
         @csrf
         <div class="form-group">
           <label for="name">Name:</label>
           <input type="name" class="form-control" id="email" placeholder="Enter name" name="name" value="{{ old('name') }}">
           @if($errors->has('name'))
              <small class="text-danger">{{ $errors->first('name') }}</small>
           @endif
         </div>
         <div class="form-group">
           <label for="email">Email:</label>
           <input type="email" class="form-control" id="email" placeholder="Enter email" name="email" value="{{ old('email') }}">
           @if($errors->has('email'))
              <small class="text-danger">{{ $errors->first('email') }}</small>
           @endif
         </div>
         <div class="form-group">
           <label for="message">Message:</label>
           <textarea class="form-control" id="message" placeholder="Enter message" name="message">{{ old('message') }}</textarea>
           @if($errors->has('message'))
              <small class="text-danger">{{ $errors->first('message') }}</small>
           @endif
         </div>

         <button type="submit" class="btn btn-primary">Submit</button>
      </form>
   </div>
​
</body>
</html>

10. Output

View Output


11. Conclusion

Make sure to add <meta name="csrf-token" > to store the CSRF token otherwise token is not readable and a verification request not be sent.

You can also view Google reCaptcha v2 integration in Laravel 8 here.

If you found this tutorial helpful then don't forget to share.

Leave a Comment