Integrating a CAPTCHA with the WordPress Login Form

Share this article

In a previous tutorial, we took a deep dive into the WordPress HTTP API and I promised to show you how APIs can be consumed via the HTTP API in a WordPress plugin.

We’ve seen an example of a plugin using the HTTP API during the course of building a Domain WHOIS and Social Data WordPress Widget and in today’s tutorial, we will write a plugin that integrates a CAPTCHA with the WordPress login system using Google’s reCAPTCHA. And of course, the HTTP API will be used to send a POST request to reCAPTCHA to validate the user’s answer to the CAPTCHA challenge.

Below is a screenshot of the default WordPress login form protected by a CAPTCHA on activation of the plugin to be developed during this tutorial.

CAPTCHA WordPress

Plugin Development

Before we begin coding the plugin, head over to reCAPTCHA, register your domain name and grab your public and private API keys.

First off, include the plugin header.

<?php

/*
Plugin Name: WP Login Form with reCAPTCHA
Plugin URI: https://www.sitepoint.com
Description: Add Google's reCAPTCHA to WordPress Login 
Version: 1.0
Author: Agbonghama Collins
Author URI: http://w3guy.com
License: GPL2
*/

Create a PHP class with two properties that will store your reCAPTCHA’s private and public key.

class reCAPTCHA_Login_Form {

    /** @type string private key|public key */
    private $public_key, $private_key;

When writing WordPress plugins the OOP way, all action and filter hooks should be in the constructor ( __construct ). Our plugin’s magic constructor method will consist of just two actions hooks that will add the CAPTCHA to the login form and validate the CAPTCHA response.

/** class constructor */
    public function __construct() {
        $this->public_key  = '6Le6d-USAAAAAFuYXiezgJh6rDaQFPKFEi84yfMc';
        $this->private_key = '6Le6d-USAAAAAKvV-30YdZbdl4DVmg_geKyUxF6b';

        // adds the captcha to the login form
        add_action( 'login_form', array( $this, 'captcha_display' ) );

        // authenticate the captcha answer
        add_action( 'wp_authenticate_user', array( $this, 'validate_captcha_field' ), 10, 2 );
    }

Code explanation: First, my reCAPTCHA public and private keys are saved to their class properties.

The captcha_display() method that will output the reCAPTCHA challenge is added to the WordPress login by the login_form Action.

The validate_captcha_field() method that will ensure – the CAPTCHA field isn’t left empty and also the answer is correct – is included to the login validation system by the wp_authenticate_user Action.

Below is the code for the captcha_display() and validate_captcha_field() method we talked about.

/** Output the reCAPTCHA form field. */
    public function captcha_display() {
        ?>
        <script type="text/javascript"
                src="http://www.google.com/recaptcha/api/challenge?k=<?=$this->public_key;?>">
        </script>
        <noscript>
            <iframe src="http://www.google.com/recaptcha/api/noscript?k=<?=$this->public_key;?>"
                    height="300" width="300" frameborder="0"></iframe>
            <br>
            <textarea name="recaptcha_challenge_field" rows="3" cols="40">
            </textarea>
            <input type="hidden" name="recaptcha_response_field"
                   value="manual_challenge">
        </noscript>

    <?php
    }
/**
     * Verify the captcha answer
     *
     * @param $user string login username
     * @param $password string login password
     *
     * @return WP_Error|WP_user
     */
    public function validate_captcha_field($user, $password) {

        if ( ! isset( $_POST['recaptcha_response_field'] ) || empty( $_POST['recaptcha_response_field'] ) ) {
            return new WP_Error( 'empty_captcha', 'CAPTCHA should not be empty');
        }

        if( isset( $_POST['recaptcha_response_field'] ) && $this->recaptcha_response() == 'false' ) {
            return new WP_Error( 'invalid_captcha', 'CAPTCHA response was incorrect');
        }

        return $user;
    }

Taking a closer look at the validate_captcha_field() precisely the second if conditional statement, a call is made to recaptcha_response() to check if the CAPTCHA answer is correct ( i.e. returns false if the CAPTCHA response is wrong).

Let’s see the code and explanation of recaptcha_response().

/**
     * Get the reCAPTCHA API response.
     *
     * @return string
     */
    public function recaptcha_response() {

        // reCAPTCHA challenge post data
        $challenge = isset($_POST['recaptcha_challenge_field']) ? esc_attr($_POST['recaptcha_challenge_field']) : '';

        // reCAPTCHA response post data
        $response  = isset($_POST['recaptcha_response_field']) ? esc_attr($_POST['recaptcha_response_field']) : '';

        $remote_ip = $_SERVER["REMOTE_ADDR"];

        $post_body = array(
            'privatekey' => $this->private_key,
            'remoteip'   => $remote_ip,
            'challenge'  => $challenge,
            'response'   => $response
        );

        return $this->recaptcha_post_request( $post_body );

    }

Code explanation: To verify that the CAPTCHA answer supplied by the user is correct, a POST request need to be sent to the endpoint http://www.google.com/recaptcha/api/verify with the following parameters or body.

