Insights

Securing a Next.js Contact Form using Google reCAPTCHA

Integrating Google reCAPTCHA with a Next.js Form

In this blog, we will learn how to integrate Google reCAPTCHA with a Next.js contact form to prevent spam submissions and enhance the security of the form.

Google reCAPTCHA is a free service provided by Google that helps protect websites from abusive activities by bots. By adding reCAPTCHA to our contact form, we can ensure that only human users can submit the form while reducing the chances of receiving spam.

Please refer to my previous blog on building a Contact Us form in Sitecore using Nextjs and Nodemailer.

Prerequisites

Before proceeding, ensure that you have the following set up:

  1. A working Next.js project with a contact form and corresponding json rendering in sitecore implemented.
  2. A Google reCAPTCHA API key. If you don't have one, you can get it by registering your website with the Google reCAPTCHA service.

Create a Google reCAPTCHA Account

  1. Go to the Google reCAPTCHA website (https://www.google.com/recaptcha) and log in with your Google account.
  2. Click on the "Admin Console" button to create a new reCAPTCHA project.
  3. Fill in the required information, such as the label (name) of your project and the domains where the reCAPTCHA will be used.
  4. Choose the reCAPTCHA type. For this tutorial, we'll use "reCAPTCHA v2" with the "Checkbox" option.
  5. Add the domain(s) where you'll implement the reCAPTCHA and accept the terms of service.
  6. After successfully registering your site, you'll receive the Site Key and Secret Key. Keep these keys secure, as the Secret Key should never be exposed on the client-side.

Install react-google-recaptcha Package

To use the ReCAPTCHA component, we need to install the react-google-recaptcha package. Run the following command in your project directory:

npm install react-google-recaptcha

Adding reCAPTCHA to the Contact Form

In the component where you have implemented the contact form, add the reCAPTCHA widget to the form. Update your ContactUsForm.tsx component as follows:

//...(Existing imports)
import ReCAPTCHA from 'react-google-recaptcha';

//...(Sitecore fields)
const FORM_DEFAULT: {
  [key: string]: string;
} = {
  firstName: '',
  lastName: '',
  message: '',
    captchaToken: '',
};

const ContactUsForm = ({ fields }: ContactUsFormProps): JSX.Element => {
  const [formData, setFormData] = useState(FORM_DEFAULT);
  const [successMsgCss, setSuccesssMsg] = useState(false);
// Create a ref for the reCAPTCHA widget
  const recaptcha: RefObject<ReCAPTCHA> = useRef(null);
// ... (Existing functions)

const formSubmit = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
            formData.recipient = fields.emailRecipient.value;
      formData.emailSubject = fields.emailSubject.value;
      fetch('/api/contact', {
        method: 'POST',
        headers: {
          Accept: 'application/json, text/plain, */*',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(formData),
      })
        .then((response) => {
          console.log('response recieved');
          if (response.status === 200) {
            console.log('response succeeded');
            setSuccesssMsg(true);
            setFormData(FORM_DEFAULT);
                        recaptcha?.current?.reset();// reset recaptcha after submission
          }
        })
        .catch((error) => {
          console.error(error);
        });
    }
  };

const onCaptchaChange = (token: string | null) => {
    // Set the captcha token when the user completes the reCAPTCHA
    if (token) {
      formData.captchaToken = token;
    }
  };
return (
{/* ... (existing TSX markup) */}
    <div className="pr-15px pl-25px pt-50px pb-25px mx-auto max-w-1200px w-full">
      <div>
    {/* ... (existing form fields) */}
  {/* Add the reCAPTCHA widget */}
    <div className="pb-20px">
          <ReCAPTCHA
            size="normal"
            sitekey="YOUR_RECAPTCHA_SITE_KEY"
            onChange={onCaptchaChange}
            ref={recaptcha}
          />
        </div>
{/* ... (existing submit button) */}
      </form>
    </div>

Server-Side Verification

Update your API route (/pages/api/contact.ts) to validate the reCAPTCHA token received from the frontend:

//...existing imports
import axios from 'axios';

export default async function handler(req: NextApiRequest, res: NextApiResponse): Promise<void> {
// ... (existing transporter setup and mailData)
// Validate the reCAPTCHA token on the server-side

try {
    const response = await axios.post(
      `https://www.google.com/recaptcha/api/siteverify?secret=${process.env.RECAPTCHA_SECRET_KEY}&response=${req.body.captchaToken}`
    );
    if (response.data.success) {
//reCaptcha verification successfull
transporter.sendMail(mailData, function (err, info) {
        if (err) {
          console.log(err);
          res.status(500).send('Internal Server Error');
        } else {
          console.log('successful');
          console.log(info);
          res.status(200).end();
        }
      });
    } else {
      // reCAPTCHA verification failed
      res.status(400).send('reCAPTCHA verification failed.');
    }
  } catch (error) {
    console.error(error);
    res.status(500).send('Internal server error');
  }
}

In this above code, we use axios.post to send a POST request to the Google reCAPTCHA API endpoint (https://www.google.com/recaptcha/api/siteverify). We pass the reCAPTCHA token and the reCAPTCHA secret key in the request body. The response contains the verification result, which we check to ensure the reCAPTCHA was successful. If the reCAPTCHA verification succeeds, we proceed with sending the email; otherwise, we return an error response.

Conclusion

In this blog post, we learned how to add Google reCAPTCHA to your existing Next.js contact form. By integrating reCAPTCHA, you can enhance the security of your form and prevent automated spam submissions. Implementing reCAPTCHA is a straightforward process and provides an added layer of protection for your website's forms.

👋 Hey Sitecore Enthusiasts!

Sign up to our bi-weekly newsletter for a bite-sized curation of valuable insight from the Sitecore community.

What’s in it for you?

  • Stay up-to-date with the latest Sitecore news
  • New to Sitecore? Learn tips and tricks to help you navigate this powerful tool
  • Sitecore pro? Expand your skill set and discover troubleshooting tips
  • Browse open careers and opportunities
  • Get a chance to be featured in upcoming editions
  • Learn our secret handshake
  • And more!
Sitecore Snack a newsletter by Fishtank Consulting
 

Meet Anju Thomas

Sitecore Web Developer

🎞🥘🧩

Anju is a Sitecore Developer with a Bachelor's Degree in Computer Science and over 4 years of experience in Sitecore development. She loves solving Sudoku puzzles, watching movies, eating delicious food and exploring the world.

Connect with Anju