Skip to content

Bot Protection

bot protection CAPTCHA Turnstile Cloudflare spam prevention security automated attacks

To safeguard your Auth API against automated attacks from scripts and bots, you can implement Cloudflare’s Turnstile. Turnstile offers CAPTCHA-like protection without user friction, as it doesn’t require solving puzzles.

Turnstile Check in Action

  1. Selective Protection: Auth integrates Turnstile specifically for: a. Signup requests b. Password reset requests c. Passwordless signin requests (OTP, SMS and magic links)
  2. API Accessibility: Other API endpoints remain accessible for legitimate programmatic use.
  3. Bot Deterrence: Manual verification during signup discourages unwanted bot activity.

This approach balances security with usability, ensuring robust protection where it matters most.

Sign up on Cloudflare if you haven’t already.

Go to your account -> Turnstile -> Add Widget. Then:

  • Set a descriptive name
  • In the domain, enter your frontend’s domain
  • Set widget mode as “managed”

Then click on “create” and write down the site key and the secret key.

Start by adding the following configuration to your Nhost project:

[auth.signUp.turnstile]
secretKey = 'turnstileSecretKey'

Replace turnstileSecretKey with the secret key from the first step.

Integrate turnstile into your sign up form

Section titled “Integrate turnstile into your sign up form”

To integrate turnstile into your sign up form you can refer to Cloudfare’s documentation. Just keep in mind a few things:

  • You don’t need to do any verification of the response, just pass it to the Auth service on the /signup/... request in the header x-cf-turnstile-response.
  • The “server side verification” is done by the auth service and will return a forbidden status error if the header is not present or if the check didn’t pass.
  • You will need to use the site key from step 1 to configure turnstile in your form

Pass turnstile’s response to the signup request

Section titled “Pass turnstile’s response to the signup request”

To pass the response as a header change your request to include the header. For instance:

await signUpEmailPassword(
email,
password,
{
displayName,
},
{
headers: {
'x-cf-turnstile-response': turnstileResponse,
},
},
);