CSRF Protection
Built-in Cross-Site Request Forgery protection using the Double-Submit Cookie pattern, integrated directly into the security middleware pipeline.
__Host-csrf-token by default). For every state-mutating request (POST, PUT, PATCH, DELETE), the client must include the token in one of the following locations:Header (Recommended)
x-csrf-token HTTP header for SPAs and API clients.
Body Field
_csrf field in the request body.
Query Param
_csrf query parameter (less recommended).
GET, HEAD, and OPTIONS requests are ignored by default, as they are considered safe methods.
Configuration
Basic Setup
import { createServer } from "xypriss";
const app = createServer({
security: {
csrf: {
secret: __sys__.__env__.get("CSRF_SECRET"),
}
}
});Using XyPriss Environment Shield (`__sys__`)
The recommended approach is to use the built-in environment shield to securely load the secret:
import { createServer, __sys__ } from "xypriss";
const app = createServer({
security: {
csrf: {
secret: __sys__.__env__.get("CSRF_SECRET", "fallback-dev-secret"),
cookieOptions: {
httpOnly: true,
sameSite: "strict",
}
}
}
});Disabling CSRF Protection
const app = createServer({
security: {
csrf: false,
}
});Configuration Reference
CSRF protection is configured under security.csrf.
| Property | Type | Default | Description |
|---|---|---|---|
| secret | string | — | Required. Secret key used to sign and verify CSRF tokens. |
| enabled | boolean | true | Toggle CSRF protection. |
| cookieName | string | "__Host-csrf-token" | Name of the CSRF cookie set on the client. |
| cookieOptions.httpOnly | boolean | true | Prevents client-side JavaScript from accessing the cookie. |
| cookieOptions.sameSite | "strict" | "lax" | "none" | boolean | "strict" | Controls cookie cross-site behavior. |
| cookieOptions.secure | boolean | true in production | Restricts the cookie to HTTPS. Automatically set based on environment. |
Reading the Token (Server-Side)
The CSRF token is attached to the request object and can be read directly from req.csrfToken(). Use this to send the token to the client (e.g., in an HTML form or as part of an initial API response).
app.get("/csrf-token", (req, res) => {
const token = req.csrfToken?.();
res.json({ csrfToken: token });
});Client-Side Integration
HTML Forms
Embed the token in a hidden field:
<form method="POST" action="/api/submit">
<input type="hidden" name="_csrf" value="<%= csrfToken %>" />
<!-- form fields -->
<button type="submit">Submit</button>
</form>Fetch / Axios (SPA)
Fetch the token
Get the token from the server first:
const { csrfToken } = await fetch("/csrf-token").then(r => r.json());Include in subsequent requests
Include it in mutating requests via the x-csrf-token header:
await fetch("/api/data", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-csrf-token": csrfToken,
},
body: JSON.stringify({ name: "example" }),
});Pipeline Position
CSRF middleware runs last in the security pipeline, after body parsing and all other protections. This is intentional, as CSRF validation requires the request body and session data to be fully available.
403 Forbidden. No further request processing occurs.Protect your application at the URL level with the StruLink-powered scanner.
