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-responseand sends it to google server along withSecret Keyto make sure submitted form was from human and not from bot. -
Google server check
g-recaptcha-responsesent 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
headtag<script src="https://www.google.com/recaptcha/api.js"></script> divto 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 includedsitekeygenerated during ReCaptcha registration insidedivto render ReCaptcha.<div class="g-recaptcha" data-sitekey=""></div>Instead of hardcoding,
sitekeyyou can render it by passing it toviewwithjinja2from 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-responseOnce 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_responsefrom ReCaptcha ServerTo check submitted token under
captcha_responseit needs to be send to google server with payloadresponse. We will use pythonrequests. Server will checkcaptcha_responseand respondjsonobjectresponse_text.response_textwill have keysuccesscontaining valuetrueif request is valid (from human) andfalseif it's invalid. We will implement this by definingis_humanfunction in python.Note that we need to pass
Secret Keygenerated during registration under payloadsecretto 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_humanreturnsTruethen 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.