DEV3 Technologies home

DEV3 Developer Forum

How should I validate and authorise input in a Next.js server action?

Next.js helpSolved0 views
dev3 ·

My server action takes an id and deletes a record. Someone told me anyone can call it with any id. How do I properly protect and validate server actions?

#nextjs#server-actions#security

0

1 reply

dev3 · Accepted answer

A server action compiles to a public POST endpoint. Treat every argument as untrusted, like an API request body.

"use server";
import { z } from "zod";
import { auth } from "@/auth";
import { revalidatePath } from "next/cache";

const Input = z.object({ id: z.string().regex(/^[a-f0-9]{24}$/) });

export async function deletePost(raw: unknown) {
  // 1. authenticate
  const session = await auth();
  if (!session?.user) throw new Error("Unauthorized");

  // 2. validate
  const { id } = Input.parse(raw);

  // 3. authorise at the data level (ownership)
  const res = await db.post.deleteMany({ where: { id, authorId: session.user.id } });
  if (res.count === 0) throw new Error("Not found");

  revalidatePath("/posts");
}

Checklist

  1. Authenticate inside the action, not only in middleware or by hiding the button.
  2. Validate shape and types with zod or similar (FormData values are always strings or files).
  3. Authorise the specific resource: filter by owner or role in the query so an id from someone else matches nothing.
  4. Do not trust hidden fields (prices, roles, user ids). Recompute on the server.
  5. Rate limit sensitive actions (login, email sending).
  6. Return safe errors: expected failures as { error: "..." } values; do not leak stack traces or SQL details.
  7. Next.js encrypts closed-over variables and checks the Origin against Host, which helps against CSRF, but it does not replace the steps above. Configure serverActions.allowedOrigins if you run behind a proxy with a different host.
  8. Unused exported actions can be reachable; only export what you intend to call.

Pitfall: a "use server" file exports only async functions. Constants or schemas exported there cause errors, so keep schemas in a separate module.

0

Your reply

Every post is reviewed by DEV3 before it appears. Usually reviewed within 24 hours.

Markdown supported. Use ``` for code blocks. Images are not allowed.