Next.js Supabase V3 (#463)
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
This commit is contained in:
committed by
GitHub
parent
4912e402a3
commit
7ebff31475
168
docs/security/data-validation.mdoc
Normal file
168
docs/security/data-validation.mdoc
Normal file
@@ -0,0 +1,168 @@
|
||||
---
|
||||
label: "Data Validation"
|
||||
title: "Data Validation in the Next.js Supabase Turbo kit"
|
||||
description: "Learn how to validate data in the Next.js Supabase Turbo kit."
|
||||
order: 3
|
||||
---
|
||||
|
||||
Data Validation is a crucial aspect of building secure applications. In this section, we will look at how to validate data in the Next.js Supabase Turbo kit.
|
||||
|
||||
{% sequence title="Steps to validate data" description="Learn how to validate data in the Next.js Supabase Turbo kit." %}
|
||||
|
||||
[What are we validating?](#what-are-we-validating)
|
||||
|
||||
[Using Zod to validate data](#using-zod-to-validate-data)
|
||||
|
||||
[Validating payload data to Server Side API](#validating-payload-data-to-server-side-api)
|
||||
|
||||
[Validating Cookies](#validating-cookies)
|
||||
|
||||
[Validating URL parameters](#validating-url-parameters)
|
||||
|
||||
{% /sequence %}
|
||||
|
||||
## What are we validating?
|
||||
|
||||
A general rule, is that all client-side provided data should be validated/sanitized. This includes:
|
||||
|
||||
- URL parameters
|
||||
- Search params
|
||||
- Form data
|
||||
- Cookies
|
||||
- Any data provided by the user
|
||||
|
||||
## Using Zod to validate data
|
||||
|
||||
The Next.js Supabase Turbo kit uses [Zod](https://zod.dev/) to validate data. You can use the `z` object to validate data in your application.
|
||||
|
||||
```ts
|
||||
import * as z from "zod";
|
||||
|
||||
const userSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
email: z.string().email(),
|
||||
});
|
||||
|
||||
// Validate the data
|
||||
const validatedData = userSchema.parse(data);
|
||||
```
|
||||
|
||||
## Validating payload data to Server Side API
|
||||
|
||||
We generally use two ways for sending data from a client to a server:
|
||||
|
||||
1. Server Actions
|
||||
2. API Route Handlers
|
||||
|
||||
Let's look at how we can validate data for both of these cases.
|
||||
|
||||
### Server Actions: Using authActionClient
|
||||
|
||||
The `authActionClient` creates type-safe server actions with built-in Zod validation and authentication.
|
||||
|
||||
```ts
|
||||
'use server';
|
||||
|
||||
import { authActionClient } from "@kit/next/safe-action";
|
||||
import * as z from "zod";
|
||||
|
||||
const UserSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
email: z.string().email(),
|
||||
});
|
||||
|
||||
export const createUserAction = authActionClient
|
||||
.inputSchema(UserSchema)
|
||||
.action(async ({ parsedInput, ctx: { user } }) => {
|
||||
// parsedInput is now validated against the UserSchema
|
||||
|
||||
// do something with the validated data
|
||||
});
|
||||
```
|
||||
|
||||
When you define an action using `authActionClient`, the `parsedInput` is validated against the `schema` automatically. The `ctx.user` provides the authenticated user.
|
||||
|
||||
### API Route Handlers: Using the "enhanceRouteHandler" utility
|
||||
|
||||
The `enhanceRouteHandler` hook is a utility hook that enhances Next.js API Route Handlers with Zod validation.
|
||||
|
||||
```ts
|
||||
import { enhanceRouteHandler } from "@kit/next/routes";
|
||||
import * as z from "zod";
|
||||
|
||||
const UserSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
email: z.string().email(),
|
||||
});
|
||||
|
||||
export const POST = enhanceRouteHandler(async ({ body, user, request }) => {
|
||||
// body is now validated against the UserSchema
|
||||
// user is the authenticated user
|
||||
// request is the incoming request
|
||||
|
||||
// do something with the validated data
|
||||
}, {
|
||||
schema: UserSchema,
|
||||
auth: true,
|
||||
});
|
||||
```
|
||||
|
||||
Very similar to `authActionClient`, the `enhanceRouteHandler` utility enhances the handler function with Zod validation and authentication.
|
||||
|
||||
When you define an API route using `enhanceRouteHandler`, the `body` argument is validated against the `schema` option automatically. The `user` argument provides the authenticated user, and `request` is the incoming request object.
|
||||
|
||||
## Validating Cookies
|
||||
|
||||
Whenever you use a cookie in your application, you should validate the cookie data.
|
||||
|
||||
Let's assume you receive a cookie with the name `my-cookie`, and you expect it to be a number. You can validate the cookie data as follows:
|
||||
|
||||
```ts
|
||||
import * as z from "zod";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
const cookieStore = await cookies();
|
||||
|
||||
const cookie = z.coerce.number()
|
||||
.safeParse(cookieStore.get("my-cookie")?.value);
|
||||
|
||||
if (!cookie.success) {
|
||||
// handle the error or provide a default value
|
||||
}
|
||||
```
|
||||
|
||||
## Validating URL parameters
|
||||
|
||||
Whenever you receive a URL parameter, you should validate the parameter data. Let's assume you receive a URL parameter with the name `my-param`, and you expect it to be a number. You can validate the parameter data as follows:
|
||||
|
||||
```ts
|
||||
interface PageProps {
|
||||
searchParams: Promise<{ myParam: string }>;
|
||||
}
|
||||
|
||||
async function Page({ searchParams }: PageProps) {
|
||||
const params = await searchParams;
|
||||
|
||||
const param = z.coerce.number()
|
||||
.safeParse(params.myParam);
|
||||
|
||||
if (!param.success) {
|
||||
// handle the error or provide a default value
|
||||
}
|
||||
|
||||
// render the page with the validated data
|
||||
}
|
||||
```
|
||||
|
||||
Going forward, remember to validate all data that you receive from the client, and never trust anything the client provides you with. Always have a default value ready to handle invalid data, which can prevent potential security issues or bugs in your application.
|
||||
|
||||
## Upgrading from v2
|
||||
|
||||
{% callout title="Differences with v2" %}
|
||||
In v2, server actions used `enhanceAction` from `@kit/next/actions` and Zod was imported as `import { z } from 'zod'`. In v3, server actions use `authActionClient` from `@kit/next/safe-action` and Zod is imported as `import * as z from 'zod'`.
|
||||
|
||||
For the full migration guide, see [Upgrading from v2 to v3](/docs/next-supabase-turbo/installation/v3-migration).
|
||||
{% /callout %}
|
||||
Reference in New Issue
Block a user