  • privatekey: Your private key
  • remoteip The IP address of the user who solved the CAPTCHA.
  • challenge The value of recaptcha_challenge_field sent via the form.
  • response The value of recaptcha_response_field sent via the form.

First, the challenge and response POST data sent by the form is captured and saved to $challenge and $response respectively.

The IP address of the user is captured by $_SERVER["REMOTE_ADDR"] and save to $remote_ip.

To send a POST request with the HTTP API, the parameters or body should be array form as follows:

$post_body = array(
            'privatekey' => $this->private_key,
            'remoteip'   => $remote_ip,
            'challenge'  => $challenge,
            'response'   => $response
        );

The POST parameters is passed as an argument to recaptcha_post_request() which will send the request along with the parameters to https://www.google.com/recaptcha/api/verify with the API response returned.

recaptcha_post_request() returns true if the CAPTCHA answer is correct and false otherwise.

Below is the code for recaptcha_post_request()

/**
     * Send HTTP POST request and return the response.
     *
     * @param $post_body array HTTP POST body
     *
     * @return bool
     */
    public function recaptcha_post_request( $post_body ) {

        $args = array( 'body' => $post_body );

        // make a POST request to the Google reCaptcha Server
        $request = wp_remote_post( 'https://www.google.com/recaptcha/api/verify', $args );

        // get the request response body
        $response_body = wp_remote_retrieve_body( $request );

        /**
         * explode the response body and use the request_status
         * @see https://developers.google.com/recaptcha/docs/verify
         */
        $answers = explode( "\n", $response_body );

        $request_status = trim( $answers[0] );

        return $request_status;
    }

Code explanation: An array $args with the POST body $post_body save to the key body is created.

The wp_remote_post send the POST request with the response save to $request.

The response body is retrieved by the wp_remote_retrieve_body and saved to $response_body.

If the captcha test was passed, the reCAPTCHA API returns:

true
success

Otherwise the following error is returned

false
incorrect-captcha-sol

To get the recaptcha_post_request method to return a Boolean value i.e. true on success and false on failure; the response $response_body is exploded and the array data with index 0 trimmed to remove any redundant white space from the beginning and end of the string.

Finally, we close the plugin class.

} // reCAPTCHA_Login_Form

We are done coding the plugin class. To put the class to work, we need to instantiate it like so:

new reCAPTCHA_Login_Form();

Wrap Up

If you wish to use the plugin on your WordPress site or to study the code in-depth, download the plugin.

This is the second in a series that will demonstrate how the WordPress HTTP API is used in a plugin.

Be sure to keep an eye on the WordPress channel for similar tutorials.

Happy coding!

Frequently Asked Questions (FAQs) about Integrating a CAPTCHA with the WordPress Login Form

What is the importance of integrating a CAPTCHA with the WordPress login form?

Integrating a CAPTCHA with the WordPress login form is crucial for enhancing the security of your website. CAPTCHA, which stands for Completely Automated Public Turing test to tell Computers and Humans Apart, is a system that verifies whether a user is human or a bot. By adding a CAPTCHA to your WordPress login form, you can prevent automated bots from attempting to gain unauthorized access to your site. This is particularly important as bots can carry out malicious activities such as spamming, data theft, and brute force attacks.

How can I add a CAPTCHA to my WordPress login and registration form?

To add a CAPTCHA to your WordPress login and registration form, you can use various plugins available in the WordPress repository. Some popular options include the Simple Login Captcha, Login Security reCAPTCHA, and reCAPTCHA for Login and Registration plugins. These plugins are easy to install and configure, and they provide an effective way to prevent bots from accessing your site.

Are there any alternatives to CAPTCHA for securing my WordPress login form?

Yes, there are several alternatives to CAPTCHA for securing your WordPress login form. These include two-factor authentication, limiting login attempts, using strong passwords, and changing the default WordPress login URL. However, CAPTCHA remains one of the most effective methods for preventing automated bot attacks.

Can I customize the appearance of the CAPTCHA on my WordPress login form?

Yes, most CAPTCHA plugins for WordPress allow you to customize the appearance of the CAPTCHA on your login form. You can change the style, color, and size of the CAPTCHA to match the design of your website.

Does adding a CAPTCHA to my WordPress login form affect user experience?

While adding a CAPTCHA to your WordPress login form can enhance security, it may also affect user experience. Some users may find it inconvenient to complete the CAPTCHA every time they log in. However, this inconvenience is generally outweighed by the increased security that CAPTCHA provides.

What is the difference between reCAPTCHA v2 and v3?

reCAPTCHA v2 requires users to interact with a checkbox or select images that match a certain description. On the other hand, reCAPTCHA v3 uses a scoring system to determine whether a user is a human or a bot, without requiring any interaction from the user.

How can I troubleshoot issues with the CAPTCHA on my WordPress login form?

If you’re experiencing issues with the CAPTCHA on your WordPress login form, you can try deactivating and reactivating the CAPTCHA plugin, clearing your browser cache, or checking for conflicts with other plugins. If the issue persists, you may need to contact the plugin developer for assistance.

Can I use CAPTCHA for other forms on my WordPress site?

Yes, you can use CAPTCHA for other forms on your WordPress site, such as contact forms, registration forms, and comment forms. This can help to prevent spam submissions and enhance the overall security of your site.

Is it possible to bypass a CAPTCHA?

While CAPTCHA is designed to prevent automated bot attacks, it is not foolproof. Sophisticated bots may be able to bypass CAPTCHA by using techniques such as machine learning and image recognition. However, CAPTCHA remains an effective deterrent against most types of bot attacks.

How often should I update the CAPTCHA plugin on my WordPress site?

It’s recommended to update the CAPTCHA plugin on your WordPress site whenever a new version is available. This ensures that you’re using the latest security measures and that the plugin is compatible with the most recent version of WordPress.

Collins AgbonghamaCollins Agbonghama
View Author

Collins is a web developer and freelance writer. Creator of the popular ProfilePress and MailOptin WordPress plugins. When not wrangling with code, you can find him writing at his personal blog or on Twitter.

captchaChrisBhttp apipluginreCAPTCHAWordPress
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week