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.

/app/page/login.{jsx,tsx}
'use client'
import { Turnstile } from '@marsidev/react-turnstile'

export default function LoginForm() {
  const formRef = React.useRef()

  async function handleSubmit(event) {
    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>
  )
}
/app/api/verify/route.{js,ts}
const verifyEndpoint = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'
const secret = '1x0000000000000000000000000000000AA'

export async function POST(request) {
  const { token } = await request.json()

  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()

  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.