|
| 1 | +# Google reCAPTCHA v3 Integration Notes |
| 2 | + |
| 3 | +## 1. Overview |
| 4 | + |
| 5 | +This document outlines the integration of Google reCAPTCHA v3 into the web application. reCAPTCHA v3 works by returning a score for each request without user friction. This score can be used to take appropriate action, such as requiring additional verification steps or blocking suspected bot traffic. It helps protect user actions like form submissions from abuse. |
| 6 | + |
| 7 | +## 2. Environment Variables |
| 8 | + |
| 9 | +The following environment variables are required for the reCAPTCHA integration to function correctly: |
| 10 | + |
| 11 | +- `NEXT_PUBLIC_RECAPTCHA_SITE_KEY`: This is the client-side site key obtained from the Google reCAPTCHA Admin Console. It's prefixed with `NEXT_PUBLIC_` because it needs to be accessible in the browser. |
| 12 | +- `RECAPTCHA_SECRET_KEY`: This is the server-side secret key obtained from the Google reCAPTCHA Admin Console. **This key must be kept confidential and should only be used on the server.** |
| 13 | + |
| 14 | +Ensure these variables are set in your local development environment (e.g., in an `.env.local` file at the root of the `apps/web` project) and in your deployment environments. |
| 15 | + |
| 16 | +## 3. How it Works |
| 17 | + |
| 18 | +The integration consists of three main parts: |
| 19 | + |
| 20 | +### a. Client-side Script Loading (`app/layout.tsx`) |
| 21 | + |
| 22 | +- The root layout file (`apps/web/app/layout.tsx`) includes a Next.js `Script` component to load the Google reCAPTCHA API script. |
| 23 | +- The script source URL includes the `NEXT_PUBLIC_RECAPTCHA_SITE_KEY`. |
| 24 | +- The script is loaded only if `NEXT_PUBLIC_RECAPTCHA_SITE_KEY` is present, preventing errors if the key is not configured. |
| 25 | +- The `strategy="afterInteractive"` attribute is used to load the script after the page becomes interactive, minimizing impact on initial page load performance. |
| 26 | + |
| 27 | +### b. `useRecaptcha` Hook (`hooks/use-recaptcha.ts`) |
| 28 | + |
| 29 | +- The custom React hook `useRecaptcha` (located in `apps/web/hooks/use-recaptcha.ts`) provides a convenient way to trigger reCAPTCHA verification. |
| 30 | +- It exports an `executeRecaptcha` function that takes an `action` string as an argument. This `action` helps you identify which part of your site is being protected when viewing results in the Google reCAPTCHA Admin Console. |
| 31 | +- When called, `executeRecaptcha`: |
| 32 | + 1. Checks if `NEXT_PUBLIC_RECAPTCHA_SITE_KEY` is available. If not, it logs an error and returns `null`. |
| 33 | + 2. Checks if `window.grecaptcha` and `window.grecaptcha.ready` are available (i.e., if the Google script has loaded). |
| 34 | + 3. Calls `window.grecaptcha.ready()` to ensure the API is ready. |
| 35 | + 4. Calls `window.grecaptcha.execute()` with the site key and the provided `action` to get a reCAPTCHA token. |
| 36 | + 5. Returns a Promise that resolves with the token, or `null` if an error occurs. |
| 37 | +- The `executeRecaptcha` function is wrapped in `useCallback` for performance optimization. |
| 38 | + |
| 39 | +### c. `/api/recaptcha` Server-side Endpoint (`app/api/recaptcha/route.ts`) |
| 40 | + |
| 41 | +- This API route (located at `apps/web/app/api/recaptcha/route.ts`) handles the server-side verification of the reCAPTCHA token. |
| 42 | +- It expects a `POST` request with a JSON body containing the `token` received from the client-side. |
| 43 | +- **Verification Steps**: |
| 44 | + 1. Retrieves the `RECAPTCHA_SECRET_KEY` from server environment variables. Returns a 500 error if not set. |
| 45 | + 2. Checks if the `token` is present in the request body. Returns a 400 error if not. |
| 46 | + 3. Makes a `POST` request to Google's `https://www.google.com/recaptcha/api/siteverify` endpoint. |
| 47 | + 4. The request to Google includes the `secret` (your `RECAPTCHA_SECRET_KEY`) and `response` (the client's `token`). |
| 48 | + 5. Parses the JSON response from Google. |
| 49 | + 6. Returns relevant information from Google's response to the client, including `success`, `score`, `action`, `challenge_ts`, `hostname`, and `error-codes`. |
| 50 | +- Includes error handling for the fetch request to Google and other potential issues. |
| 51 | + |
| 52 | +## 4. Using the `recaptcha-example-form.tsx` |
| 53 | + |
| 54 | +- An example component `RecaptchaExampleForm` (located in `apps/web/components/recaptcha-example-form.tsx`) demonstrates the end-to-end reCAPTCHA flow. |
| 55 | +- It renders a simple form. On submission: |
| 56 | + 1. It calls `executeRecaptcha` from the `useRecaptcha` hook. |
| 57 | + 2. If a token is received, it sends this token to the `/api/recaptcha` endpoint. |
| 58 | + 3. It then logs the verification response from the API and displays a status message to the user, indicating whether the action would be allowed based on the `success` status and `score` (e.g., score > 0.5). |
| 59 | +- **To test the integration**: Temporarily import and render this component on any page within the `apps/web` application. |
| 60 | + |
| 61 | +## 5. Testing Steps |
| 62 | + |
| 63 | +1. **Set Environment Variables**: |
| 64 | + * Ensure `NEXT_PUBLIC_RECAPTCHA_SITE_KEY` and `RECAPTCHA_SECRET_KEY` are correctly set in your local environment (e.g., in an `.env.local` file at the root of `apps/web`). Use valid keys from your Google reCAPTCHA admin console for a specific domain (localhost can be registered for testing). |
| 65 | + |
| 66 | +2. **Render the Example Form**: |
| 67 | + * Modify an existing page (e.g., the homepage) in `apps/web` to import and render the `RecaptchaExampleForm` component. |
| 68 | + ```tsx |
| 69 | + // Example: in apps/web/app/page.tsx |
| 70 | + import { RecaptchaExampleForm } from "@/components/recaptcha-example-form"; |
| 71 | + |
| 72 | + export default function HomePage() { |
| 73 | + return ( |
| 74 | + <div> |
| 75 | + {/* ... other page content ... */} |
| 76 | + <RecaptchaExampleForm /> |
| 77 | + </div> |
| 78 | + ); |
| 79 | + } |
| 80 | + ``` |
| 81 | + |
| 82 | +3. **Open Browser Developer Tools**: |
| 83 | + * Access the page where `RecaptchaExampleForm` is rendered. |
| 84 | + * Open your browser's developer tools (usually by pressing F12). |
| 85 | + |
| 86 | +4. **Monitor Console**: |
| 87 | + * Check the **Console** tab for logs: |
| 88 | + * From `useRecaptcha` if the site key is missing or reCAPTCHA isn't ready. |
| 89 | + * From `RecaptchaExampleForm` showing the token received (if any), the call to `/api/recaptcha`, the verification response, and status messages. |
| 90 | + |
| 91 | +5. **Check Network Tab**: |
| 92 | + * Switch to the **Network** tab in developer tools. |
| 93 | + * Submit the example form. |
| 94 | + * Look for the `POST` request to `/api/recaptcha`. Inspect its payload (the token) and response (Google's verification result). |
| 95 | + * Note: The call to Google's `siteverify` endpoint happens server-to-server, so you won't see it directly in the browser's network tab, but its outcome is returned by your `/api/recaptcha` endpoint. |
| 96 | + |
| 97 | +6. **Google reCAPTCHA Admin Console (Post-Deployment)**: |
| 98 | + * After deploying the application to a staging or test environment with valid production/test reCAPTCHA keys: |
| 99 | + * Visit your Google reCAPTCHA Admin Console. |
| 100 | + * Select the site key you configured. |
| 101 | + * You should see traffic data, including the number of requests, scores, and the distribution of actions (e.g., 'example_form_submit'). This helps verify that reCAPTCHA is actively processing requests for your site. |
| 102 | + |
| 103 | +7. **Test Missing Keys**: |
| 104 | + * Temporarily unset or comment out `NEXT_PUBLIC_RECAPTCHA_SITE_KEY` in your `.env.local` and restart the development server. The reCAPTCHA script should not load, and `executeRecaptcha` should return `null` or handle it gracefully. |
| 105 | + * Temporarily unset `RECAPTCHA_SECRET_KEY`. The `/api/recaptcha` endpoint should return a 500 error, which the example form should handle. |
| 106 | + |
| 107 | +By following these steps, you can thoroughly test the reCAPTCHA v3 integration. Remember to remove the `RecaptchaExampleForm` from any public pages after testing. |
0 commit comments