Security

CSRF Protection

Built-in Cross-Site Request Forgery protection using the Double-Submit Cookie pattern, integrated directly into the security middleware pipeline.

How It Works
CSRF protection is based on the Double-Submit Cookie strategy. On the first request, the server generates a cryptographically signed CSRF token and sets it as a cookie (__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

typescript
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:

typescript
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

typescript
const app = createServer({
    security: {
        csrf: false,
    }
});

Configuration Reference

CSRF protection is configured under security.csrf.

PropertyTypeDefaultDescription
secretstringRequired. Secret key used to sign and verify CSRF tokens.
enabledbooleantrueToggle CSRF protection.
cookieNamestring"__Host-csrf-token"Name of the CSRF cookie set on the client.
cookieOptions.httpOnlybooleantruePrevents client-side JavaScript from accessing the cookie.
cookieOptions.sameSite"strict" | "lax" | "none" | boolean"strict"Controls cookie cross-site behavior.
cookieOptions.securebooleantrue in productionRestricts 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).

typescript
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:

html
<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:

typescript
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:

typescript
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.

Error Behavior
If the CSRF token is missing or invalid, the middleware returns 403 Forbidden. No further request processing occurs.
Malicious URL Scanner

Protect your application at the URL level with the StruLink-powered scanner.