reCAPTCHA Integration
Assemble Web supports Google reCAPTCHA v3 to protect forms from automated abuse (bots, credential stuffing, spam submissions). The integration is opt-in and controlled entirely via environment variables, so it can be enabled or disabled per environment without any code changes.
Where It Is Used
reCAPTCHA is currently integrated into the following forms:
| Form | Component | Location |
|---|---|---|
| Login | LoginForm | src/features/Login/LoginForm.tsx |
| Sign-up | SignupForm | src/features/Signup/SignupForm.tsx |
Both forms follow the same integration model: when reCAPTCHA is enabled, the token is obtained on form submission and verified server-side before the underlying action (authentication or account creation) is performed.
Environment Variables
Four environment variables control the integration:
| Variable | Scope | Required | Description |
|---|---|---|---|
NEXT_PUBLIC_RECAPTCHA_ENABLED | Client | Yes | Set to 'true' to enable reCAPTCHA. Any other value disables it. |
NEXT_PUBLIC_RECAPTCHA_KEY | Client | Yes (when enabled) | The site key obtained from the Google reCAPTCHA Admin Console. Exposed to the browser. |
NEXT_PUBLIC_RECAPTCHA_MIN_SCORE | Client | No | Minimum acceptable score (0.0–1.0). Defaults to 0.8. Submissions with a score below this threshold are rejected. |
RECAPTCHA_SECRET | Server | Yes (when enabled) | The secret key obtained from the Google reCAPTCHA Admin Console. Never expose this to the client. |
RECAPTCHA_SECRET must never be prefixed with NEXT_PUBLIC_. Doing so would expose it to the browser and allow anyone to bypass server-side verification.
How It Works
The integration is split between client-side token generation and a server-side verification API route.
1. Client — Token Generation
When the user submits a protected form and reCAPTCHA is enabled (NEXT_PUBLIC_RECAPTCHA_ENABLED === 'true' and NEXT_PUBLIC_RECAPTCHA_KEY is set), the form calls grecaptcha.execute() to obtain a short-lived token:
grecaptcha.ready(() => {
const token = await grecaptcha.execute(siteKey, { action: 'submit' });
// token is then sent to the server-side verification endpoint
});
If the grecaptcha global is not available (e.g. the reCAPTCHA script failed to load), an error notification is shown and the submission is blocked.
2. Server — Token Verification (/api/recaptcha)
The token is POST-ed to the internal Next.js API route at src/app/api/recaptcha/route.ts, which forwards it to Google's verification endpoint:
POST https://www.google.com/recaptcha/api/siteverify
The server sends the token and the RECAPTCHA_SECRET to Google and returns the raw verification response (containing success and score) back to the client.
3. Client — Score Evaluation
After receiving the verification result, the form checks:
data.successmust betrue.data.scoremust be ≥NEXT_PUBLIC_RECAPTCHA_MIN_SCORE(default0.8).
If either condition fails, the submission is rejected and the user is shown an error notification. Only when both conditions pass does the form proceed with the primary action (login or sign-up).
Flow Diagram
User submits form
│
▼
grecaptcha.execute() ──► Google reCAPTCHA ──► token
│
▼
POST /api/recaptcha { captcha: token }
│
▼
Next.js API route ──► Google siteverify API ──► { success, score }
│
▼
score ≥ minScore?
├─ No ──► show error, block submission
└─ Yes ──► proceed with login / sign-up
reCAPTCHA Disclosure
Google requires that all sites using reCAPTCHA display the following notice wherever the widget is used. When NEXT_PUBLIC_RECAPTCHA_ENABLED is true, the forms render this disclaimer automatically via the page_sign_in_captcha_disclaimer i18n key:
The disclaimer is rendered in a styled container at the bottom of the form and is conditionally shown only when reCAPTCHA is active. Refer to loginPage.module.css (.recaptchaDisclaimer) for the styling.
Disabling reCAPTCHA
Set NEXT_PUBLIC_RECAPTCHA_ENABLED to any value other than 'true' (or omit it entirely). The integration is fully bypassed: no token generation occurs, no network call is made to /api/recaptcha, and the disclaimer is hidden. The form falls back to its standard submission flow.