csurf
CSRF token middleware for Express — archived by the Express team in 2025 and no longer maintained.
Repository Health
Technical Analysis
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 lazyreq.csrfToken()function to generate tokens on demand - Two secret-storage strategies: session-based (default, via
req.session) or cookie-based double-submit (via thecookieoption, 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 customvalue(req)override - A typed error path (
err.code === 'EBADCSRFTOKEN') passed tonext()for building custom 403 handling instead of a thrown exception - A configurable
ignoreMethodslist (defaults to GET/HEAD/OPTIONS) andsessionKeyoverride 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_csrfinput field - Protecting AJAX/fetch calls from a server-rendered page by exposing the token via a
<meta>tag and echoing it back as aCSRF-Tokenrequest header - Cookie-only CSRF protection for APIs that don’t use server-side sessions, via
cookie: trueplus 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.
Used by 2 apps in this directory
Countly
Analytics · Marketing
Privacy-first, self-hosted analytics and customer engagement platform with full data ownership, GDPR compliance, and AI-powered insights across mobile, web, desktop, and IoT.
overleaf
Collaboration · Productivity
Open-source, real-time collaborative LaTeX editor with sandboxed compilation and full TeXLive support for self-hosted academic and research teams.