Client-Server Implementation of reCAPTCHA with React and Django
Google provides a service known as reCAPTCHA that helps keep malicious users away from your website. It does this by posing a challenge that is simple for humans to solve and difficult for bots. <!--more--> This tutorial will show you how to implement Google reCAPTCHA v2 into your Django and React application.
Prerequisites
To be able to follow along in this article, the reader should have
- Node.js installed.
- Python installed.
- Basic React knowledge.
- Basic Python and Django knowledge.
- Basic understanding of the Django Rest Framework.
- Understanding of the Fetch API.
Goals
By the end of this article, the reader will be able to:
- Implement reCAPTCHA into a website.
- Verify the reCAPTCHA response on the server-side and take the appropriate action.
- Connect a React frontend with a Django backend.
Acquiring our Site and Secret Keys
To enable reCAPTCHA on your website, you first need to register your site on the reCAPTCHA website so that you be able to acquire the site and secret keys. Click here to open the Google reCAPTCHA section for registering a new site.
Fill in the required information as shown below:
- In the Label text field, enter your site name.
- In the reCAPTCHA section, choose reCAPTCHA v2. In the options list that appears, select option 1 ("I'm not a robot" checkbox).
- In the Domains section, enter the following two options: 127.0.0.1 and localhost.
- Accept the reCAPTCHA's terms of service and click submit.
- You will then be provided with a site key (to use in the frontend) and a secret key (in the backend).
Setting up our Frontend
Create a folder named react-django-recaptcha.
Open the folder in your terminal and run the following command:
npx create-react-app frontend
The command above will create our React frontend.
Next,run the following commands to navigate into the frontend directory.
cd frontend
npm i react-google-recaptcha
The above command installs the Google reCAPTCHA v2 package into our project. We will use this to set up reCAPTCHA in the frontend.
Now, open the App.js
file and modify the code in it with the following code:
import './App.css';
import { useState } from 'react';
import ReCAPTCHA from "react-google-recaptcha";
function App() {
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [message, setMessage] = useState('')
const [captchaResult, setCaptchaResult] = useState()
const handleSubmit = (e) => {
e.preventDefault()
// Handle form submission here
}
const handleRecaptcha = (value) => {
fetch('http://127.0.0.1:8000/recaptcha/', {
method: 'POST',
body: JSON.stringify({ 'captcha_value': value }),
headers: { 'Content-Type': 'application/json' }
})
.then(res => res.json())
.then(data => {
console.log(data.captcha.success)
setCaptchaResult(data.captcha.success)
})
}
return (
<div className="container">
<h2>Contact us:</h2>
<form>
<label>Name</label>
<input type="text" name="name" placeholder="Your name.." value={name} onChange={(e) => {setName(e.target.value)}} />
<label>Email</label>
<input type="email" name="email" placeholder="[email protected]" value={email} onChange={(e) => {setEmail(e.target.value)}} />
<label>Subject</label>
<textarea name="subject" placeholder="Write something.." value={message} onChange={(e) => {setMessage(e.target.value)}} />
<div className="cta">
<ReCAPTCHA
sitekey="YOUR SITE KEY"
onChange={handleRecaptcha}
/>
{
captchaResult && <button type='submit' onClick={(e) => {handleSubmit(e)}}>Submit</button>
}
</div>
</form>
</div>
);
}
export default App;
- In the code above, we have a contact form that contains the fields; name, email, and message. We track the data entered in these fields using the
useState()
hook. - In the
div
with the classNamecta
, we have our ReCaptcha component that takes two attributes. One is the site key that we get from the Google reCAPTCHA website. The other attribute is anonChange
attribute that calls thehandleRecaptcha()
function when the reCAPTCHA component is clicked on. - Below the reCAPTCHA component, we conditionally render the
Submit
button depending on the outcome of the reCAPTCHA. We only show it when the success value of the reCAPTCHA evaluates to true (when the user successfully solves the reCAPTCHA challenge). This helps ensure that the form data can only be submitted after the reCAPTCHA challenge has been solved. - The
handleRecaptcha()
function takes in a value that we send to the backend for server-side verification. You can console.log the value to see it. Next, we use the Fetch API to make a POST request to the routehttp://127.0.0.1:8000/recaptcha/
, which we will, later on, create on our server. We then use the response we get from the server and pass it to thesetCaptchaResult()
function, which sets the state of thecaptchaResult
. The response is either true or false. If it is true, we show theSubmit
button. - After the Submit button has been displayed (which means that the reCAPTCHA challenge has been successfully solved), you can go ahead and handle the form submission using the
handleSubmit()
function.
Now, open the App.css
and modify it with the following code to make our webpage look better:
body {
background: #f2f2f2;
height: 100vh;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.container {
max-width: 80%;
border-radius: 5px;
background-color: white;
padding: 20px;
}
input[type="text"],
[type="email"],
textarea {
width: 100%;
padding: 12px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
margin-top: 6px;
margin-bottom: 16px;
resize: vertical;
}
.cta {
display: flex;
flex-direction: column;
justify-content: flex-end;
}
button {
background-color: #04aa6d;
color: white;
padding: 12px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
margin-top: 1rem;
}
Running our Frontend: Open the integrated terminal and type in the following command:
npm start
This will open our project in the local development server. Open 127.0.0.1:3000
on your web browser to view the webpage.
Setting up our backend
To set up our backend, we first need to create a virtual environment. To learn more about Django virtual environment, click here.
Open the command prompt and cd
into our react-django-recaptcha
folder.
Type in the following command to create a virtual environment:
python -m venv recaptcha-env
This creates a virtual environment with the name recaptcha-env
.
To activate the virtual environment, type in the following command:
.\recaptcha-env\Scripts\activate
Now that we've activated our virtual environment, let's proceed and install Django by running the following commands:
python -m pip install Django
Next, execute the following commands in the same directory:
django-admin startproject recaptchaVerification
cd recaptchaVerification
code .
The first command creates a Django application with the name recaptchaVerification
, the second one changes our active directory, and the last one launches our code editor.
Open the integrated terminal and ensure that the virtual environment is still active. If it is not, type in the following commands to activate it:
cd ..
.\recaptcha-env\Scripts\activate
To make sure our server is working, run the following command (remember to cd
into the recaptchaVerification
directory before running the command):
python manage.py runserver
Now, let's create a new app to handle our API requests.
Run the following command to create an app named api
:
django-admin startapp api
Next, proceed and install all the dependencies and shown below:
pip install djangorestframework
python -m pip install requests
python -m pip install django-cors-headers
The first command installs Django Rest Framework, which helps us create an API.
- The second command installs the Requests HTTP library that helps us send HTTP requests easily. We will use this to send an HTTP request to Google ReCAPTCHA to verify the user's response.
- The last command installs CORS that allows in-browser requests to your Django application from other origins. This will enable our React frontend to make requests to our Django backend.
Modifying the settings.py
file: Open the settings.py
file and modify theINSTALLED_APPS
and MIDDLEWARE
section as shown below:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'api.apps.ApiConfig', #registers our api app
'rest_framework',
'requests',
'corsheaders'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
"corsheaders.middleware.CorsMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
At the bottom of the settings.py
file, add the following lines of code:
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
"http://127.0.0.1:3000",
]
You'll notice that we've added cross-origin resource sharing (CORS). CORS is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served. Therefore, the above array ensures our two applications can communicate.
Modifying the recaptchaVerification\urls.py
file: Open the urls.py
file located in the recaptchaVerification
directory and modify it as shown below:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('api.urls'))
]
This will help route all the requests to our api app.
Working on the api app: In the api
file that we created earlier, open the views.py
file and modify it as shown below:
import requests
from rest_framework.response import Response
from rest_framework.decorators import api_view
@api_view(['POST'])
def recaptcha(request):
r = requests.post(
'https://www.google.com/recaptcha/api/siteverify',
data={
'secret': 'YOUR SECRET KEY',
'response': request.data['captcha_value'],
}
)
return Response({'captcha': r.json()})
- In the code above, we used the
@api_view
decorator provided by the Django Rest Framework to restrict only POST requests to this API route. - We then used the requests HTTP library to make a POST request to
https://www.google.com/recaptcha/api/siteverify
. This API post request can take three parameters;secret
,response
, andremoteip
. - The
secret
is the secret key provided by the Google reCAPTCHA website, theresponse
is the user response token that we get from the frontend when the user solves the captcha challenge andremoteip
is the user's IP address. The first two are required but theremoteip
is optional. Therefore, we have only used thesecret
and theresponse
in our example. - The API responds with a JSON object that contains the following attributes:
success
which is either true or false,challenge_ts
which is the timestamp the challenge was taken,hostname
which is the name of our hostname of the site where the captcha was solved (in our case, localhost) anderror-codes
which are optional. - We store the API response in
r
and then send it to the frontend as a JSON object.
In the same API folder, create a urls.py
file and modify it as shown below:
from django.urls import path
from . import views
urlpatterns = [
path('recaptcha/', views.recaptcha)
]
The code above exposes our API endpoint that the frontend will access.
Testing our application
To test our application, ensure that the React front-end and the Django back-end are running. Now go to your browser on localhost:3000
. You'll notice that our contact form has no submission button.
Next, solve the reCAPTURE challenge, and notice that the submit button appears, and only then can you submit the form. This ensures that someone has to solve the captcha challenge before submitting data.
You'll also notice that the captcha verification displays a message, verification expired
after a while. Recheck the checkbox, and the submit button disappears. This means that our application is working since the submit button is only displayed when a server responds with success = true
.
Conclusion
Implementing Google reCAPTCHA in a React application is easy, and it can give your application another layer of security against bots. It provides a great and simple way of protecting us from spamming victims.
Thanks for reading, and hope you can implement it into your next project.
Happy coding!
Peer Review Contributions by: Miller Juma