Skip to content

Using reCAPTCHA v3 in the frontend #281

Closed

Description

Hello, while this is not specific to the PHP client library, but I hope to get some answers about the use of the new reCAPTCHA v3.

Basically I have a contact form in PrestaShop, and I want to be able to add reCAPTCHA v3 so that there is no extra interaction for users while making sure I don't get spammed from bots. From the docs page, the idea being brought forward is to add the script tag with the link toapi.js with the render GET parameter ?render=reCAPTCHA_site_key. Doing so you will not need to run grecaptcha.render() manually, which is an important point (more on this later).

Now, I have to add grecaptcha.execute() in the callback of grecaptcha.ready(). Here I can define an action, and finally in the then() promise fulfillment I get a token. I take this token and update the value attribute of a hidden input tag in the form, named g-recaptcha-response. This way it gets sent to the server alongside with the regular form fields and I can make the server verification in ContactController::postProcess() method.

Since I want users to fill the form with several fields and a message, they might take even minutes to submit the form. I'm also using jQuery to run on the form submission, doing some validation checks and in case calling event.preventDefault() and showing an alert if some required fields are empty or invalid.

In my tests I found out that tokens expire rather quickly. Since we don't manually run grecaptcha.render() as mentioned above, we cannot specify an expired-callback to run when the token expires. At this point I resorted to add a setInterval with a 60000 delay (1 minute) to run again grecaptcha.execute().

Is this the right way to use the frontend library? Is it correct to run multiple checks once per minute? Will this affect users' score?

$(document).ready(function () {
  function reCAPTCHA_execute () {
    // grecaptcha instantiated by external script from Google
    // reCAPTCHA_site_key comes from backend
    grecaptcha.execute(reCAPTCHA_site_key, { action: 'contactForm' }).then(function (token) {
      $('[name="g-recaptcha-response"]').val(token);
    }, function (reason) {
      console.log(reason);
    });
  }

  if (typeof grecaptcha !== 'undefined' && typeof reCAPTCHA_site_key !== 'undefined') {
    grecaptcha.ready(reCAPTCHA_execute);
    setInterval(reCAPTCHA_execute, 60000);
  }
});

Initially I thought of running grecaptcha.execute() on form submission, in the same callback function that does data validation, but since grecaptcha.execute() is asynchronous, I cannot stop the form submission (event.preventDefault()) and the resume in the promise fulfillment.

  $('.contact-form-box').on('submit', function (e) {
    // Check if email is empty
    if ($('#email').val() === '') {
      e.preventDefault();
      window.alert(contact_emptyEmail);
      return;
    }

    // Check if email is not valid
    if (!validate_isEmail($('#email').val())) {
      e.preventDefault();
      window.alert(contact_invalidEmail);
      return;
    }

    // etc…

    // here I cannot do grecaptcha.execute() because it's asynchronous,
    // and stopping the form submission cannot be reverted.
  });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions