'React and reCAPTCHA v3

Is there any easy way to use reCAPTCHA v3 in react? Did a google search an can only find components for v2. And only react-recaptcha-v3 for v3.

But I get an error Invalid site key or not loaded in api.js when I try to use the component.



Solution 1:[1]

Hey you don't need a package, its just an unnecessary package you don't need. https://medium.com/@alexjamesdunlop/unnecessary-packages-b3623219d86 I wrote an article about why you shouldn't use it and another package. Don't rely on some package! Rely on google instead :)

const handleLoaded = _ => {
  window.grecaptcha.ready(_ => {
    window.grecaptcha
      .execute("_reCAPTCHA_site_key_", { action: "homepage" })
      .then(token => {
        // ...
      })
  })
}

useEffect(() => {
  // Add reCaptcha
  const script = document.createElement("script")
  script.src = "https://www.google.com/recaptcha/api.js?render=_reCAPTCHA_site_key"
  script.addEventListener("load", handleLoaded)
  document.body.appendChild(script)
}, [])

return (
  <div
    className="g-recaptcha"
    data-sitekey="_reCAPTCHA_site_key_"
    data-size="invisible"
  ></div>
)

Solution 2:[2]

I am teaching myself React + TypeScript and this is what I came up with to implement recaptcha v3.

I wanted a simple solution that would allow me to:

  • get the token dynamically only when the form is submitted to avoid timeouts and duplicate token errors
  • use recaptcha only on some components for privacy reasons (eg. login, register, forgot-password) instead of globally defining recaptcha api.js in index.html
  • require the least code possible to implement in a component

reCAPTCHA.ts

declare global {
    interface Window {
        grecaptcha: any;
    }
}

export default class reCAPTCHA {
    siteKey: string;
    action: string;

    constructor(siteKey: string, action: string) {
        loadReCaptcha(siteKey);
        this.siteKey = siteKey;
        this.action = action;
    }

    async getToken(): Promise<string> {
        let token = "";
        await window.grecaptcha.execute(this.siteKey, {action: this.action})
            .then((res: string) => {
                token = res;
            })
        return token;
    }
}

const loadReCaptcha = (siteKey: string) => {
    const script = document.createElement('script')
    script.src = `https://www.recaptcha.net/recaptcha/api.js?render=${siteKey}`
    document.body.appendChild(script)
}

To use this class declare it as a property in the component:

recaptcha = new reCAPTCHA((process.env.REACT_APP_RECAPTCHA_SITE_KEY!), "login");

And on form submit get the token that you need to pass to backend:

let token: string = await this.recaptcha.getToken();

To verify the token on the backend:

recaptcha.ts

const fetch = require("node-fetch");
const threshold = 0.6;

export async function validateRecaptcha(recaptchaToken: string, expectedAction: string) : Promise<boolean> {
    const recaptchaSecret = process.env.RECAPTCHA_SECRET_KEY;
    const url = `https://www.recaptcha.net/recaptcha/api/siteverify?secret=${recaptchaSecret}&response=${recaptchaToken}`;
    let valid = false;
    await fetch(url, {method: 'post'})
        .then((response: { json: () => any; }) => response.json())
        .then((data: any)=> {
            valid = (data.success && data.score && data.action && data.score >= threshold && data.action === expectedAction);
        });
    return valid;
}

I have very limited experience with JS/TS and React but this solution does work for me. I welcome any input on improving this code.

Solution 3:[3]

Try this one! https://github.com/t49tran/react-google-recaptcha-v3 npm install react-google-recaptcha-v3

Solution 4:[4]

You can use react-google-recaptcha3 npm package (size: ~5 KB)

npm i react-google-recaptcha3

Usage

import ReactRecaptcha3 from 'react-google-recaptcha3';

const YOUR_SITE_KEY = '';

function App() {
 // load google recaptcha3 script
  useEffect(() => {
    ReactRecaptcha3.init(YOUR_SITE_KEY).then(
      (status) => {
        console.log(status);
      }
    );
  }, [])

}

Now on form submit you need to generate token and then append it to your form data

  const submit = () => {
    const formData = { name: "John", lastname: "Doe" }
    ReactRecaptcha3.getToken().then(
      (token) => {
        console.log(token);
        formData.token = token;
        // send request to backend
        fetch(url, { method: 'POST', body: JSON.stringify(formData) }).then(...)
        
      },
      (error) => {
        console.log(error);
      }
    );
  };

Now in backend you need to validate token

const request = require('request-promise');

const secretKey = YOUR_RECAPTCHA_SECRET_KEY;
const userIp = 'USER_IP';
request.get({
    url: `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${recaptchaToken}&remoteip=${userIp}`,
}).then((response) => {

    // If response false return error message
    if (response.success === false) {
        return res.json({
            success: false,
            error: 'Recaptcha token validation failed'
        });
    }
    // otherwise continue handling/saving form data
    next();
})

Stackblitz example

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Alex Dunlop
Solution 2
Solution 3 Erçin Dedeoğlu
Solution 4 Armen Stepanyan