Bun.CSRF — native CSRF token generation/verification in middleware
Accept, depends on [[rfc-bun-cookies]] and (for renderer auto-injection) [[rfc-bun-htmlrewriter]].
Review verdict (2026-05-24)
Accept, depends on [[rfc-bun-cookies]] and (for renderer auto-injection) [[rfc-bun-htmlrewriter]].
Scope split:
- Phase 1 (this RFC):
Bun.CSRFexposed asctx.csrf.token()/ctx.csrf.verify(submitted). Users render the hidden input themselves in their forms. No renderer-side magic. - Phase 2 (folded into HTMLRewriter RFC): opt-in auto-injection of
<input type="hidden" name="_csrf">into POST forms via the HTMLRewriter pipeline.
Edge-adapter parity (12): outside Bun, fall back to a WebCrypto HMAC implementation of the same scheme. Adapter responsibility.
Summary
Bun ships Bun.CSRF.generate(secret, opts?) and Bun.CSRF.verify(token, secret, opts?) — HMAC-signed CSRF tokens with optional expiration and sameSite semantics. Patties middleware (07) should expose a one-liner CSRF helper that wraps this API rather than telling users to bring csurf or roll their own HMAC.
Motivation
07-middleware leaves CSRF as an unanswered "where does this live" question. Any framework that ships forms (and Patties does, via 02b filesystem routes and 06 islands) needs an answer. Bun.CSRF is zero-dep, constant-time, and pairs naturally with Bun.CookieMap (see rfc-bun-cookies.md) and Bun.secrets for the signing secret.
Proposal
- 07-middleware: add
ctx.csrf.token()(generates + sets the cookie if absent) andctx.csrf.verify(submitted)(returns boolean). Users render the hidden input in their forms in Phase 1. - 03-render: opt-in renderer auto-injection of
<input type="hidden" name="_csrf">for POST forms — deferred to Phase 2 via [[rfc-bun-htmlrewriter]]. Opt-out attribute will be<form data-no-csrf>. - 13-conventions: ban
csurf,lusca.
Sample:
export const POST = async (ctx) => {
if (!ctx.csrf.verify(ctx.formData.get("_csrf"))) return new Response("403", { status: 403 });
// ...
};
Trade-offs
- Only meaningful for cookie-bearing browsers; pure JSON APIs called with bearer tokens skip CSRF — middleware must allow opt-out.
- Adds an implicit cookie on first GET — surprise factor; documented in 07.
Open questions
- Secret source:
Bun.env.PATTIES_CSRF_SECRETrequired, or auto-generated per process in dev? - Token rotation policy.
- Edge adapter parity —
Bun.CSRFships in Bun runtime only; vendor adapters need a shim or fall back to WebCrypto HMAC.