Integrating Google reCAPTCHA v3 with PHP

Introduction

Google’s reCAPTCHA v3 is designed to help websites tell the difference between real users and bots without bothering users with challenges like identifying pictures or typing text. It works quietly in the background, making it both effective and user-friendly.

To use reCAPTCHA V3, you need to have your site key and secret key. To generate them, visit the Google reCAPTCHA website, click on the “v3 Admin Console” button, register your site and generate the site key and secret key.

The process has two parts. The first part is generating a token on the front end and the second part is verifying that token in the backend.

Generating the Token on the Front-end

For the front-end part, there are two methods.

Method 1: Automatically bind the challenge to a button

This method generates the token when a specific button is clicked. This is the form submit button in most cases. This method adds a hidden textarea field to the form and sets its value to the generated token. As a result the token will be submitted with other form data and we can access it in the backend.

Step 1: Load the JavaScript API

 <script src="https://www.google.com/recaptcha/api.js"></script>

This api.js file is a short script that creates and adds another <script> element to the page called recaptcha__en.js. So now if you inspect the page you’ll see two JS files loaded for reCAPTCHA:

recaptcha scripts

Step 2: Add attributes to your html button

<button class="g-recaptcha" 
        data-sitekey="reCAPTCHA_site_key" 
        data-callback='onSubmit' 
        data-action='submit'>Submit</button>

The data-sitekey attribute should be set to the site key generated for the site. The data-callback attribute is the name of a JS function that we need to define in the next step. When the user clicks on the submit button, first a reCAPTCHA token is generated and then this token is passed to that function.

The class g-recaptcha is used by the reCAPTCHA script to inject a div like this just before the button:

recaptcha injected textarea

As you can see, reCAPTCHA adds a textarea field to the form with name g-recaptcha-response. When the Submit button is clicked, reCAPTCHA script sets the value of this textarea field to the generated reCAPTCHA token. As a result, the reCAPTCHA token will be submitted along side other input fields in the form.

Step 3: Add a callback function to handle the token

function onSubmit(token) {
     document.getElementById("demo-form").submit();
   }

When you add reCAPTCHA attributes to a submit button, reCAPTCHA prevents the form from submitting. That’s why we need to submit the form in this function.

Method 2: Programmatically invoke the challenge

In this method we control when the token is generated and it doesn’t need to be generated when a button is clicked (unlike the previous method). As a result we have more control. For instance we can generate the token after validating other form fields. The tradeoff is that in this method the token won’t be automatically added to the form data or submitted to the backend, so we need to write code to send it to the backend.

Step 1: Load the JavaScript API with your sitekey

Similar to the first method, we need to load the api.js file. The difference is that in this method, we need to add the site key as a query parameter called render, like this:

<script src="https://www.google.com/recaptcha/api.js?render=reCAPTCHA_site_key"></script>

Similar to the previous method, the api.js loads another script called recaptcha__en.js on the page. This script, gives us access to an object called grecaptcha. This object has a few methods including ready() and execute().

The grecaptcha.ready method is provided by the Google reCAPTCHA v3 library. It accepts a callback function as an argument and ensures that this callback is executed only after the reCAPTCHA library is completely loaded. This is crucial because reCAPTCHA functions like grecaptcha.execute need the library to be fully initialized to work correctly.

The grecaptcha.execute method triggers the reCAPTCHA verification process. When you call this function, reCAPTCHA v3 evaluates the user’s interactions with your website and generates a token that you can send to your server for verification.

Step 2: Call grecaptcha.execute on each action you wish to protect

function onClick(e) {
    e.preventDefault();
    
    grecaptcha.ready(function () {
        grecaptcha
            .execute('reCAPTCHA_site_key', { action: 'submit' })
            .then(function (token) {
                // Add your logic to submit to your backend server here.
            });
    });
}

Here, we use the grecaptcha.ready method to make sure the function we pass to it is only executed when the recaptcha library is loaded. Then in the callback function we run the grecaptcha.execute method. This method returns a promise that resolves to a token, which can then be handled as needed (e.g., sent to your server for verification).

Verifying the token on the Back-end

Regardless of the method you use on the front end, you need to verify the generated token in the backend. In PHP you can do this like so:

if ( $_SERVER['REQUEST_METHOD'] === 'POST' ) {
	// get the recaptcha token
	$recaptcha_response = $_POST['g-recaptcha-response'];

	// set the secret key
	$secret_key = '6LdXp-EpAAAAAJL5yQEiZbQWNsQbz*********';

	// send the secret key and the generated token to recaptcha API
	$response = file_get_contents( "https://www.google.com/recaptcha/api/siteverify?secret={$secret_key}&response={$recaptcha_response}" );

	$response_data = json_decode( $response );

	if ( $response_data->success ) {
		// reCAPTCHA verification successful
		echo 'reCAPTCHA verified successfully.';
		// Process the form data...
	} else {
		// reCAPTCHA verification failed
		echo 'reCAPTCHA verification failed.';
		print_r( $response_data );
	}
}