Validating React Js form submit with reCaptcha

Last updated : Jul 30, 2023 12:00 AM

This article demonstrates two ways to validate a React form using Google's ReCaptcha and React simple captcha. The recommended way is to use Google's ReCaptcha; the easy way is to use the React simple captcha. If your form data contains sensitive information, consider using Google's ReCaptcha.

Steps to Implement React simple captcha Validation

Figure 1: React Simple Captcha validation
Figure 1: React Simple Captcha validation

Install Dependencies

We have to install the react-simple-captcha library, which provides a React component for the captcha.

npm install react-simple-captcha

or

yarn add react-simple-captcha

Using Simple Captcha in a form

Here is how to use the simple captcha in a simple React Js form. Here I prevent bots from submitting the form. Therefore, the submit button appears after a successful captcha validation.

Simple Captcha in a formDescription
import { useEffect, useState } from "react"
import { LoadCanvasTemplate, loadCaptchaEnginge, validateCaptcha } from "react-simple-captcha"

export const SignupForm = () => {

  const [error, setError] = useState('')
  const [isFormValid, setIsFormValid] = useState(false)

  const handleFormSubmit = (event) => {
    event.preventDefault()
  }

  const validateFormUser = () => {
    const captchaInput = document.getElementById('captcha_input').value
    setError("")
    if (validateCaptcha(captchaInput) === true) {
      setIsFormValid(true)
    } else {
      setError("Invalid Captcha")
    }
  }

  useEffect(() => {
    loadCaptchaEnginge(6, 'green')
  }, [])

  return (
    <>
      <form onSubmit={handleFormSubmit}>
        {error && <p>{error}</p>}
        <label >
          Name: <input type="text" name="name" />
        </label>
        <br />
        <label>
          Password: <input type="password" name="password" />
        </label>
        {isFormValid && <input type="submit" value="Submit" />}
      </form>
      {!isFormValid && <div>
        <LoadCanvasTemplate />
        <input type="text" id="captcha_input" />
        <input type="button" value="Validate" onClick={validateFormUser} />
      </div>}
    </>
  )
}

You may encounter a webpack related error Module not found: Error: Can't resolve 'buffer'. In such cases, installing buffer fixes the issue.

npm install --save buffer

Steps to Implement Google reCaptcha Validation

To implement Google reCaptcha, you'll need a ReCaptcha site key and secret key, which you can get by registering your site with Google's ReCaptcha service. That will provide you with two API keys, SITE KEY, and SECRET KEY, to validate the user. It is a good practice to store these keys in environment variables for security reasons. In below code examples, I refer to them as process.env.REACT_APP_SITE_KEY and process.env.REACT_APP_SECRET_KEY.

Figure 2: Google reCaptcha validation
Figure 2: Google reCaptcha validation
Figure 3: Google reCaptcha validation success
Figure 3: Google reCaptcha validation success

Install dependencies

Install Google reCaptcha by running the below command:

npm install --save react-google-recaptcha

or

yarn add react-google-recaptcha

Setup the ReCAPTCHA

Step 1: ReCAPTCHA component in React Js

Here is how to set up the reCaptcha component in a React Js component. Note that the ReCAPTCHA component has two props. I use the ref to obtain the value from the ReCAPTCHA component and reset the component after every submission.

ReCAPTCHA in React JsDescription
import { useRef, useState } from 'react'
import ReCAPTCHA from 'react-google-recaptcha'

export default function SignupForm() {
  const captchaReference = useRef(null)
  const [name, setName] = useState('')
  const [captchaStatus, setCaptchaStatus] = useState({ success: false, message: '' })

  const submitForm = async (e) => {
    e.preventDefault()
    const captcha = captchaReference.current.getValue();
    captchaReference.current.reset()

    const response = await fetch(
      `http://localhost:3002/submit-form`,
      {
        headers: {
          "Content-Type": "application/json",
        },
        method: "POST",
        body: JSON.stringify({ captcha, name })
      }
    );
    const captchaValidation = await response.json();
    setCaptchaStatus(captchaValidation)
  }
  return (
    <form onSubmit={submitForm}>
      <div>Name: <input type="text" value={name} onChange={(e) => setName(e.target.value)} /></div>
      <ReCAPTCHA
        sitekey={process.env.REACT_APP_SITE_KEY}
        ref={captchaReference}
      />
      <p>{captchaStatus.message}</p>
      <input type='submit' value='Submit' />
    </form>
  )
}

Step 2: Validating reCaptcha token on the server

The second validation stage happens in the server. In the above component, I capture the user form details and the captcha token and submit them to the server to process further. Here is a simple Express server to represent the backend.

Validating reCaptcha tokenDescription
const express = require('express');
const axios = require('axios');
const app = express();
const cors = require('cors')
app.use(cors(), express.json())

app.post('/submit-form', async (req, res) => {
    const { captcha, name } = req.body;
    try {
        const googleResponse = await axios.post(`https://www.google.com/recaptcha/api/siteverify?secret=${process.env.SECRET_KEY}&response=${captcha}`);
        if (googleResponse.data.success) {
            saveData(name)
            res.json({ success: true, message: 'Form submitted' });
        } else {
            res.json({ success: false, message: 'Captcha validation failed' });
        }
    } catch (err) {
        res.json({ success: false, message: 'Error occurred while validating captcha' });
    }
});
app.listen(3002, () => console.log('Server started'));

I validate the user's captcha token on the server with the secret key. This validation should happen on the server side due to CORS restrictions. Google API will reject any requests coming from the browser.

Lance

By: Lance

Hi, I'm Lance Raney, a dedicated Fullstack Developer based in Oklahoma with over 15 years of exp

Read more...