In this article we will learn to integrate Google ReCaptcha into flask web application without using any flask extension to prevent bots from submitting spam.
Traditionally web applications used CAPTCHA
containing image with some problem which human could solve but no automated bot can solve. In modern applications this can be achieved by using third party API like Google ReCaptcha.
How Google ReCaptcha API works ?
When you register for recaptcha it provides you two keys.
Site Key
: For Client Side IntegrationSecret Key
: For Server Side Integration-
Whenever user submits a form configured with ReCaptcha it contains payload with name
g-recaptcha-response
. -
Upon submitting form your server collects
g-recaptcha-response
and sends it to google server along withSecret Key
to make sure submitted form was from human and not from bot. -
Google server check
g-recaptcha-response
sent by you and returns back value suggesting whether form submission is from human or bot .
Registering for ReCaptcha
Before we begin with actual code I assume that you have registered for Google ReCaptcha and have Site Key
and Secret Key
for your domain.
To test application locally add localhost
into the domain name while registering like below.
Implementing ReCaptcha with python and flask
We will create contact form which is most common use case for using flask and recaptcha. Form will allow user to submit name, email and message. At the end of the tutorial working code will be pushed on github for easier access.
- Client side Implementation
For client side implementation we will include two elements into
html
- ReCaptcha Javascript Code Inside
head
tag<script src="https://www.google.com/recaptcha/api.js"></script>
div
to render ReCaptcha Control inside form<div class="g-recaptcha" data-sitekey=""></div>
For client side we will create simple form with 4 fields. (Name, Email Address, Message and ReCaptcha.
Note that how we have includedsitekey
generated during ReCaptcha registration insidediv
to render ReCaptcha.<div class="g-recaptcha" data-sitekey=""></div>
Instead of hardcoding,
sitekey
you can render it by passing it toview
withjinja2
from server side python code.<div class="g-recaptcha" data-sitekey="{{ sitekey }}"></div>
- ReCaptcha Javascript Code Inside
After rendering example form will look like this.
- Accept form values with
g-recaptcha-response
Once user has submitted the form by completing ReCaptcha challenge form will get additional field from ReCaptcha under name
g-recaptcha-response
. Accept it along with other fields with flask contact route.@app.route("/contact/", methods=["GET", "POST"]) def contact(): if request.method == "POST": name = request.form['name'] email = request.form['email'] msg = request.form['message'] captcha_response = request.form['g-recaptcha-response']
- Verify
captcha_response
from ReCaptcha ServerTo check submitted token under
captcha_response
it needs to be send to google server with payloadresponse
. We will use pythonrequests
. Server will checkcaptcha_response
and respondjson
objectresponse_text
.response_text
will have keysuccess
containing valuetrue
if request is valid (from human) andfalse
if it's invalid. We will implement this by definingis_human
function in python.Note that we need to pass
Secret Key
generated during registration under payloadsecret
to ReCaptcha server while verifyingcaptcha_response
.def is_human(captcha_response): """ Validating recaptcha response from google server Returns True captcha test passed for submitted form else returns False. """ secret = "2PmehhhhsdhsjHGOnjdnsjkfnkjsdn56HDHFjhjh" payload = {'response':captcha_response, 'secret':secret} response = requests.post("https://www.google.com/recaptcha/api/siteverify", payload) response_text = json.loads(response.text) return response_text['success']
- Process Request
If
is_human
returnsTrue
then we will process contact request else we will show message saying Bots are not allowed !@app.route("/contact/", methods=["GET", "POST"]) def contact(): """ Renders contact form on get and processes it on post. """ sitekey = "your-site-key-here" if request.method == "POST": name = request.form['name'] email = request.form['email'] msg = request.form['message'] captcha_response = request.form['g-recaptcha-response'] if is_human(captcha_response): # Process request here status = "Detail submitted successfully." else: # Log invalid attempts status = "Sorry ! Bots are not allowed." flash(status) return redirect(url_for('contact')) return render_template("contact.html", sitekey=sitekey)
Code
Working code for the flask contact form has been posted on gihub. Please configure site-key and secret key into contact_form.py
before running the application.