Repository navigation
feat(website): protect contact form with Cloudflare Turnstile - #58
Merged
Merged
Conversation
The contact form was getting a lot of bot submissions that the honeypot didn't catch. The form now renders a Turnstile widget and sends its token with the submission; /api/contact verifies it with Cloudflare's siteverify endpoint (passing the client IP) before sending anything through Resend, and returns 403 when the token is missing, invalid, or reused. The widget is reset after a failed submit since tokens are single-use. Requires NEXT_PUBLIC_TURNSTILE_SITE_KEY and TURNSTILE_SECRET_KEY. Without the secret, verification is skipped in development and fails closed in production. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The contact form has been receiving a lot of bot submissions. This adds Cloudflare Turnstile:
ContactPage.tsxloads the Turnstile script, renders the widget (dark theme), sends the token with the form, and resets the widget after a failed submit (tokens are single-use)./api/contactverifies the token via Cloudflaresiteverify(with the client IP) before calling Resend, and returns403on a missing, invalid, or reused token.concepta.dev.Required env vars (Vercel: Production + Preview)
NEXT_PUBLIC_TURNSTILE_SITE_KEYTURNSTILE_SECRET_KEYTURNSTILE_SECRET_KEYfails closed: every submission is rejected. Add the preview hostnames (e.g.*.vercel.app) to the widget in Cloudflare too.Test plan
pnpm test:site(47 passing, including a new Turnstile test)🤖 Generated with Claude Code