How to fix captcha_failed: Captcha verification process failed in Supabase

SupabaseINTERMEDIATEHIGHUpdated Dec 29, 2025· 248 views

The CAPTCHA verification failed during Supabase authentication, typically because the CAPTCHA token was not passed correctly to the auth request or the token has expired. Ensure your frontend is passing the captchaToken in the options parameter and that your Supabase CAPTCHA provider keys are correctly configured.

Quick fix

Fixes captcha_failed: Captcha verification process failed

import { createClient } from '@supabase/supabase-js';

const supabase = createClient(url, key);

// In your sign-up handler
const { data, error } = await supabase.auth.signUp({
  email: userEmail,
  password: userPassword,
  options: {
    captchaToken: captchaToken // ← Make sure this is included
  }
});

// Or for sign-in
const { data, error } = await supabase.auth.signInWithPassword({
  email: userEmail,
  password: userPassword,
  options: {
    captchaToken: captchaToken // ← Must be passed here too
  }
});
  1. Verify CAPTCHA is configured in Supabase Dashboard
  2. Pass the CAPTCHA token to your sign-up or sign-in function
  3. Get the CAPTCHA token from your widget
  4. Check for variable scoping issues
supabase — error
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(url, key);
// In your sign-up handler
const { data, error } = await supabase.auth.signUp({
email: userEmail,
password: userPassword,
options: {
captchaToken: captchaToken // ← Make sure this is included
}
});
// Or for sign-in
const { data, error } = await supabase.auth.signInWithPassword({
email: userEmail,
password: userPassword,
options: {
captchaToken: captchaToken // ← Must be passed here too
}
});
captcha_failed: Captcha verification process failed

What this error means

When Supabase receives an authentication request with CAPTCHA protection enabled, it verifies the CAPTCHA token against your configured provider (hCaptcha or Cloudflare Turnstile). This error occurs when the verification fails, which usually means either the token is missing from the request, the token has already been used or expired, or the CAPTCHA provider's secret key in Supabase is incorrect. The Supabase auth service cannot verify that a human completed the CAPTCHA challenge, so it blocks the authentication request to prevent bot abuse.

Typical symptoms

  • Sign-up or sign-in requests fail with "captcha_failed" error message
  • Users can see the CAPTCHA widget but still get verification errors
  • OAuth login fails after CAPTCHA is enabled in Supabase Auth settings
  • Local testing works with dummy keys but fails in production
  • The same credentials work in one environment but fail in another
  • CAPTCHA errors occur intermittently, especially with rapid requests

Common causes

  1. CAPTCHA token is not being passed to the Supabase auth function (missing captchaToken in options)
  2. The captchaToken variable is undefined or in the wrong scope in your application code
  3. CAPTCHA token has expired (tokens typically expire after 5 minutes)
  4. The same CAPTCHA token is being reused for multiple authentication attempts
  5. Supabase CAPTCHA Secret key is incorrect or does not match the provider's key
  6. CAPTCHA provider (hCaptcha or Turnstile) site key and secret key mismatch
  7. OAuth login attempts do not include CAPTCHA verification in the auth flow
  8. Local testing using localhost without proper domain configuration (ngrok not set up)
  9. CAPTCHA widget was not reset after a previous use, preventing new token generation

How to fix "captcha_failed: Captcha verification process failed"

1Verify CAPTCHA is configured in Supabase Dashboard

Navigate to your Supabase project dashboard and confirm CAPTCHA protection is enabled:

1. Go to Authentication > Bot and Abuse Protection > Enable CAPTCHA protection
2. Select your CAPTCHA provider (hCaptcha or Cloudflare Turnstile)
3. Enter the Secret key from your provider (not the site key)
4. Click Save
5. Copy your Site Key from the provider settings and use it in your frontend

If you haven't signed up with a CAPTCHA provider yet:
- For hCaptcha: https://dashboard.hcaptcha.com
- For Cloudflare Turnstile: https://dash.cloudflare.com/?to=/:account/turnstile

