Add useCsrfToken hook and update README

A new `useCsrfToken` hook has been added for fetching CSRF token from the meta tag. The shared package's exports have been updated to include this new hook. Additionally, extensive documentation on writing server actions and API route handlers, as well as the usage of Captcha token protection and CSRF token, has been added to the README file.
This commit is contained in:
giancarlo
2024-04-22 11:56:42 +08:00
parent e2503333e2
commit 61b1edcdd9
4 changed files with 253 additions and 1 deletions

237
README.md
View File

@@ -285,6 +285,241 @@ npx shadcn-ui@latest add button --path=packages/src/ui/shadcn
We pass the `--path` flag to specify the path where the component should be installed. You may need to adjust the path based on your project structure.
**NB**: you may need to update the imports to the `cn` utility function to use the relative imports because it somehow breaks. Please do that.
## Writing Server Actions
In the large majority of cases - you will be writing React Server Actions to update data in your DB.
Makerkit ships with a utility to help you write these actions. The utility is called `enhanceAction` and we import it from `@kit/next/actions`.
```tsx
import { enhanceAction } from '@kit/next/actions';
```
This utility helps us with three main things:
1. checks the user state (if the user is authenticated)
2. given a Zod schema, it validates the request body
3. given a captcha site key, it validates the captcha token
Fantastic, let's see how we can use it.
```tsx
'use server';
import { z } from 'zod';
import { enhanceAction } from '@kit/next/actions';
const ZodSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
});
export const myServerAction = enhanceAction(
async function (data, user) {
// 1. "data" has been validated against the Zod schema, and it's safe to use
// 2. "user" is the authenticated user
// ... your code here
return {
success: true,
};
},
{
schema: ZodSchema,
},
);
```
### Using a Captcha token protection
If you want to protect your server actions with a captcha token, you can do so by passing the captcha site token to the `enhanceAction` function and setting the `captcha` flag to `true`.
```tsx
'use server';
import { enhanceAction } from '@kit/next/actions';
export const myServerAction = enhanceAction(
async function (data, user) {
// ... your code here
return {
success: true,
};
},
{
captcha: true,
schema: ZodSchema,
},
);
```
When calling the server action, we must supply the captcha token in the request body.
The captcha token can be retrieved from the `useCaptchaToken` hook in the package `@kit/auth/captcha/client`.
```tsx
import { useCaptchaToken } from '@kit/auth/captcha/client';
function Component() {
const captchaToken = useCaptchaToken();
// ... your code here
}
```
Now, when calling the server action, we can pass the captcha
```tsx
import { useCaptchaToken } from '@kit/auth/captcha/client';
function Component() {
const captchaToken = useCaptchaToken();
const onSubmit = async (params: {
email: string;
password: string;
}) => {
const response = await myServerAction({
...params,
captchaToken,
});
// ... your code here
};
}
```
NB: to use Captcha protection, you need to set the captcha token in the environment variables.
```bash
CAPTCHA_SECRET_TOKEN=
```
As a secret environment variable, please do not add it to the `.env` file. Instead, add it to the environment variables of your CI/CD system.
The only captcha provider supported is Cloudflare Turnstile.
## Writing API Route Handlers
You won't be writing too many API route handlers - but when you do, you can use the `enhanceRouteHandler` utility to help you with the following:
1. checks the user state (if the user is authenticated)
2. given a Zod schema, it validates the request body
3. given a captcha site key, it validates the captcha token
Fantastic, let's see how we can use it.
```tsx
'use server';
import { z } from 'zod';
import { enhanceRouteHandler } from '@kit/next/routes';
import { NextResponse } from 'next/server';
const ZodSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
});
export const POST = enhanceRouteHandler(
async function({ body, user, request }) {
// 1. "body" has been validated against the Zod schema, and it's safe to use
// 2. "user" is the authenticated user
// 3. "request" is the request object that contains the headers, query, etc.
// ... your code here
return NextResponse.json({
success: true,
});
},
{
schema: ZodSchema,
},
);
```
### Using a Captcha token protection
If you want to protect your API route handlers with a captcha token, you can do so by passing the captcha site token to the `enhanceRouteHandler` function and setting the `captcha` flag to `true`.
```tsx
'use server';
import { enhanceRouteHandler } from '@kit/next/routes';
export const POST = enhanceRouteHandler(
async function({ body, user, request }) {
// ... your code here
return NextResponse.json({
success: true,
});
},
{
captcha: true,
schema: ZodSchema,
},
);
```
When calling the API route handler, we must supply the captcha token in the request body.
The captcha token can be retrieved from the `useCaptchaToken` hook in the package `@kit/auth/captcha/client`.
```tsx
import { useCaptchaToken } from '@kit/auth/captcha/client';
function Component() {
const captchaToken = useCaptchaToken();
// ... your code here
}
```
Now, when calling the API route handler, we can pass the captcha and the CSRF token.
NB: The CSRF token **must be added for all API routes** making mutations in routes that are outside `/api/*`. Routes inside `/api/*` are not protected by default as they're meant to be used externally.
```tsx
import { useCaptchaToken } from '@kit/auth/captcha/client';
import { useCsrfToken } from '@kit/shared/hooks';
function Component() {
const captchaToken = useCaptchaToken();
const csrfToken = useCsrfToken();
const onSubmit = async (params: {
email: string;
password: string;
}) => {
const response = await fetch('/api/my-api-route', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-csrf-token': csrfToken,
},
body: JSON.stringify({
...params,
captchaToken,
}),
});
// ... your code here
};
}
```
NB: to use Captcha protection, you need to set the captcha token in the environment variables.
```bash
CAPTCHA_SECRET_TOKEN=
```
As a secret environment variable, please do not add it to the `.env` file. Instead, add it to the environment variables of your CI/CD system.
The only captcha provider supported is Cloudflare Turnstile.
## Environment Variables
The majority of the environment variables are defined in the `apps/web/.env` file. These are the env variables
@@ -420,6 +655,8 @@ As the endpoint, remember to use the `/api/db/webhook` endpoint. If your APP url
#### Adding Database Webhooks from Supabase Studio
The below is only needed when going to production. The local development seed.sql script will add the webhooks for you.
While you can create a migration to add the database webhooks, you can also add them from the Supabase Studio.
1. Go to the Supabase Studio

View File

@@ -11,7 +11,8 @@
"prettier": "@kit/prettier-config",
"exports": {
"./logger": "./src/logger/index.ts",
"./utils": "./src/utils.ts"
"./utils": "./src/utils.ts",
"./hooks": "./src/hooks/index.ts"
},
"dependencies": {
"@tanstack/react-table": "^8.16.0",

View File

@@ -0,0 +1 @@
export * from './use-csrf-token';

View File

@@ -0,0 +1,13 @@
/**
* Get the CSRF token from the meta tag.
* @returns The CSRF token.
*/
export function useCsrfToken() {
const meta = document.querySelector('meta[name="csrf-token"]');
if (!meta) {
return '';
}
return meta.getAttribute('content') ?? '';
}