How to add Google reCAPTCHA v3 in CodeIgniter 4

Google reCAPTCHA v3 is an invisible type of captcha where the user doesn’t have to interact. It tracks the user behavior on the site and returns a score between 0 to 1 with the response.

This score is use for validation on the server side.

In this tutorial, I show how you can add Google reCAPTCHA v3 to your form in CodeIgniter 4.

How to add Google reCAPTCHA v3 in CodeIgniter 4


Contents

  1. Get Google reCaptcha keys
  2. Create variables in .env
  3. Enable CSRF
  4. Create custom validation for reCaptcha v3
  5. Create Controller
  6. Routes
  7. Create View
  8. Output
  9. Conclusion

1. Get Google reCaptcha keys

You can skip this step if you already registered for Google reCAPTCHA v3 and have site and secret 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. Create variables in .env

  • Open .env file which is available at the project root.

NOTE – If dot (.) not added at the start then rename the file to .env.

  • Here, define 2 variables for storing the captcha site and secret keys –
GOOGLE_RECAPTCHAV3_SITEKEY = 6LdP-nIhAAAAAA6rzq7BTh_jKqIYeKMoaALxkKte
GOOGLE_RECAPTCHAV3_SECRETKEY = 6LdV-nIhAAAAAL-uFI4w9kQUaqMkeU2K3KojlXyE

3. Enable CSRF

  • Again open .env file.
  • Remove # from the start of the security.tokenName,security.headerName, security.cookieName, security.expires,and security.regenerate.
  • I update the security.tokenName value with 'csrf_hash_name'. With this name read CSRF hash. You can update it with any other value.
  • If you don’t want to regenerate CSRF hash after each request then set security.regenerate = false.
security.tokenName = 'csrf_hash_name' 
security.headerName = 'X-CSRF-TOKEN' 
security.cookieName = 'csrf_cookie_name' 
security.expires = 7200 
security.regenerate = true
  • Open app/Config/Filters.php file.
  • Uncomment 'csrf' in 'before' if commented.
// Always applied before every request
public $globals = [
    'before' => [
         // 'honeypot',
         'csrf',
         // 'invalidchars',
    ],
    'after' => [
        'toolbar',
        // 'honeypot',
        // 'secureheaders',
    ],
];

4. Create custom validation for reCaptcha v3

Create a rule to verify reCaptcha v3 response.

  • Create a new CaptchaValidation.php file in app/Config/ folder.
  • Create a CaptchaValidation class.
  • In the class create verifyrecaptchaV3() method. Here, the method name is also a rule name.
  • Read the secret key from .env file and assign it to $secretkey.
  • Send request to –
https://www.google.com/recaptcha/api/siteverify?secret=".$secretkey."&response=".$str."&remoteip=".$_SERVER['REMOTE_ADDR']
  • Here, pass secret key, recaptcha response, and IP address.
  • It returns a JSON response.
  • If $responseData->success is true and $responseData->score is > 0.6 then return true otherwise, assign error message in $error and return false.

NOTE – You can update value of $score from 0.6 to any other value. Make sure to set it between 0.5 to 1.

Completed Code

<?php 
namespace Config;

class CaptchaValidation{

     public function verifyrecaptchaV3(string $str, ?string &$error = null): bool
     {
          $secretkey = getenv('GOOGLE_RECAPTCHAV3_SECRETKEY');

          if(($str) && !empty($str)) {

               $response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=".$secretkey."&response=".$str."&remoteip=".$_SERVER['REMOTE_ADDR']);

               $responseData = json_decode($response);
               $score = 0.6; // 0 - 1
               if($responseData->success && $responseData->score > $score) { // Verified
                    return true;
               }
          }

          $error = "Invalid captacha";

          return false;
     }

}

To use the above-created validation rule need to define it in the Validation.php file.

  • Open app/Config/Validation.php file.
  • Include Config\CaptchaValidation class.
  • Specify CaptchaValidation::class in $ruleSets Array.

Completed Code

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Validation\CreditCardRules;
use CodeIgniter\Validation\FileRules;
use CodeIgniter\Validation\FormatRules;
use CodeIgniter\Validation\Rules;
use Config\CaptchaValidation; // Custom reCAPTCHA v3 validation

class Validation extends BaseConfig
{
      // --------------------------------------------------------------------
      // Setup
      // --------------------------------------------------------------------

      /**
      * Stores the classes that contain the
      * rules that are available.
      *
      * @var string[]
      */
      public $ruleSets = [
          Rules::class,
          FormatRules::class,
          FileRules::class,
          CreditCardRules::class,
          CaptchaValidation::class, // Custom reCAPTCHA v3 validation
      ];

      /**
      * Specifies the views that are used to display the
      * errors.
      *
      * @var array<string, string>
      */
      public $templates = [
          'list' => 'CodeIgniter\Validation\Views\list',
          'single' => 'CodeIgniter\Validation\Views\single',
      ];

      // --------------------------------------------------------------------
      // Rules
      // --------------------------------------------------------------------
}

5. Create Controller

Create PagesController Controller –

php spark make:controller PagesController
  • Open app/Controllers/PagesController.php file.
  • Create 2 methods –
    • index() – Load index view.
    • submitContactUs() – This method calls on form submit.

Validate the submitted values. Here, for validating recaptcha specify – 'recaptch_response' => 'required|verifyrecaptchaV3',.

verifyrecaptchaV3 is a custom validation rule created in the previous step.

If <form > is not validated then return to the page with error messages otherwise store the success message in SESSION flash and redirect to route('/').

Completed Code

<?php

namespace App\Controllers;

use App\Controllers\BaseController;

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

     public function submitContactUs(){

         // Validation
         $input = $this->validate([
              'name' => 'required',
              'email' => 'required',
              'subject' => 'required',
              'message' => 'required',
              'recaptcha_response' => 'required|verifyrecaptchaV3',
            ],[
              'recaptcha_response' => [
                    'required' => 'Please verify captcha',
              ],
         ]);

         if (!$input) { // Not valid

              $data['validation'] = $this->validator;

              return redirect()->back()->withInput()->with('validation', $this->validator);

         }else{ 
              // Set Session
              session()->setFlashdata('message', 'Request Submitted Successfully!');
              session()->setFlashdata('alert-class', 'alert-success');

         }
         return redirect()->route('/');
     }

}

6. Routes

  • Open app/Config/Routes.php file.
  • Here, create 2 routes –
    • page/submitContactUs – Handle form submit.
$routes->get('/', 'PagesController::index');
$routes->post('page/submitContactUs', 'PagesController::submitContactUs');

7. Create View

  • Create index.php file in app/Views/ folder.
  • Include recaptcha js in <head > section –
<!-- reCAPTCHA JS-->
<script src="https://www.google.com/recaptcha/api.js?render=<?= getenv('GOOGLE_RECAPTCHAV3_SITEKEY') ?>"></script>

Here, also specify sitekey.

  • Create a contact form and set action URL to <?=site_url('page/submitContactUs')?>. Define onSubmit event on <form > that calls onSubmit(event).
  • Display an error message if <form> element is not validated. In the <form > also display an error message if recaptcha is not validated.
  • Create a hidden element #recaptcha_response to store recapatcha token response on <form > submit.
  • Create a submit button.

Script

  • Create onSubmit() function that calls on <form > submit.
  • Call grecaptcha.execute on submit action to get a token.
  • Assign the token to the hidden element #recaptcha_response.
  • Submit the <form >.

