Next.js Curriculum
HardSecurity100% Free35 min read

Server Action Security: CSRF, Authorization & Validation

The 30-Second Interview Answer

Server Actions are publicly accessible HTTP POST endpoints and must be secured with the same defense-in-depth posture as public REST APIs. Next.js enforces built-in CSRF protection by validating the Origin and Host headers. However, developers must explicitly enforce user authentication, role-based authorization, and schema validation (e.g. Zod) inside every Server Action.

Learning Objectives

Understand how Next.js compares Origin and Host headers to mitigate CSRF attacks.

Enforce server-side authentication and role-based access control inside Server Actions.

Validate untrusted input data using schemas (Zod/Valibot) before business logic execution.

Prevent IDOR (Insecure Direct Object Reference) vulnerabilities.

Prerequisites & Background Knowledge
Cross-Site Request Forgery (CSRF)Role-Based Access Control (RBAC)Input validation with Zod

Why Interviewers Care

Top priority for senior and staff frontend engineering interviews. Security vulnerabilities in Server Actions are a common blindspot.

The Challenge

Why must Server Actions be treated as public HTTP endpoints? Implement a secure Server Action with authentication verification, role-based authorization, Zod schema validation, and IDOR protection.

Code Architecture & Implementation

1// app/actions/projects.ts
2'use server';
3
4import { z } from 'zod';
5import { getAuthenticatedSession } from '@/lib/auth';
6import { db } from '@/lib/db';
7import { projects } from '@/lib/schema';
8import { eq, and } from 'drizzle-orm';
9
10const DeleteProjectSchema = z.object({
11 projectId: z.string().uuid('Invalid project identifier'),
12});
13
14export async function deleteProjectAction(formData: FormData) {
15 // 1. AUTHENTICATION CHECK: Never trust client parameters for identity
16 const session = await getAuthenticatedSession();
17 if (!session || !session.userId) {
18 throw new Error('Authentication required');
19 }
20
21 // 2. INPUT VALIDATION: Ensure strict types and formats
22 const parsed = DeleteProjectSchema.safeParse({
23 projectId: formData.get('projectId'),
24 });
25 if (!parsed.success) {
26 return { error: 'Invalid input payload' };
27 }
28
29 const { projectId } = parsed.data;
30
31 // 3. AUTHORIZATION & IDOR PREVENTION:
32 // Ensure the user actually OWNS the project or has admin privileges!
33 const deleted = await db
34 .delete(projects)
35 .where(
36 and(
37 eq(projects.id, projectId),
38 eq(projects.ownerId, session.userId) // Prevents deleting other users' projects!
39 )
40 )
41 .returning();
42
43 if (deleted.length === 0) {
44 return { error: 'Project not found or unauthorized' };
45 }
46
47 return { success: true };
48}

Architectural Explanation

Because Server Actions look like regular TypeScript functions, developers often assume they are private. In reality, Next.js exposes them as HTTP endpoints. Next.js provides built-in CSRF mitigation: it verifies that the Origin header matches the Host header. However, CSRF protection does NOT authenticate the user. Developers must: 1) Verify the user session from cookies, 2) Validate inputs with Zod, 3) Verify authorization (RBAC), and 4) Ensure the user has permission to mutate that specific entity (preventing IDOR).

Common Mistakes & Anti-Patterns

Passing the user ID from the client: `action(userId, data)`, allowing attackers to pass another user's ID.

Relying solely on UI checks (e.g. hiding the delete button) without verifying permissions on the server.

Catching auth errors and returning generic 200 OK without preventing unauthorized writes.

Interview Follow-Up Traps

The interviewer asks: "Do I need CSRF tokens for Server Actions?" Explain that Next.js uses Origin and Host header verification (SameSite cookie policy + Origin comparison), eliminating the need for manual CSRF tokens for modern browsers, though allowedOrigins must be configured for complex reverse proxies.

Frequently Asked Questions

Can Server Actions be called by external third-party websites?

By default, no. Next.js rejects requests where the Origin header does not match the Host header.

Use action wrapper utilities (e.g. `createSafeActionClient` from next-safe-action) to enforce auth and validation pipelines.

Next.js will reject valid form submissions with a 403 Forbidden or "Invalid origin" error.