Integrate recaptcha and wp_signon - what is needed?

I've been using wp_signon for a long time in a project:

//Do the actual login for WP User
$creds = array();
$creds['user_login'] = $skuser_name;
$creds['user_password'] = $skuser_pass;
$creds['remember'] = true;
$user = wp_signon( $creds, false ); 

This have been working for a long time. I recently added plugin Wordfence which included recaptcha (invislbe) for login and registration forms and those obviously do work.

After installation of that plugin my custom loginforms with code above did not work. After some research I figured out that it was the recaptcha in combination with my custom loginform that uses wp_signon that was the issue.

I get the error (when using correct username and password):

//VERIFICATION REQUIRED: Additional verification is required for login. Please check the email address associated with the account for a verification link.

When I deactive recaptcha which is included in WordFence - plugin -> my custom loginform does work.

I have keys that are needed for the actual recaptcha but I can't figure what I have to do to integrate this with wp_signon!? Is it possible to integrate recaptcha with wp_signon or do I have to create a custom wp_signon function?

Please point me in right direction! Thank you!

Topic captcha errors login Wordpress

Category Web


So Wordfence uses JavaScript to add the CAPTCHA fields to the login/registration form, but by default only on https://example.com/wp-login.php.

And if you want to add the fields to your form, or integrate the CAPTCHA security with your custom login form, the steps are:

  1. Enqueue the (re)CAPTCHA scripts, preferably only on the page having the custom form:

    add_action( 'wp_enqueue_scripts', function () {
        if ( is_page( 'my-page' ) &&
            class_exists( '\WordfenceLS\Controller_WordfenceLS' )
        ) {
            \WordfenceLS\Controller_WordfenceLS::shared()->_login_enqueue_scripts();
        }
    } );
    

    The above would load the scripts only on the my-page Page, so you should change the slug or use another conditional tag like is_single().

  2. Your custom form has to meet these conditions:

    1. The username field must be named log (e.g. <input name="log" />).

    2. The password field must be named pwd (e.g. <input name="pwd" />).

    3. The submit button's id must be wp-submit (e.g. <input id="wp-submit" type="submit" />).

    4. There must be no other forms having those fields, i.e. there must be no other form fields having the same name or id.

    5. Wordfence will run an AJAX request to check the credentials and when there's an error like wrong password, Wordfence will add the error message after a h1 (heading level 1) inside the element with the id of login.

      So you need to make sure those two elements (#login and #login > h1) both exist — see the sample form code below.


    And those are, unfortunately, limitations in the Wordfence's custom login script, which you can find it in wp-content/plugins/wordfence/modules/login-security/js and the file name looks like login.1581523568.js (i.e. login.<numbers>.js). You may copy and modify the script (i.e. remove those 5 limitations), then enqueue it instead of the default, but you'll need to try doing so on your own.

    Also, if you use wp_login_form() (with a custom action value), you would only need to add the elements mentioned in #5 above.

Code I used for testing:

The form, shown on https://example.com/my-page/:

<div id="login">
    <h1>Login</h1>

    <!-- Wordfence places AJAX error here -->

    <form method="post" action="">
        <input name="log" type="text" placeholder="Username" />
        <input name="pwd" type="password" placeholder="Password" />

        <input type="hidden" name="action" value="my_login" />
        <?php wp_nonce_field( 'my-login' ); ?>

        <input type="submit" id="wp-submit" />
    </form>
</div>

And the PHP, which calls wp_signon():

add_action( 'init', function () {
    if (
        wp_doing_ajax() || empty( $_POST['_wpnonce'] ) ||
        ( ! ( isset( $_POST['log'], $_POST['pwd'] ) ) ) ||
        ! wp_verify_nonce( $_POST['_wpnonce'], 'my-login' )
    ) {
        return;
    }

    $creds = array();

    $creds['user_login']    = $_POST['log'];
    $creds['user_password'] = $_POST['pwd'];
    $creds['remember']      = true;

    $user = wp_signon( $creds, false );
    if ( is_wp_error( $user ) ) {
        wp_die( $user );
    } else {
        wp_redirect( home_url( wp_get_referer() ) );
        exit;
    }
} );

Additional Notes

As I mentioned in the comment, if you just want to bypass the CAPTCHA validation while doing wp_signon(), you can use the wordfence_ls_require_captcha filter:

add_filter( 'wordfence_ls_require_captcha', '__return_false' );
// call wp_signon() here
remove_filter( 'wordfence_ls_require_captcha', '__return_false' );

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.