Using reCAPTCHA v3 with Django

reCAPTCHA is a system to prevent spam and abuse of web services. It's easy to integrate with Django. There are three steps to using v3 reCAPTCHA in your web app:

  1. Create the reCAPTCHA application
  2. Integrate with your frontend
  3. Validate the response from Google

Create the reCAPTCHA application

First, register a new reCAPTCHA application at https://www.google.com/recaptcha/admin: recaptcha admin page

Copy the value in the Secret Key box. Put this in your Django settings:

GOOGLE_RECAPTCHA_SECRET_KEY = <secret_key>

You probably don't want to hardcode the value in your settings.py. You can store it in a separate config file, and read it in via configparser.

Integrate with your frontend

In the "Client side integration" section of the reCAPTCHA admin page, copy the first snippet:

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

Copy the one from your admin page, not the snippet above. Or replace <YOUR_SITE_KEY> with your actual site key. Put that tag in your template's <head> tag.

Copy the second snippet from the reCAPTCHA admin page:

<script>
    grecaptcha.ready(function() {
        grecaptcha.execute('<YOUR_SITE_KEY>', {action: '<ACTION_NAME>'})
        .then(function(token) {
            <RESPONSE_ACTION>
        });
    });
</script>

Put that in the <body> tag of the page you want to use reCAPTCHA on. You'll need to replace <YOUR_SITE_KEY> with your actual site key. The version on your reCAPTCHA admin page should already have it. You also need to replace <ACTION_NAME> with an appropriate value - if you are using it to validate user signups, you could use signup for example.

The next step is to replace <RESPONSE_ACTION> with some javascript. If you are using reCAPTCHA to protect form submissions, you might have this form on the same page:

<form method="post" id="form">
    <input type="email" name="email">
    <button type="submit">Sign up</button>
    </div>
</form>

Google will return a token to the client. That token needs to be passed to your server for validation. You can do that like this:

<script>
    grecaptcha.ready(function() {
        grecaptcha.execute('<YOUR_SITE_KEY>', {action: '<ACTION_NAME>'})
        .then(function(token) {
            document.getElementById("form").appendChild(document.CreateElement(`<input type="hidden" name="g-recaptcha-response" value=${token}`);
        });
    });
</script>

The form will now contain an extra item named g-recaptcha-response on submission.

Validate the response from Google

In the view that processes your form, you need to separately verify the submitted token is valid. If you are using a class-based view:

def form_valid(self, form):

    # get the token submitted in the form
    recaptcha_response = self.request.POST.get('g-recaptcha-response')
    url = 'https://www.google.com/recaptcha/api/siteverify'
    payload = {
        'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY,
        'response': recaptcha_response
    }
    data = urllib.parse.urlencode(payload).encode()
    req = urllib.request.Request(url, data=data)

    # verify the token submitted with the form is valid
    response = urllib.request.urlopen(req)
    result = json.loads(response.read().decode())

    # result will be a dict containing 'success' and 'action'.
    # it is important to verify both

    if (not result['success']) or (not result['action'] == 'signup'):  # make sure action matches the one from your template
        messages.error(self.request, 'Invalid reCAPTCHA. Please try again.')
        return super().form_invalid(form)

    <finish your form processing...>

That's it! Now you have integrated reCAPTCHA with your Django app.

This post was written using Python 3.7.0 and Django 2.1.4.