Completed Code

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>How to add Google reCAPTCHA v3 in CodeIgniter 4</title>

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" >

    <!-- reCAPTCHA JS-->
    <script src="https://www.google.com/recaptcha/api.js?render=<?= getenv('GOOGLE_RECAPTCHAV3_SITEKEY') ?>"></script>

    <!-- Include script -->
    <script type="text/javascript">

    function onSubmit(e) {
        e.preventDefault();
        grecaptcha.ready(function() {
             grecaptcha.execute("<?= getenv('GOOGLE_RECAPTCHAV3_SITEKEY') ?>", {action: 'submit'}).then(function(token) {

                  // Store recaptcha response
                  document.getElementById("recaptcha_response").value = token;

                  // Submit form
                  document.getElementById("contactForm").submit();

             });
        });
    }

    </script>
</head>
<body>

    <div class="container">

        <div class="row">
             <div class="col-md-6 mt-5" style="margin: 0 auto;">

                 <?php 
                 // Display Response
                 if(session()->has('message')){
                 ?>
                      <div class="alert <?= session()->getFlashdata('alert-class') ?>">
                           <?= session()->getFlashdata('message') ?>
                      </div>
                 <?php
                 }
                 ?>

                 <h2 class="mb-4">Contact US</h2>

                 <?php $validation = \Config\Services::validation(); ?>

                 <form id="contactForm" method="post" action="<?=site_url('page/submitContactUs')?>" onSubmit="onSubmit(event)">

                     <?= csrf_field(); ?>

                     <!-- Recaptcha Error -->
                     <?php if( $validation->getError('recaptcha_response') ) {?>

                          <div class="alert alert-danger">
                                <?= $validation->getError('recaptcha_response'); ?>
                          </div>
                     <?php }?>

                     <div class="form-group mb-4">
                          <label class="control-label col-sm-2" for="name">Name:</label>
                          <div class="col-sm-10">
                                <input type="text" class="form-control" id="name" placeholder="Enter Name" name="name" value="<?= old('name') ?>">
                          </div>

                          <!-- Error -->
                          <?php if( $validation->getError('name') ) {?>
                                <div class='text-danger mt-2'>
                                     * <?= $validation->getError('name'); ?>
                                </div>
                          <?php }?>
                     </div>
                     <div class="form-group mb-4">
                          <label class="control-label col-sm-2" for="email">Email:</label>
                          <div class="col-sm-10">
                                <input type="email" class="form-control" id="email" placeholder="Enter Email" name="email" value="<?= old('email') ?>">
                          </div>

                          <!-- Error -->
                          <?php if( $validation->getError('email') ) {?>
                                <div class='text-danger mt-2'>
                                     * <?= $validation->getError('email'); ?>
                                </div>
                          <?php }?>
                     </div>
                     <div class="form-group mb-4">
                          <label class="control-label col-sm-2" for="subject">Subject:</label>
                          <div class="col-sm-10">
                                <input type="text" class="form-control" id="subject" placeholder="Enter Subject" name="subject" value="<?= old('subject') ?>" >
                          </div>

                          <!-- Error -->
                          <?php if( $validation->getError('subject') ) {?>
                                <div class='text-danger mt-2'>
                                     * <?= $validation->getError('subject'); ?>
                                </div>
                          <?php }?>
                     </div>
                     <div class="form-group mb-4">
                          <label class="control-label col-sm-2" for="message">Message:</label>
                          <div class="col-sm-10">
                                <textarea class="form-control" id="message" name="message"><?= old('message') ?></textarea>
                          </div>

                          <!-- Error -->
                          <?php if( $validation->getError('message') ) {?>
                                <div class='text-danger mt-2'>
                                     * <?= $validation->getError('message'); ?>
                                </div>
                          <?php }?>
                     </div>

                     <div class="form-group "> 
                          <div class="col-sm-offset-2 col-sm-10">
                                <input type="hidden" id="recaptcha_response" name="recaptcha_response" value="">
                                <button type="submit" class="btn btn-info">Submit</button>
                          </div>
                     </div>
                 </form>
             </div>
        </div>

    </div>

</body>
</html>

8. Output

View Output


9. Conclusion

Using this you can protect your website without forcing the user to verify whether it is human or a bot.

You can also view this tutorial if you want to know Google reCAPTCHA v2 implementation in CodeIgniter 4.

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

Leave a Comment