Documentation
Server actions
Form handling where CSRF verification is structural, not a decorator.
Any exported HTTP method handler under routes/api/ is a server action. By the time it runs, the framework has already verified the CSRF token.
import type { ActionContext } from "stoneware";
export async function POST({ request }: ActionContext) {
const form = await request.formData();
const email = String(form.get("email") ?? "");
return Response.json({ ok: true });
}Forms
Use the Form helper instead of a raw form element and the hidden token field is injected for you.
import { Form } from "stoneware";
<Form action="/api/subscribe">
<input type="email" name="email" required />
<button type="submit">Subscribe</button>
</Form>;Verification happens in the request pipeline, before any handler is reached, on every non-GET request. It is not something a route opts into — a raw form does not silently skip protection, it simply fails. The token is checked against a clone of the request, so your handler still receives an unconsumed body.
For an island doing its own fetch(), pass the token in as a prop with csrfToken() and send it in the x-csrf-token header.
Something wrong in the framework itself rather than the page? Open an issue on GitHub.