After some digging in, I have some possible answers. The fix was to adjust the action hook to wpforms_process
.
- Reusing of Turnstile tokens is not allowed. On a normal submission cycle the form isn’t submitted until all client-side validation passes. This means that the siteverify API isn’t called until most field validation passes.
- Our testing process triggered an extra level of email validation which occurs on the server-side. During that submission, the Turnstile token is submitted and verified. However the form itself has not been completed when email validation fails.
- If the error with the email address is corrected, the subsequent submissions reuse the Turnstile token when calling siteverify which will fail. This may resolve itself after 5 minutes when the token expires IF the widget is configured to refresh itself.
By changing the action hook where Turnstile validates, all other validation has passed before siteverify is called. This is not an ideal fix because other plugins may run during this later hook (as recommended by the developers in the code!) and fail submission, creating the same scenario.
The optimal solution would refresh the Turnstile token has been used to call the siteverify API and if the form fails server-side submission for any reason.