Captcha verification failed

I keep getting "Captcha verification failed" after adding Cloudflare Turnstyle captcha using Nextjs:
import { Footer } from "@/components/internal/footer";
import RegisterForm from "@/components/internal/forms/register-form";
import Navigation from "@/components/internal/navigation";
import { Turnstile } from "@marsidev/react-turnstile";

export default function Login() {
return (
<div className="flex flex-col w-full h-full min-h-screen">

<Navigation />
<div className="flex flex-col gap-4 items-center justify-center flex-grow h-full w-full max-w-[90rem] mx-auto">
<RegisterForm />
<Turnstile siteKey={process.env.NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY as string} />

</div>
<Footer />
</div>
);
}
import { Footer } from "@/components/internal/footer";
import RegisterForm from "@/components/internal/forms/register-form";
import Navigation from "@/components/internal/navigation";
import { Turnstile } from "@marsidev/react-turnstile";

export default function Login() {
return (
<div className="flex flex-col w-full h-full min-h-screen">

<Navigation />
<div className="flex flex-col gap-4 items-center justify-center flex-grow h-full w-full max-w-[90rem] mx-auto">
<RegisterForm />
<Turnstile siteKey={process.env.NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY as string} />

</div>
<Footer />
</div>
);
}
1 Reply
Alex
AlexOP5d ago
In RegisterForm:
const onSubmit = async (data: RegisterFormValues) => {
setError("");
setIsLoading(true);

try {
// TODO: Implement register
await authClient.signUp.email({
email: data.email as string,
password: data.password as string,
name: data.email as string,
callbackURL: "/app",
fetchOptions: {
headers: {
"x-captcha-response": process.env.NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY as string
},
onError: (ctx) => {
if (ctx.error.status === 422) {
setError("Something went wrong.");
} else {
console.log(ctx);
setError(ctx.error.message);
}
},
}
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (err) {
setError("Something went wrong. Please try again.");
} finally {
setIsLoading(false);
}
};
const onSubmit = async (data: RegisterFormValues) => {
setError("");
setIsLoading(true);

try {
// TODO: Implement register
await authClient.signUp.email({
email: data.email as string,
password: data.password as string,
name: data.email as string,
callbackURL: "/app",
fetchOptions: {
headers: {
"x-captcha-response": process.env.NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY as string
},
onError: (ctx) => {
if (ctx.error.status === 422) {
setError("Something went wrong.");
} else {
console.log(ctx);
setError(ctx.error.message);
}
},
}
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (err) {
setError("Something went wrong. Please try again.");
} finally {
setIsLoading(false);
}
};
In lib/auth.ts:
import { PrismaClient } from "@/lib/generated/prisma";
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { captcha } from "better-auth/plugins";

const prisma = new PrismaClient();

export const auth = betterAuth({
database: prismaAdapter(prisma, {
provider: "postgresql",
}),
trustedOrigins: ["http://localhost"],
emailAndPassword: {
requireEmailVerification: true,
enabled: true,
minPasswordLength: 8,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
sendResetPassword: async ({ user, url, token }, request) => {
// todo
},
},
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET! as string,
},
},
plugins: [
captcha({
provider: "cloudflare-turnstile",
secretKey: process.env.CLOUDFLARE_TURNSTILE_SECRET_KEY! as string,
endpoints: ["/sign-up/email", "/forget-password"],
}),
],
});
import { PrismaClient } from "@/lib/generated/prisma";
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { captcha } from "better-auth/plugins";

const prisma = new PrismaClient();

export const auth = betterAuth({
database: prismaAdapter(prisma, {
provider: "postgresql",
}),
trustedOrigins: ["http://localhost"],
emailAndPassword: {
requireEmailVerification: true,
enabled: true,
minPasswordLength: 8,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
sendResetPassword: async ({ user, url, token }, request) => {
// todo
},
},
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET! as string,
},
},
plugins: [
captcha({
provider: "cloudflare-turnstile",
secretKey: process.env.CLOUDFLARE_TURNSTILE_SECRET_KEY! as string,
endpoints: ["/sign-up/email", "/forget-password"],
}),
],
});
lib/auth-client.ts:
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({
/** The base URL of the server (optional if you're using the same domain) */
baseURL: "http://localhost:3000",
});
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({
/** The base URL of the server (optional if you're using the same domain) */
baseURL: "http://localhost:3000",
});
Envs are defined like so in both .env.local and regular .env file : CLOUDFLARE_TURNSTILE_SECRET_KEY=..... NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY=...... It is basically throwing a 403: POST /api/auth/sign-up/email 403 in 145ms

Did you find this page helpful?