Make sure the Secret key in Supabase exactly matches the key from your provider.

2Pass the CAPTCHA token to your sign-up or sign-in function

Update your authentication code to include the CAPTCHA token in the options parameter:

typescript
import { createClient } from '@supabase/supabase-js';

const supabase = createClient(url, key);

// In your sign-up handler
const { data, error } = await supabase.auth.signUp({
  email: userEmail,
  password: userPassword,
  options: {
    captchaToken: captchaToken // ← Make sure this is included
  }
});

// Or for sign-in
const { data, error } = await supabase.auth.signInWithPassword({
  email: userEmail,
  password: userPassword,
  options: {
    captchaToken: captchaToken // ← Must be passed here too
  }
});

For anonymous sign-ins:

typescript
const { data, error } = await supabase.auth.signInAnonymously({
  options: {
    captchaToken: captchaToken
  }
});

The captchaToken comes from your CAPTCHA widget's onVerify callback.

3Get the CAPTCHA token from your widget

Ensure your CAPTCHA widget is properly configured to capture the token. Below are examples for both providers:

hCaptcha example:

typescript
import HCaptcha from '@hcaptcha/react-hcaptcha';
import { useRef, useState } from 'react';

function SignUpForm() {
  const captchaRef = useRef(null);
  const [captchaToken, setCaptchaToken] = useState<string | null>(null);

  const handleCaptchaVerify = (token: string) => {
    setCaptchaToken(token);
  };

  const handleSignUp = async () => {
    if (!captchaToken) {
      alert('Please complete the CAPTCHA');
      return;
    }

    const { data, error } = await supabase.auth.signUp({
      email: email,
      password: password,
      options: {
        captchaToken: captchaToken
      }
    });
  };

  return (
    <>
      <HCaptcha
        ref={captchaRef}
        sitekey="your-site-key"
        onVerify={handleCaptchaVerify}
      />
      <button onClick={handleSignUp}>Sign Up</button>
    </>
  );
}

Cloudflare Turnstile example:

typescript
import { Turnstile } from '@captcha/react';
import { useState } from 'react';

function SignUpForm() {
  const [captchaToken, setCaptchaToken] = useState<string | null>(null);

  return (
    <>
      <Turnstile
        sitekey="your-turnstile-site-key"
        onVerify={(token: string) => setCaptchaToken(token)}
      />
      <button onClick={() => handleSignUp(captchaToken)}>Sign Up</button>
    </>
  );
}
4Check for variable scoping issues

A common bug is having two variables with the same name in different scopes. For example:

typescript
// ❌ WRONG: captchaToken declared in wrong scope
function SignUpForm() {
  let captchaToken; // Declared here

  function handleCaptchaVerify(token: string) {
    const captchaToken = token; // Redeclared in nested scope!
    // This only sets the local variable, not the outer one
  }

  function handleSubmit() {
    console.log(captchaToken); // Still undefined!
  }
}

// ✓ CORRECT: Use the same variable
function SignUpForm() {
  let captchaToken; // Declared once

  function handleCaptchaVerify(token: string) {
    captchaToken = token; // Assign to outer variable
  }

  function handleSubmit() {
    console.log(captchaToken); // Now has the token
  }
}

If using React hooks (recommended):

typescript
const [captchaToken, setCaptchaToken] = useState<string | null>(null);

const handleCaptchaVerify = (token: string) => {
  setCaptchaToken(token); // Updates state for all components
};
5Verify your provider secret key matches

Check that the Secret key you entered in Supabase exactly matches your CAPTCHA provider's key:

For hCaptcha:
1. Go to https://dashboard.hcaptcha.com
2. Click your site
3. Click Settings
4. Copy the Secret Key (not the Site Key)
5. Paste it into Supabase Auth settings
6. Click Save

For Cloudflare Turnstile:
1. Go to https://dash.cloudflare.com
2. Navigate to Turnstile > Your site
3. Copy the Secret Key
4. Paste it into Supabase Auth settings
5. Click Save

