new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Bun · Runtime · all subjects

bun apis/csrf protection

13 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

CSRF protection APIs: Bun.CSRF.generate and Bun.CSRF.verify

Bun provides Bun.CSRF.generate() to generate CSRF tokens and Bun.CSRF.verify() to verify CSRF tokens for server-side CSRF protection.

Bun.CSRF.verify validates CSRF tokens

Bun.CSRF.verify() verifies a CSRF token and returns true if the token is valid and has not expired, false otherwise. It takes a token string parameter and an options object (optional). The token and options must use the same secret, encoding, algorithm, and sessionId that were used to generate the token.

Bun.CSRF.generate() options table

Bun.CSRF.generate(secret?, options?) accepts the following options: | Option | Type | Default | Description | |--------|------|---------|-------------| | expiresIn | number | 86400000 | Milliseconds until token expires. Defaults to 24 hours. | | encoding | string | "base64url" | Token encoding format: "base64", "base64url", or "hex". | | algorithm | string | "sha256" | HMAC algorithm: "sha256", "sha384", "sha512", "sha512-256", "blake2b256", or "blake2b512". | | sessionId | string | (none) | Binds token to requesting principal. Token only verifies when same sessionId passed to verify(). |

Bun.CSRF.verify() options table

Bun.CSRF.verify(token, options?) accepts the following options: | Option | Type | Default | Description | |--------|------|---------|-------------| | secret | string | (auto) | Secret used to sign token. If not provided, uses same in-memory default as generate(). | | maxAge | number | 86400000 | Maximum token age in milliseconds, independent of token's expiresIn. | | encoding | string | "base64url" | Must match encoding used during generate(). | | algorithm | string | "sha256" | Must match algorithm used during generate(). | | sessionId | string | (none) | Must match sessionId used during generate(). Token bound to one principal fails verification for other principals. |

Always bind CSRF tokens to sessionId to prevent replay attacks

The sessionId parameter (the requester's session identifier or user ID) must be passed to both generate() and verify(). Without sessionId, a token is only bound to the secret and any token the server has issued validates for every user, allowing attackers to obtain a token in their own session and replay it in a forged cross-site request from a victim's browser.

CSRF token generation example with sessionId

const token = Bun.CSRF.generate("my-secret", { sessionId: "user-session-id" }); const isValid = Bun.CSRF.verify(token, { secret: "my-secret", sessionId: "user-session-id" }); console.log(isValid); // true

Bun.CSRF.generate generates signed CSRF tokens

Bun.CSRF.generate() creates a CSRF token containing a cryptographic nonce, timestamp, and HMAC signature, encoded as a string. It takes a secret string parameter (optional) and an options object (optional). If no secret is provided, Bun generates a random in-memory default secret unique per thread.

CSRF token verification with custom options example

const isValid = Bun.CSRF.verify(token, { secret: "my-secret", sessionId: "user-session-id", }); const isValid2 = Bun.CSRF.verify(token, { secret: "my-secret", sessionId: "user-session-id", maxAge: 60 * 1000, // reject tokens older than 1 minute });

Bun.serve with CSRF protection example

const SECRET = process.env.CSRF_SECRET || "my-secret"; function getSessionId(req: Request): string | null { return req.headers.get("cookie")?.match(/(?:^|;\s*)session=([^;]+)/)?.[ 1] ?? null; } const server = Bun.serve({ routes: { "/form": req => { let sessionId = getSessionId(req); const headers = new Headers({ "Content-Type": "text/html" }); if (!sessionId) { sessionId = crypto.randomUUID(); headers.append("Set-Cookie", `session=${sessionId}; HttpOnly; SameSite=Lax; Path=/`); } const token = Bun.CSRF.generate(SECRET, { sessionId }); return new Response( `<form method="POST" action="/submit"> <input type="hidden" name="_csrf" value="${token}" /> <input type="text" name="message" /> <button type="submit">Send</button> </form>`, { headers }, ); }, "/submit": { POST: async req => { const sessionId = getSessionId(req); const formData = await req.formData(); const csrfToken = formData.get("_csrf"); if (!sessionId || typeof csrfToken !== "string" || !Bun.CSRF.verify(csrfToken, { secret: SECRET, sessionId })) { return new Response("Invalid CSRF token", { status: 403 }); } return new Response("OK"); }, }, }, }); console.log(`Listening on ${server.url}`);

CSRF default secret per thread

If the secret parameter is omitted in both generate() and verify(), Bun uses a random secret generated once per thread. This is convenient for single-threaded applications but tokens will not verify across servers, workers, or after a restart. For production use, always provide an explicit secret shared across your infrastructure.

CSRF default secret example

const token = Bun.CSRF.generate(); const isValid = Bun.CSRF.verify(token); // true

Bun.CSRF TypeScript types

type CSRFAlgorithm = "blake2b256" | "blake2b512" | "sha256" | "sha384" | "sha512" | "sha512-256"; interface CSRFGenerateOptions { expiresIn?: number; encoding?: "base64" | "base64url" | "hex"; algorithm?: CSRFAlgorithm; sessionId?: string; } interface CSRFVerifyOptions { secret?: string; encoding?: "base64" | "base64url" | "hex"; algorithm?: CSRFAlgorithm; maxAge?: number; sessionId?: string; } namespace Bun.CSRF { function generate(secret?: string, options?: CSRFGenerateOptions): string; function verify(token: string, options?: CSRFVerifyOptions): boolean; }

CSRF token generation with custom options example

const token = Bun.CSRF.generate("my-secret", { sessionId: "user-session-id", expiresIn: 60 * 60 * 1000, encoding: "hex", }); const token2 = Bun.CSRF.generate("my-secret", { sessionId: "user-session-id", algorithm: "sha512", });

Give your agent this brain