Validating a token

The validation of tokens needs to be done on the server. Here is an example of how to do it with Next.js 13 App Router.

"use client";
import { Turnstile } from "@marsidev/react-turnstile";

export default function LoginForm() {
  const formRef = React.useRef<HTMLFormElement>(null);

  async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const formData = new FormData(formRef.current!);
    const token = formData.get("cf-turnstile-response");

    const res = await fetch("/api/verify", {
      method: "POST",
      body: JSON.stringify({ token }),
      headers: {
        "content-type": "application/json",
      },
    });

    const data = await res.json();
    if (data.success) {
      // the token has been validated
    }
  }

  return (
    <form ref={formRef} onSubmit={handleSubmit}>
      <input type="text" placeholder="username" />
      <input type="password" placeholder="password" />
      <Turnstile siteKey="1x00000000000000000000AA" />
      <button type="submit">Login</button>
    </form>
  );
}
import type { TurnstileServerValidationResponse } from "@marsidev/react-turnstile";

const verifyEndpoint = "https://challenges.cloudflare.com/turnstile/v0/siteverify";
const secret = "1x0000000000000000000000000000000AA";

export async function POST(request: Request) {
  const { token } = (await request.json()) as { token: string };

  const res = await fetch(verifyEndpoint, {
    method: "POST",
    body: `secret=${encodeURIComponent(secret)}&response=${encodeURIComponent(token)}`,
    headers: {
      "content-type": "application/x-www-form-urlencoded",
    },
  });

  const data = (await res.json()) as TurnstileServerValidationResponse;

  return new Response(JSON.stringify(data), {
    status: data.success ? 200 : 400,
    headers: {
      "content-type": "application/json",
    },
  });
}

Check out Cloudflare official docs for more info about server side validation.