- Symptom
- An admin page redirects signed-out visitors, but its form action still runs when posted to directlyA 'use server' function changes or deletes data without calling your auth helperA signed-in user can change another user's records by passing a different id
- Cause
- An exported Server Action is reachable by a direct POST request, not only through your UI. A page-level authentication check does not extend to the Server Actions defined in it, because each action is a separate entry point. Checking that a user is logged in is also not enough when the action acts on a record they do not own.
- Fix
- Verify authentication and authorization inside every Server Action, or in a server-only data access layer each action calls: get the session, throw if there is none, then check that the user owns or may act on the specific record before changing it.
- Apply
'use server' import { auth } from '@/lib/auth' import { db } from '@/lib/db' export async function deletePost(postId: string) { const session = await auth() if (!session?.user) { throw new Error('Unauthorized') } const post = await db.post.findUnique({ where: { id: postId } }) if (post?.authorId !== session.user.id) { throw new Error('Forbidden') } await db.post.delete({ where: { id: postId } }) }- Affected
- Next.js App Router apps with Server Actions that change data
- Sources
Last verified 2026-10-27 · Confirmed by 0 builders