csurf

CSRF token middleware for Express — archived by the Express team in 2025 and no longer maintained.

Library
npm
v1.11.0
2,306stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
43/100Fair
Development Activity0
Maintenance20
Community52
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
57/100Fair
Architecture68
Code Quality68
Innovation42
Learning Curve50

csurf adds CSRF (cross-site request forgery) protection to Express and Connect apps as a single middleware: it wires a req.csrfToken() function into the request/response cycle, storing a per-visitor secret either in the session (via a session middleware like express-session) or in a cookie (via cookie-parser, using the double-submit cookie pattern), then validates that secret against a token submitted in the request body, query string, or a handful of well-known headers (CSRF-Token, XSRF-Token, X-CSRF-Token, X-XSRF-Token) on any non-GET/HEAD/OPTIONS request. It was, for years, the default answer to “how do I add CSRF protection to Express,” referenced directly from OWASP’s CSRF prevention cheat sheet and pulled into a huge number of Express tutorials and boilerplates.

The repository was formally archived by the Express organization in May 2025 with a caution banner directing users to Express’s GitHub Discussions instead of filing issues or PRs, and it had already carried a soft deprecation notice for some time before that — the maintainers stopped accepting new work well before the archive. Despite that, weekly npm downloads are still in the hundreds of thousands, reflecting how deeply it’s embedded in existing codebases rather than any ongoing new adoption; teams starting fresh are steered toward actively maintained alternatives (e.g. csrf-csrf, tiny-csrf) or toward SameSite-cookie-based designs that don’t require a dedicated token dance at all.

What You Get

  • A csurf(options) middleware factory that attaches a lazy req.csrfToken() function to generate tokens on demand
  • Two secret-storage strategies: session-based (default, via req.session) or cookie-based double-submit (via the cookie option, requiring cookie-parser)
  • A configurable token-lookup chain that reads from req.body._csrf, req.query._csrf, or one of four CSRF/XSRF header variants, with a fully custom value(req) override
  • A typed error path (err.code === 'EBADCSRFTOKEN') passed to next() for building custom 403 handling instead of a thrown exception
  • A configurable ignoreMethods list (defaults to GET/HEAD/OPTIONS) and sessionKey override for apps that store session data under a non-default key

Common Use Cases

  • Protecting classic server-rendered form POSTs in an Express app by embedding req.csrfToken() in a hidden _csrf input field
  • Protecting AJAX/fetch calls from a server-rendered page by exposing the token via a <meta> tag and echoing it back as a CSRF-Token request header
  • Cookie-only CSRF protection for APIs that don’t use server-side sessions, via cookie: true plus cookie-parser
  • Exempting specific routes (e.g. a webhook or public API mounted before the middleware) from CSRF checks by controlling middleware ordering
  • Auditing or maintaining legacy Express codebases that already depend on csurf, without introducing new CSRF logic

Under The Hood

Architecture The entire module lives in one ~200-line index.js: a csurf(options) factory closes over cookie/session configuration and returns the actual middleware, which lazily defines req.csrfToken() (caching the generated token until the secret changes) and validates incoming requests against a Tokens instance from the separate csrf package. Secret storage is abstracted behind getSecretBag/getSecret/setSecret helpers that branch on whether cookie-based or session-based storage was configured, and verifyConfiguration fails fast with a descriptive error if the required session or cookie-parser middleware wasn’t installed upstream — a small but deliberate piece of defensive design given how often that misconfiguration was reported as an issue.

Tech Stack Runtime dependencies are minimal and stable-era Node.js: cookie (serialization), cookie-signature (signed cookie support), http-errors (structured error objects with a .code), and csrf (the actual token generation/verification logic, itself wrapping uid-safe and tsscmp for constant-time comparison). There’s no build step, no TypeScript, and the engines field targets Node >= 0.8, reflecting a codebase frozen well before modern Node or ESM conventions took hold.

Code Quality A single test/test.js (~450 lines) exercises the middleware end-to-end with Connect, supertest, cookie-parser, cookie-session, and body-parser rather than mocking the request/response objects — covering session mode, cookie mode, signed cookies, custom value() getters, misconfiguration errors, and every documented token-lookup location. Tests run under Mocha with nyc coverage reporting, and the project lints with eslint-config-standard. There are no type annotations or TypeScript definitions, and no commits of substance have landed since the deprecation notice was added; the final commits in the repository’s history removed the source entirely and replaced it with an archive notice.

API Design The public surface is intentionally tiny: one factory function, one lazily-computed req.csrfToken(), and a small set of options. That minimalism made adoption nearly frictionless in the mid-2010s Express ecosystem, but it’s also become the project’s central liability — the double-submit-cookie/session-secret model it implements is no longer considered best practice on its own, and the Express team’s own guidance now points newcomers toward actively maintained CSRF middleware or toward SameSite-cookie-first designs rather than csurf’s token-matching approach.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search