If you recently migrated from hCaptcha to Turnstile, ensure you've updated BOTH the site key in your frontend code AND the secret key in Supabase.

6Reset the CAPTCHA widget after verification

After a CAPTCHA token is used, reset the widget to allow the user to complete it again if needed. If the first attempt fails and they retry, they need a fresh token:

For hCaptcha:

typescript
const captchaRef = useRef(null);

const resetCaptcha = () => {
  captchaRef.current?.resetCaptcha();
};

const handleSignUp = async () => {
  try {
    const { error } = await supabase.auth.signUp({
      email, password,
      options: { captchaToken }
    });
    if (error) {
      resetCaptcha(); // Reset for retry
      setCaptchaToken(null);
    }
  } catch (err) {
    resetCaptcha();
  }
};

For Turnstile:
Turnstile typically resets automatically, but you can force it if needed by unmounting and remounting the component or using its API if provided by the library version you're using.

7Set up proper local testing with ngrok

CAPTCHA providers require valid domains for security. Localhost won't work in production keys. For local testing:

1. Install ngrok: Download from https://ngrok.com
2. Run your dev server: npm run dev (typically on localhost:3000)
3. Start ngrok tunnel:

bash
ngrok http 3000

4. Update your /etc/hosts file:

bash
sudo nano /etc/hosts
   # Add line:
   # 127.0.0.1 yourdomain.local

5. Add ngrok URL to CAPTCHA provider:
- In hCaptcha dashboard: Add your ngrok URL (e.g., https://xxxx-xxxx-xxxx.ngrok.io)
- In Cloudflare Turnstile: Add your ngrok URL to allowed domains
6. Update your code to use the tunnel URL during local testing

Alternatively, use your CAPTCHA provider's test/dummy keys for localhost development (check their documentation).

Advanced notes

Token expiration varies by provider: hCaptcha tokens typically expire after 5 minutes, while Cloudflare Turnstile tokens expire after 5 minutes by default. If users take too long to submit a form after completing CAPTCHA, the token becomes invalid. To handle this, consider regenerating the CAPTCHA challenge if the auth request fails. When migrating between CAPTCHA providers (e.g., hCaptcha to Turnstile), you may see errors like "captcha protection: request disallowed (timeout-or-duplicate)" if old tokens are still being sent. Always update both your frontend site key and Supabase secret key when switching providers. For OAuth flows, CAPTCHA verification happens on the server side during code exchange. Ensure your callback route calls exchangeCodeForSession() which should include CAPTCHA verification if enabled. Some frameworks like Next.js require extra configuration to properly pass the captchaToken through OAuth redirects. Check Supabase logs for detailed error messages—they provide much more information than the API response. If you see "no captcha response (captcha_token) found in request", it definitively means the token was not passed to Supabase.

Frequently asked questions

What does "captcha_failed: Captcha verification process failed" mean?
When Supabase receives an authentication request with CAPTCHA protection enabled, it verifies the CAPTCHA token against your configured provider (hCaptcha or Cloudflare Turnstile). This error occurs when the verification fails, which usually means either the token is missing from the request, the token has already been used or expired, or the CAPTCHA provider's secret key in Supabase is incorrect. The Supabase auth service cannot verify that a human completed the CAPTCHA challenge, so it blocks the authentication request to prevent bot abuse.
How do I fix "captcha_failed: Captcha verification process failed"?
The CAPTCHA verification failed during Supabase authentication, typically because the CAPTCHA token was not passed correctly to the auth request or the token has expired. Ensure your frontend is passing the captchaToken in the options parameter and that your Supabase CAPTCHA provider keys are correctly configured.
What causes "captcha_failed: Captcha verification process failed"?
CAPTCHA token is not being passed to the Supabase auth function (missing captchaToken in options) The captchaToken variable is undefined or in the wrong scope in your application code CAPTCHA token has expired (tokens typically expire after 5 minutes)
Is the "captcha_failed: Captcha verification process failed" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading