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.
Contents
- Get Google reCaptcha keys
- Create variables in .env
- Enable CSRF
- Create custom validation for reCaptcha v3
- Create Controller
- Routes
- Create View
- Output
- 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.
- 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.
- Copy the 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
,andsecurity.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 inapp/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
istrue
and$responseData->score
is>
0.6 then returntrue
otherwise, assign error message in$error
and returnfalse
.
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.
- index() – Load
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 inapp/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')?>
. DefineonSubmit
event on<form >
that callsonSubmit(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
onsubmit
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
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.