Blog

How to keep your Next.js application secure

September 2024

Server Actions

Let's say we have a page for deleting user with a button and a handler that calls the server action.

import { deleteUser } from "./action";
import { auth } from "./auth";

export default async function DeleteUserPage() {
  const { userId } = await auth();

  async function handleDelete() {
    await deleteUser(userId);
  }

  return (
    <div>
      <button onClick={handleDelete}>delete</button>
    </div>
  )
}
"use server";

// exporting the function and making it asynchronous turns it into a server action

export async function deleteUser(id: string) {
  await db.user.delete(id);
}

Now, what might seem to be a problem? The problem is that now anyone can delete any user.

But How?

  • The server action is a POST endpoint than can be accessed by anyone
  • Anyone can call the server action and delete any user if they have their id

Solution

"use server";

export async function deleteUser(id: string) {
  await db.user.delete(id); 

  const { userId } = await auth(); 

  if (userId !== id) { 
    throw new Error("Unauthorized") 
  } 

  await db.user.delete(id); 
}