{"id":10693,"library":"csrf-sync","title":"CSRF Sync","description":"CSRF Sync is a utility package designed to provide robust stateful Cross-Site Request Forgery (CSRF) protection for Express applications, utilizing the Synchroniser Token Pattern. Developed in response to the deprecation of `csurf` and the perceived complexity or limited scope of alternative solutions, `csrf-sync` (current stable version 4.2.1) aims for a targeted and simplified implementation. It requires a server-side session management middleware like `express-session` to store tokens. The library focuses on providing the essential components for CSRF protection without imposing a full solution, allowing developers to integrate it flexibly. It is actively maintained with regular updates and follows a clear versioning strategy, with significant changes typically highlighted in major version bumps.","status":"active","version":"4.2.1","language":"javascript","source_language":"en","source_url":"https://github.com/Psifi-Solutions/csrf-sync","tags":["javascript","csrf","middleware","express","tokens","typescript"],"install":[{"cmd":"npm install csrf-sync","lang":"bash","label":"npm"},{"cmd":"yarn add csrf-sync","lang":"bash","label":"yarn"},{"cmd":"pnpm add csrf-sync","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for stateful session management to store CSRF tokens in `req.session`.","package":"express-session","optional":false}],"imports":[{"note":"Since v3, `csrfSync` is a named export. It's the factory function that returns an object of utilities, and should be imported as such for both ESM and CommonJS.","wrong":"const csrfSync = require('csrf-sync');","symbol":"csrfSync","correct":"import { csrfSync } from 'csrf-sync';"},{"note":"This is a middleware function returned by calling the `csrfSync()` factory function, not a direct named export from the package root. It must be destructured from the `csrfSync()` return value.","wrong":"import { csrfSynchronisedProtection } from 'csrf-sync';","symbol":"csrfSynchronisedProtection","correct":"const { csrfSynchronisedProtection } = csrfSync();"},{"note":"This utility function, used to create and store CSRF tokens in the session and retrieve them for client-side inclusion, is destructured from the object returned by `csrfSync()`.","wrong":"import { generateToken } from 'csrf-sync';","symbol":"generateToken","correct":"const { generateToken } = csrfSync();"}],"quickstart":{"code":"import express from 'express';\nimport session from 'express-session';\nimport { csrfSync } from 'csrf-sync';\n\nconst app = express();\nconst port = 3000;\n\n// Configure express-session middleware\napp.use(session({\n  secret: process.env.SESSION_SECRET ?? 'super-secret-key-please-change-me',\n  resave: false,\n  saveUninitialized: true,\n  cookie: { httpOnly: true, secure: process.env.NODE_ENV === 'production' }\n}));\n\n// Initialize csrf-sync and get the protection middleware and token generator\nconst { csrfSynchronisedProtection, generateToken } = csrfSync();\n\n// Apply CSRF protection to all routes (or specific ones)\napp.use(csrfSynchronisedProtection);\n\n// Middleware to parse URL-encoded bodies for form submissions\napp.use(express.urlencoded({ extended: false }));\n\n// Route to display a form with a CSRF token\napp.get('/', (req, res) => {\n  const token = generateToken(req);\n  res.send(`\n    <!DOCTYPE html>\n    <html>\n    <head><title>CSRF Test</title></head>\n    <body>\n      <h1>Submit Form</h1>\n      <form action=\"/submit\" method=\"POST\">\n        <input type=\"hidden\" name=\"_csrf\" value=\"${token}\">\n        <input type=\"text\" name=\"data\" placeholder=\"Enter data\">\n        <button type=\"submit\">Submit</button>\n      </form>\n    </body>\n    </html>\n  `);\n});\n\n// Protected route to handle form submission\napp.post('/submit', (req, res) => {\n  res.send(`Data received: ${req.body.data} (CSRF protected)`);\n});\n\n// Error handling for CSRF issues (optional but recommended)\napp.use((err, req, res, next) => {\n  if (err.code === 'EBADCSRFTOKEN') {\n    res.status(403).send('Invalid CSRF token - potential attack!');\n  } else {\n    next(err);\n  } \n});\n\napp.listen(port, () => {\n  console.log(`Server listening at http://localhost:${port}`);\n  if (!process.env.SESSION_SECRET) {\n    console.warn('WARNING: SESSION_SECRET is not set. Using a default, which is insecure for production.');\n  }\n});","lang":"typescript","description":"This quickstart demonstrates setting up an Express application with `express-session` and `csrf-sync` to protect a form submission route. It shows how to initialize the CSRF protection, generate a token, include it in an HTML form, and handle POST requests with CSRF validation, including basic error handling for invalid tokens."},"warnings":[{"fix":"Ensure `express-session` and `@types/express-session` are installed: `npm install express-session @types/express-session`.","message":"Starting with v4.0.0, `csrf-sync` no longer bundles TypeScript types for `express-session`. Users must explicitly install `express-session` and its types (`@types/express-session`) for TypeScript projects.","severity":"breaking","affected_versions":">=4.0.0"},{"fix":"Update import statements to use named exports for CommonJS or `import { csrfSync } from 'csrf-sync';` for ESM.","message":"Version 3.0.0 transitioned `csrf-sync` to an ESM-first package. This changed the CommonJS import pattern from attempting a default import to a named import `const { csrfSync } = require('csrf-sync');`.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Always ensure `express-session` or a compatible session middleware is initialized and used prior to `csrfSynchronisedProtection` middleware.","message":"`csrf-sync` fundamentally relies on a stateful session middleware (e.g., `express-session`) that populates `req.session`. Without this middleware correctly configured and placed before `csrfSynchronisedProtection`, the library will fail to store and validate tokens.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Follow OWASP guidelines for secure session management. Use a strong, securely stored `session.secret`, set `httpOnly` and `secure` flags appropriately for cookies, and avoid common session hijacking vectors.","message":"Improper configuration of the underlying session middleware (e.g., weak session secret, insecure cookie flags) can compromise the effectiveness of CSRF protection provided by `csrf-sync`. The library itself cannot mitigate underlying session vulnerabilities.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Evaluate your application's architecture; choose `csrf-sync` for stateful web applications and consider alternatives for stateless APIs.","message":"`csrf-sync` implements the Synchronizer Token Pattern, which requires server-side state. It is not suitable for purely stateless APIs. For stateless scenarios, consider the Double-Submit Cookie Pattern (e.g., using `csrf-csrf`).","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure `app.use(session(...))` is called *before* `app.use(csrfSynchronisedProtection)` in your Express application setup.","cause":"The `express-session` middleware (or equivalent) has not been configured or is not placed correctly before the `csrf-sync` middleware.","error":"TypeError: Cannot read properties of undefined (reading 'session')"},{"fix":"Verify that the client-side code correctly retrieves the token using `generateToken(req)` and includes it in all state-changing requests (e.g., POST, PUT, DELETE). On the server, ensure `csrfSynchronisedProtection` is applied to the routes that require protection.","cause":"The CSRF token submitted in the request (e.g., via `_csrf` form field or header) does not match the token stored in the user's session, or no token was provided.","error":"Error: Invalid CSRF Token"},{"fix":"For ESM, use `import { csrfSync } from 'csrf-sync';`. For CommonJS, use `const { csrfSync } = require('csrf-sync');`.","cause":"Incorrect import statement for `csrfSync`. This often happens when treating it as a default export or using an outdated CommonJS pattern after v3.","error":"TypeError: csrfSync is not a function"}],"ecosystem":"npm"}