DEV Community

Ibrohim Abdivokhidov
Ibrohim Abdivokhidov

Posted on

Cloudflare Turnstile NextJS: Invalid Token Error on Repeated Submissions

Was used in notlink — a blazingly fast url shortener ever built with rust programming language. Check: https://notl.ink

The “Invalid token” error occurs because the Turnstile token is being reused for multiple submissions. Cloudflare Turnstile tokens are single-use; once validated, they can’t be used again. Here’s how to fix it:

  1. Reset the Turnstile widget after each submission

Update your frontend code to reset the Turnstile widget and clear the token state after submission:

// Add a ref to the Turnstile component
const turnstileRef = useRef();

async function handleShorten(val: string) {
// ... existing code ...

try {
const response = await fetch(/api/shorten, { /* ... */ });
const data: ShortURLResponse = await response.json();

// Reset Turnstile after successful submission
turnstileRef.current?.reset();
setTurnstileToken("");
setTurnstileStatus("required");
Enter fullscreen mode Exit fullscreen mode

} catch (error) {
console.error('Error:', error);
} finally {
setLoading(false);
// Ensure Turnstile is reset even if there's an error
turnstileRef.current?.reset();
setTurnstileToken("");
setTurnstileStatus("required");
}
}

// Update your Turnstile component with the ref
ref={turnstileRef}
siteKey={process.env.TURNSTILE_SITE_KEY!}
// ... other props ...
/>

  1. (Optional) Clear token state on expiration/error

Enhance your Turnstile event handlers:

// ... other props ...
onExpire={() => {
setTurnstileStatus("expired");
setTurnstileError("Security check expired. Please verify again.");
setTurnstileToken(""); // Clear expired token
}}
onError={() => {
setTurnstileStatus("error");
setTurnstileError("Security check failed. Please try again.");
setTurnstileToken(""); // Clear invalid token
}}
/>
Why this works:

Each submission now requires a fresh Turnstile verification
The token state is cleared after submission/errors/expiration
The Turnstile widget is reset to force a new challenge
Additional recommendations for your backend:

Ensure your idempotencyKey implementation matches Turnstile's requirements
Consider adding rate limiting to prevent abuse
Verify the token expiration time (typically 5 minutes)
By implementing these changes, users will need to complete a new Turnstile verification for each submission, preventing token reuse and the “Invalid token” error.

Top comments (0)