# Data Validation in the Next.js Drizzle kit

> Learn how to validate data in the Next.js Drizzle kit.

*Canonical: https://makerkit.dev/docs/nextjs-drizzle/security/data-validation*

---

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 Drizzle kit.

{% sequence title="Steps to validate data" description="Learn how to validate data in the Next.js Drizzle 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 Drizzle kit uses [Zod](https://zod.dev/) to validate data. You can use the `z` object to validate data in your application.

```ts
import { 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 Server Actions for sending data from a client to a server. The Next.js Drizzle kit uses `next-safe-action` with pre-configured action clients for validation and authentication.

### Server Actions: Using the action clients

The `authenticatedActionClient` is a pre-configured action client that validates input using Zod schemas and ensures the user is authenticated.

```ts
'use server';

import { authenticatedActionClient } from "@kit/action-middleware";
import { z } from "zod";

const UserSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.string().email(),
});

export const createUserAction = authenticatedActionClient
  .inputSchema(UserSchema)
  .action(async ({ parsedInput, ctx }) => {
    // parsedInput is now validated against the UserSchema
    // ctx.user is the authenticated user

    // do something with the validated data
  });
```

When you define an action using `authenticatedActionClient` with `inputSchema`, the `parsedInput` argument is now validated against the schema automatically, without you having to do anything else. In addition, the `ctx.user` and `ctx.session` are available to you, which contain the authenticated user and session data.

### Organization-scoped actions

For actions that require organization context, use `organizationActionClient`:

```ts
'use server';

import { organizationActionClient } from "@kit/action-middleware";
import { z } from "zod";

const UpdateDocumentSchema = z.object({
  documentId: z.string().uuid(),
  content: z.string(),
});

export const updateDocumentAction = organizationActionClient
  .inputSchema(UpdateDocumentSchema)
  .action(async ({ parsedInput, ctx }) => {
    // parsedInput is validated
    // ctx.user is the authenticated user
    // ctx.organizationId is the current organization
    // ctx.role is the user's role in the organization

    // do something with the validated data
  });
```

### Actions without input

For actions that don't require input validation:

```ts
'use server';

import { authenticatedActionClient } from "@kit/action-middleware";

export const getCurrentUserAction = authenticatedActionClient
  .action(async ({ ctx }) => {
    // No input needed, just return user data
    return ctx.user;
  });
```

### Role-protected actions

For actions that require a minimum role level:

```ts
'use server';

import { authenticatedActionClient, withMinRole } from "@kit/action-middleware";
import { z } from "zod";

const DeleteMemberSchema = z.object({
  memberId: z.string().uuid(),
});

export const deleteMemberAction = authenticatedActionClient
  .use(withMinRole('admin'))
  .inputSchema(DeleteMemberSchema)
  .action(async ({ parsedInput, ctx }) => {
    // Only admins and owners can reach this point
    // parsedInput is validated
  });
```

### Permission-protected actions

For actions that require specific permissions:

```ts
'use server';

import { authenticatedActionClient, withFeaturePermission } from "@kit/action-middleware";
import { z } from "zod";

const UpdateBillingSchema = z.object({
  planId: z.string(),
});

export const updateBillingAction = authenticatedActionClient
  .use(withFeaturePermission({ billing: ['update'] }))
  .inputSchema(UpdateBillingSchema)
  .action(async ({ parsedInput, ctx }) => {
    // Only users with billing:update permission can reach this point
  });
```

## 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 { 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.
