" width="1000" style="--opacity:1">
Sam Magura
The unfortunate reality of web application development is that we cannot only think about how our application will be used — we must also think about how it will be misused. This article focuses on preventing automated abuse by bots through the use of captchas. A captcha is essentially a Turing test , meaning that it allows a web application to differentiate between legitimate use by a human and illegitimate use by a bot.
We will be using Google's reCAPTCHA, the most widely used captcha library on the web. If you have ever been asked to check the "I am not a robot" box, then you've used reCAPTCHA. Though, the "I'm not a robot checkbox" is just one flavor of reCAPTCHA — there are several options to choose from:
The rest of this article provides a step-by-step guide to setting up invisible reCAPTCHA v2 in a Django web application. Invisible reCAPTCHA v2 is a great option because it requires no user input. This flavor of reCAPTCHA is also easy to use, since it indicates whether or not the user is a bot via a simple yes/no response, rather than a confidence score like reCAPTCHA v3.
Calling the reCAPTCHA API from your backend requires a secret key. We'll store this key in the Zero secrets manager and fetch it at runtime using the Zero Python SDK .
🔗 The full code for this example is available in the zerosecrets/examples GitHub repository.
Zero is a modern secrets manager built with usability at its core. Reliable and secure, it saves time and effort.
Adding invisible reCAPTCHA v2 to your application is a straightforward task, though it does require code on both the frontend and backend. If you get stuck or want to learn about the full range of use cases supported by the library, check out the official docs provided by Google.
At a high level, here is how the process works. All steps occur client side, except for the last one which occurs server side.
success
boolean that tells you if the user passed the challenge.You can sign up for reCAPTCHA and get your API key here . Select "Select reCAPTCHA v2 - Invisible reCAPTCHA badge" and add localhost
as a domain. You'll be given your site key and secret key once you complete the signup flow. The site key can be shared publicly, while the secret key must be kept private.
We're using Zero to manage our secrets, so log in to Zero and create new project to store the reCAPTCHA keys. While we only need to fetch the secret key from Zero (since the site key can be committed directly to your git repository), it's convenient to save both keys in Zero. This makes Zero the ultimate source of truth for all of the credentials needed to run your project.
If you already have a working Django project, feel free to skip this section. We can roughly follow the official Django tutorial to get up and running with a working app. The main difference is that we'll use Poetry so that the dependencies of our new app don't get intermingled with any Python packages that are installed globally. We also don't need to set up a database or data model for this exercise.
Here's a summary of the steps to follow:
Make a new recaptcha-django
directory and cd
into it.
Run poetry init
and enter "no" when asked if you want to define dependencies interactively.
poetry add Django
poetry run django-admin startproject recaptcha_django .
Create a new Django app called pages
via poetry run python manage.py startapp pages
.
Add 'pages.apps.PagesConfig'
to the list of INSTALLED_APPS
in settings.py
.
Configure the project to forward all requests to the pages
app by setting urls.py
to:
Then, add a simple "Hello World" view and template to the pages
app.
pages/views.py
:
pages/index/pages/index.html
should be a valid HTML file which displays a simple user registration form:
Run the Django development server with poetry run python manage.py runserver
, navigate to http://localhost:8000
, and you should see the signup form.
💡 You must access the site via
localhost
rather than127.0.0.1
since we providedlocalhost
as our domain when signing up for reCAPTCHA.
The easiest way to set up reCAPTCHA v2 on the frontend is to have the library automatically bind the challenge to a <button>
element. You can do this by pasting in the required <script>
tag and adding a few data attributes to the form's submit button:
After reCAPTCHA performs the challenge, it will invoke the function specified in data-callback
. This function must be defined in the global scope. All the callback function needs to do is submit the form to the backend, like so:
The reCAPTCHA response string will automatically be included in the form's POST data.
💡 "Invisible" reCAPTCHA v2 is not truly invisible, since a reCAPTCHA badge will be shown in the bottom right of the page. You are allowed to hide the badge, but you must display a message that links to Google's Privacy Policy and Terms of Service. This is described here in the reCAPTCHA FAQ.
Now we need to modify the backend logic to pass the reCAPTCHA response from the form to the reCAPTCHA web API. The API will then return a JSON response which indicates whether the user is a bot.
This is straightforward to do: you can access the form's POST data via the request.POST
dictionary, and then make the API call using the requests
package. The finished code looks like this:
context['message']
can be then be displayed by the index.html
template.
The final step is to fetch the reCAPTCHA v2 secret key from Zero. This is a breeze thanks to the Zero Python SDK , which you can install via
Then all we have to do is read the ZERO_TOKEN
environment variable and pass it to the SDK. Once the secret key has been retrieved, we'll store it in a module-level variable so that it does not need to be refetched every time the new user form is submitted.
The finished app can be run with
If you followed along with the post, you now have a user signup form that is protected from bots! This will prevent attackers from using automation to create bogus user accounts on your platform. While we used user signup in this example, it's a good idea to add reCAPTCHA integration to any publicly-accessible form that might be abused.
This article showcased how Zero can serve as the single source of truth for your project's secrets. The fact that the reCAPTCHA API key is fetched from Zero at runtime makes it easier to integrate your Django app with additional APIs like Stripe, Twilio, .etc in the future. It's also simpler to rotate your API keys on a regular basis when using Zero since the application's configuration does not need to be updated.
Happy coding!
If a secret is obtained by a malicious actor, the consequences can be severe. Monitoring the usage history of a secret in Zero allows you to detect unauthorized access and act before the secret is used in an exploit.
Use the Claude AI assistant to summarize emails in just a few lines of code.
Zero is a modern secrets manager built with usability at its core. Reliable and secure, it saves time and effort.