Google reCAPTCHA for a Flask app

Google reCAPTCHA for a Flask app

It is trival to add Google reCAPTCHA to a Flask app. Google's description of reCAPTCHA is "Protect your website from spam and abuse while letting real people pass through with ease."

Credit: based entirely on Vitor Freitas' post
Authored date: 2018 March 08
Technologies: Python 2.7.13, Flask 0.10.1, Jinja2, reCAPTCHA V2

Go to https://www.google.com/recaptcha/admin and register your domain as a reCAPTCHA V2 site. Copy your site and secret keys. In the code examples below I use config variables GOOGLE_RECAPTCHA_SITE_KEY and GOOGLE_RECAPTCHA_SECRET_KEY. Adjust your configuration to use your own reCAPTCHA keys.

In your Jinja template add this to your <head>:

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

And add this to your Jinja template inside your form, e.g. your login or registration form:

<div class="g-recaptcha" data-sitekey="GOOGLE_RECAPTCHA_SITE_KEY"></div>

Create a decorator function that you will use to decorate your view function(s):

import requests
from functools import wraps
from flask import flash, request
from config.settings import GOOGLE_RECAPTCHA_SECRET_KEY

def check_recaptcha(f):
    """
    Checks Google  reCAPTCHA.

    :param f: view function
    :return: Function
    """
    @wraps(f)
    def decorated_function(*args, **kwargs):
        request.recaptcha_is_valid = None

        if request.method == 'POST':
            data = {
                'secret': GOOGLE_RECAPTCHA_SECRET_KEY,
                'response': request.form.get('g-recaptcha-response'),
                'remoteip': request.access_route[0]
            }
            r = requests.post(
                "https://www.google.com/recaptcha/api/siteverify",
                data=data
            )
            result = r.json()

            if result['success']:
                request.recaptcha_is_valid = True
            else:
                request.recaptcha_is_valid = False
                flash('Invalid reCAPTCHA. Please try again.', 'error')

        return f(*args, **kwargs)

    return decorated_function

The last step is to decorate the view or views that you would like to use reCAPTCHA and test request.recaptcha_is_valid for a truthy value:

@user.route('/login', methods=['GET', 'POST'])
@check_recaptcha
def login():
    """User login."""

    if form.validate_on_submit() and request.recaptcha_is_valid:
        # login user...

    return render_template('user/login.jinja2', form=form)

That's it, done.