Version 3 of the kit: - Radix UI replaced with Base UI (using the Shadcn UI patterns) - next-intl replaces react-i18next - enhanceAction deprecated; usage moved to next-safe-action - main layout now wrapped with [locale] path segment - Teams only mode - Layout updates - Zod v4 - Next.js 16.2 - Typescript 6 - All other dependencies updated - Removed deprecated Edge CSRF - Dynamic Github Action runner
209 lines
5.9 KiB
Plaintext
209 lines
5.9 KiB
Plaintext
---
|
|
status: "published"
|
|
description: "Learn how to set up captcha protection for your API routes."
|
|
title: "Captcha Protection for your API Routes"
|
|
label: "Captcha Protection"
|
|
order: 7
|
|
---
|
|
|
|
For captcha protection, we use [Cloudflare Turnstile](https://developers.cloudflare.com/turnstile).
|
|
|
|
{% sequence title="How to set up captcha protection for your API routes" description="Learn how to set up captcha protection for your API routes" %}
|
|
|
|
[Setting up the environment variables](#setting-up-the-environment-variables)
|
|
|
|
[Enabling the captcha protection](#enabling-the-captcha-protection)
|
|
|
|
[Using captcha in your components](#using-captcha-in-your-components)
|
|
|
|
[Verifying the token](#verifying-the-token)
|
|
|
|
{% /sequence %}
|
|
|
|
## Setting up the environment variables
|
|
|
|
To enable it, you need to set the following environment variables:
|
|
|
|
```bash
|
|
CAPTCHA_SECRET_TOKEN=
|
|
NEXT_PUBLIC_CAPTCHA_SITE_KEY=
|
|
```
|
|
|
|
You can find the `CAPTCHA_SECRET_TOKEN` in the Turnstile configuration. The `NEXT_PUBLIC_CAPTCHA_SITE_KEY` is public and safe to share. Instead, the `CAPTCHA_SECRET_TOKEN` should be kept secret.
|
|
|
|
This guide assumes you have correctly set up your Turnstile configuration. If you haven't, please refer to the https://developers.cloudflare.com/turnstile.
|
|
|
|
## Enabling the captcha protection
|
|
|
|
When you set the token in the environment variables, the kit will automatically protect your API routes with captcha.
|
|
|
|
**Important:** You also need to set the token in the Supabase Dashboard!
|
|
|
|
## Using Captcha in Your Components
|
|
|
|
The kit provides two clean APIs for captcha integration depending on your use case.
|
|
|
|
### Option 1: Using the useCaptcha Hook
|
|
|
|
For auth containers and simple forms, use the useCaptcha hook for zero-boilerplate captcha integration:
|
|
|
|
```tsx
|
|
import { useCaptcha } from '@kit/auth/captcha/client';
|
|
|
|
function MyComponent({ captchaSiteKey }) {
|
|
const captcha = useCaptcha({ siteKey: captchaSiteKey });
|
|
|
|
const handleSubmit = async (data) => {
|
|
try {
|
|
await myServerAction({
|
|
...data,
|
|
captchaToken: captcha.token,
|
|
});
|
|
} finally {
|
|
// Always reset after submission
|
|
captcha.reset();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<form onSubmit={handleSubmit}>
|
|
{captcha.field}
|
|
<button type="submit">Submit</button>
|
|
</form>
|
|
);
|
|
}
|
|
```
|
|
|
|
The useCaptcha hook returns:
|
|
- `token` - The current captcha token
|
|
- `reset()` - Function to reset the captcha widget
|
|
- `field` - The captcha component to render
|
|
|
|
### Option 2: React Hook Form Integration
|
|
|
|
For forms using react-hook-form, use the CaptchaField component with automatic form integration:
|
|
|
|
```tsx
|
|
import { useForm } from 'react-hook-form';
|
|
import { CaptchaField } from '@kit/auth/captcha/client';
|
|
|
|
function MyForm() {
|
|
const form = useForm({
|
|
defaultValues: {
|
|
message: '',
|
|
captchaToken: '',
|
|
},
|
|
});
|
|
|
|
const handleSubmit = async (data) => {
|
|
try {
|
|
await myServerAction(data);
|
|
form.reset(); // Automatically resets captcha too
|
|
} catch (error) {
|
|
// Handle error
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Form {...form}>
|
|
<form onSubmit={form.handleSubmit(handleSubmit)}>
|
|
{/* Your form fields */}
|
|
|
|
<CaptchaField
|
|
siteKey={config.captchaSiteKey}
|
|
control={form.control}
|
|
name="captchaToken"
|
|
/>
|
|
|
|
<button type="submit">Submit</button>
|
|
</form>
|
|
</Form>
|
|
);
|
|
}
|
|
```
|
|
|
|
When using React Hook Form integration:
|
|
- The captcha token is automatically set in the form state
|
|
- Calling form.reset() automatically resets the captcha
|
|
- No manual state management needed
|
|
|
|
## Using with Server Actions
|
|
|
|
Define your server action schema to include the captchaToken:
|
|
|
|
```tsx
|
|
import * as z from 'zod';
|
|
import { captchaActionClient } from '@kit/next/safe-action';
|
|
|
|
const MySchema = z.object({
|
|
message: z.string(),
|
|
captchaToken: z.string(),
|
|
});
|
|
|
|
export const myServerAction = captchaActionClient
|
|
.inputSchema(MySchema)
|
|
.action(async ({ parsedInput: data, ctx: { user } }) => {
|
|
// Your action code - captcha is automatically verified
|
|
console.log(data.message);
|
|
});
|
|
```
|
|
|
|
The `captchaActionClient` automatically:
|
|
|
|
1. Extracts the `captchaToken` from the data
|
|
2. Verifies it with Cloudflare Turnstile
|
|
3. Throws an error if verification fails
|
|
|
|
### Important Notes
|
|
|
|
- **Token Validity**: A captcha token is valid for one request only
|
|
- **Always Reset:** Always call captcha.reset() (or form.reset() with RHF) after submission, whether successful or not
|
|
- **Automatic Renewal**: The library automatically renews tokens when needed, but you must reset after consumption
|
|
|
|
## Verifying the Token Manually
|
|
|
|
If you need to verify the captcha token manually server-side (e.g., in API routes), use:
|
|
|
|
```tsx
|
|
import { verifyCaptchaToken } from '@kit/auth/captcha/server';
|
|
|
|
async function myApiHandler(request: Request) {
|
|
const token = request.headers.get('x-captcha-token');
|
|
|
|
// Throws an error if invalid
|
|
await verifyCaptchaToken(token);
|
|
|
|
// Your API logic
|
|
}
|
|
```
|
|
|
|
Note: If you use `captchaActionClient` or `enhanceRouteHandler` with captcha: true, verification is automatic and you don't need to call verifyCaptchaToken manually.
|
|
|
|
## Upgrading from v2
|
|
|
|
{% callout title="Differences with v2" %}
|
|
In v2, captcha-protected actions used `enhanceAction` with `{ captcha: true }`. In v3, use `captchaActionClient` from `@kit/next/safe-action` which handles captcha verification automatically. Zod imports also changed from `import { z } from 'zod'` to `import * as z from 'zod'`.
|
|
|
|
For the full migration guide, see [Upgrading from v2 to v3](/docs/next-supabase-turbo/installation/v3-migration).
|
|
{% /callout %}
|
|
|
|
## Migration from old API (prior to v2.18.3)
|
|
|
|
If you're migrating from the old `useCaptchaToken` hook:
|
|
|
|
Before:
|
|
|
|
```tsx
|
|
import { useCaptchaToken } from '@kit/auth/captcha/client';
|
|
|
|
const { captchaToken, resetCaptchaToken } = useCaptchaToken();
|
|
// Manual state management required
|
|
```
|
|
|
|
After:
|
|
|
|
```tsx
|
|
import { useCaptcha } from '@kit/auth/captcha/client';
|
|
|
|
const captcha = useCaptcha({ siteKey: captchaSiteKey });
|
|
``` |