React Logoreact-google-recaptcha

The `react-google-recaptcha` library provides a simple and declarative way to integrate Google reCAPTCHA into React applications. Google reCAPTCHA is a free service that helps protect websites from spam and abuse by differentiating between human and automated access. It offers various types, including 'I'm not a robot' checkbox, invisible reCAPTCHA, and reCAPTCHA v3 (score-based).

Purpose and Functionality:
* Bot Prevention: The primary goal is to prevent bots, spammers, and malicious automated scripts from interacting with your website, such as submitting forms, creating accounts, or posting comments.
* User Experience: For users, it aims to be as unobtrusive as possible, often requiring just a single click or even running entirely in the background.
* Client-Side Integration: `react-google-recaptcha` handles the rendering of the reCAPTCHA widget on the client side, managing its lifecycle and user interactions.
* Token Generation: Upon successful user verification (or background assessment for v3), reCAPTCHA generates a unique token. This token is crucial for server-side verification.

Key Features and Props:
* `sitekey` (required): Your reCAPTCHA site key obtained from the Google reCAPTCHA admin console. This key is client-side public.
* `onChange(token)`: A callback function that is triggered when the user successfully completes the reCAPTCHA challenge or when the invisible reCAPTCHA generates a token. It receives the reCAPTCHA token as an argument.
* `onExpired()`: A callback function invoked when the reCAPTCHA token expires (typically after 2 minutes). You should re-render or re-verify if this happens.
* `onError(error)`: A callback function for any errors during reCAPTCHA loading or execution.
* `theme`: 'light' or 'dark' (for checkbox reCAPTCHA).
* `size`: 'normal', 'compact', or 'invisible' (for checkbox reCAPTCHA).
* `hl`: Specifies the language code (e.g., 'en', 'es', 'fr') to display the reCAPTCHA widget in a specific language.

Server-Side Verification (Crucial Step):
While `react-google-recaptcha` handles the client-side rendering and token generation, it is absolutely essential to verify this token on your server-side application. Without server-side verification, an attacker could bypass the client-side reCAPTCHA by simply submitting form data without a valid token. The server-side verification involves sending the received token along with your secret key (obtained from the Google reCAPTCHA admin console) to Google's reCAPTCHA verification API. Google then responds with a success status and other details, confirming the legitimacy of the token.

Example Code

import React, { useState } from 'react';
import ReCAPTCHA from 'react-google-recaptcha';

const MyFormWithRecaptcha = () => {
  const [recaptchaToken, setRecaptchaToken] = useState(null);
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: '',
  });

  // Replace with your actual reCAPTCHA site key from Google Admin Console
  // For security, use environment variables in a real application (e.g., .env file)
  const RECAPTCHA_SITE_KEY = process.env.REACT_APP_RECAPTCHA_SITE_KEY || 'YOUR_RECAPTCHA_SITE_KEY';

  const handleRecaptchaChange = (token) => {
    console.log('reCAPTCHA Token:', token);
    setRecaptchaToken(token);
  };

  const handleFormChange = (e) => {
    const { name, value } = e.target;
    setFormData(prevData => ({ ...prevData, [name]: value }));
  };

  const handleSubmit = async (e) => {
    e.preventDefault();

    if (!recaptchaToken) {
      alert('Please complete the reCAPTCHA challenge.');
      return;
    }

    // In a real application, you would send formData and recaptchaToken to your backend server
    // for further processing and server-side reCAPTCHA verification.
    try {
      const response = await fetch('/api/submit-form', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          ...formData,
          recaptchaToken: recaptchaToken,
        }),
      });

      const result = await response.json();

      if (result.success) {
        alert('Form submitted successfully! Server-side reCAPTCHA verification passed.');
        // Reset form and reCAPTCHA (if needed, reCAPTCHA often resets on token expiry or successful submission)
        setFormData({ name: '', email: '', message: '' });
        setRecaptchaToken(null);
      } else {
        alert(`Form submission failed: ${result.message || 'Server verification failed.'}`);
      }
    } catch (error) {
      console.error('Error submitting form:', error);
      alert('An error occurred during form submission.');
    }
  };

  return (
    <form onSubmit={handleSubmit} style={{ padding: '20px', maxWidth: '500px', margin: 'auto', border: '1px solid #ccc', borderRadius: '8px', boxShadow: '0 2px 4px rgba(0,0,0,0.1)' }}>
      <h2>Contact Us</h2>
      <div style={{ marginBottom: '15px' }}>
        <label htmlFor="name" style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold' }}>Name:</label>
        <input
          type="text"
          id="name"
          name="name"
          value={formData.name}
          onChange={handleFormChange}
          required
          style={{ width: '100%', padding: '10px', boxSizing: 'border-box', border: '1px solid #ddd', borderRadius: '4px' }}
        />
      </div>
      <div style={{ marginBottom: '15px' }}>
        <label htmlFor="email" style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold' }}>Email:</label>
        <input
          type="email"
          id="email"
          name="email"
          value={formData.email}
          onChange={handleFormChange}
          required
          style={{ width: '100%', padding: '10px', boxSizing: 'border-box', border: '1px solid #ddd', borderRadius: '4px' }}
        />
      </div>
      <div style={{ marginBottom: '15px' }}>
        <label htmlFor="message" style={{ display: 'block', marginBottom: '5px', fontWeight: 'bold' }}>Message:</label>
        <textarea
          id="message"
          name="message"
          value={formData.message}
          onChange={handleFormChange}
          required
          rows="5"
          style={{ width: '100%', padding: '10px', boxSizing: 'border-box', border: '1px solid #ddd', borderRadius: '4px' }}
        ></textarea>
      </div>

      <div style={{ marginBottom: '20px' }}>
        <ReCAPTCHA
          sitekey={RECAPTCHA_SITE_KEY}
          onChange={handleRecaptchaChange}
          onExpired={() => setRecaptchaToken(null)} // Clear token if expired
          onError={() => alert('reCAPTCHA encountered an error. Please try again.')}
          // You can add theme="dark" or size="compact" here if desired for checkbox reCAPTCHA
        />
      </div>

      <button 
        type="submit" 
        disabled={!recaptchaToken} 
        style={{
          padding: '10px 20px', 
          backgroundColor: recaptchaToken ? '#007bff' : '#cccccc', 
          color: 'white', 
          border: 'none', 
          borderRadius: '5px', 
          cursor: recaptchaToken ? 'pointer' : 'not-allowed', 
          fontSize: '16px',
          fontWeight: 'bold'
        }}
      >
        Submit
      </button>
    </form>
  );
};

export default MyFormWithRecaptcha;