Learning on Web Dev Open is free for all.

Framework Internals > The App Router, and where the seams areA server action is a public endpoint
Phase 04The App Router, and where the seams are226 of 434

A server action is a public endpoint

It looks like a function call. It is an HTTP POST that anyone can construct, and the ergonomics are good enough to make you forget that.

Concept15 minAI adversary

The syntax hides an HTTP boundary. Marking a function "use server" and calling it from a component compiles to a POST to a generated endpoint with a serialised argument list. Anyone can send that request, with any arguments, at any time, without ever loading your page. Every rule about untrusted input applies exactly as it would to a route handler you wrote by hand.

So authorisation belongs inside the action. Hiding the button, disabling the form, checking permission in the page that renders it, none of that is enforcement, because none of it is in the path of the request. The first lines of the action should establish who is calling and whether they may, and then validate every argument against a schema, because the client-side types are erased.

What you get in exchange is real: no endpoint to name, no fetch to write, no duplicate type definitions, and progressive enhancement where a form still works before JavaScript loads. Take the ergonomics and keep the discipline; the failure mode is treating the compiler’s convenience as a trust boundary.

You should now be able to

  • Treat an action as an untrusted entry point
  • Place authorisation and validation inside the action, not around it
Ask the community

Loading…