Skip to content
Express.js ex libraries 4 min read

cookie-parser

HTTP cookies arrive on the request as a single Cookie header — a semicolon-delimited string that Express does not parse for you out of the box. The cookie-parser middleware decodes that header into a convenient req.cookies object, and, when you supply a secret, it can verify tamper-proof signed cookies so a client cannot quietly edit values you set. It is the standard companion to session handling, “remember me” flows, and any feature that needs to round-trip small pieces of state through the browser.

Install the package and register it with app.use before any route that needs to read cookies. The middleware runs once per request, parses the Cookie header, and attaches the result to req.cookies.

npm install cookie-parser
const express = require("express");
const cookieParser = require("cookie-parser");

const app = express();

app.use(cookieParser()); // no secret -> unsigned cookies only

app.get("/whoami", (req, res) => {
  res.json({ cookies: req.cookies });
});

app.listen(3000, () => console.log("Listening on http://localhost:3000"));

When a browser sends Cookie: theme=dark; lang=en, the parsed object is ready on the request:

Output:

> GET /whoami HTTP/1.1
> Cookie: theme=dark; lang=en

< HTTP/1.1 200 OK
< Content-Type: application/json
{"cookies":{"theme":"dark","lang":"en"}}

Reading and setting cookies

req.cookies is a plain object keyed by cookie name. To create a cookie you use Express’s built-in res.cookie(name, value, options) — that part is core Express, not cookie-parser — and to remove one you call res.clearCookie(name). The options control lifetime and security flags.

app.get("/login", async (req, res) => {
  // res.cookie comes from Express itself
  res.cookie("theme", "dark", {
    httpOnly: true,
    secure: true,
    sameSite: "lax",
    maxAge: 1000 * 60 * 60 * 24 * 7, // 7 days in ms
  });
  res.json({ ok: true });
});

app.get("/theme", (req, res) => {
  const theme = req.cookies.theme ?? "light";
  res.json({ theme });
});

The most common cookie options are summarized below.

OptionTypePurpose
maxAgenumberLifetime in milliseconds (relative)
expiresDateAbsolute expiry date
httpOnlybooleanHide the cookie from client-side JavaScript
securebooleanSend only over HTTPS
sameSite"strict" / "lax" / "none"CSRF / cross-site sending policy
signedbooleanSign the cookie (requires a secret)
pathstringURL path the cookie applies to
domainstringDomain the cookie is scoped to

Always set httpOnly: true for cookies that hold session or auth data. It prevents document.cookie from reading them, which closes off a large class of XSS-based token theft.

Signed cookies

Pass a secret to cookieParser(secret) to enable signing. A signed cookie stores the value plus an HMAC of that value using your secret. If a client edits the value, the signature no longer matches and Express discards it — so signed cookies are about integrity, not secrecy (the value is still readable, just not forgeable).

Signed cookies are written with signed: true and read from req.signedCookies rather than req.cookies.

const cookieParser = require("cookie-parser");

app.use(cookieParser(process.env.COOKIE_SECRET));

app.get("/set", (req, res) => {
  res.cookie("uid", "user-42", {
    signed: true,
    httpOnly: true,
    sameSite: "lax",
  });
  res.json({ ok: true });
});

app.get("/account", (req, res) => {
  const uid = req.signedCookies.uid; // undefined if tampered or missing
  if (!uid) return res.status(401).json({ error: "not signed in" });
  res.json({ uid });
});

On the wire a signed cookie carries an s: prefix and the appended signature:

Output:

< Set-Cookie: uid=s%3Auser-42.k8Hk%2Fd1c3...; Path=/; HttpOnly; SameSite=Lax

If a request arrives with a uid whose value was altered, req.signedCookies.uid comes back as the boolean false, while a clean, verified cookie yields its original string. You can also rotate secrets by passing an array — the first is used to sign, and any in the list can verify:

app.use(cookieParser(["new-secret", "previous-secret"]));

Clearing cookies

To delete a cookie, call res.clearCookie(name, options). The browser only honors the deletion if the path and domain match those used when the cookie was set, so pass the same options you originally used.

app.post("/logout", (req, res) => {
  res.clearCookie("uid", { httpOnly: true, sameSite: "lax" });
  res.clearCookie("theme");
  res.status(204).end();
});

clearCookie works by sending a Set-Cookie header with an expiry date in the past:

Output:

< Set-Cookie: uid=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly

cookie-parser works unchanged on Express 4 and Express 5 — it is a standalone middleware and does not rely on the routing changes (such as the new wildcard syntax) that 5.x introduced.

Best Practices

  • Mount cookieParser() early, before any route or middleware that reads req.cookies or req.signedCookies.
  • Store the signing secret in an environment variable; never hard-code it or commit it to source control.
  • Use signed cookies for anything a client must not forge (user ids, roles), and read them from req.signedCookies, not req.cookies.
  • Remember signing is integrity, not encryption — do not place truly secret data in a cookie value even when signed.
  • Set httpOnly, secure, and an appropriate sameSite on every auth-related cookie to defend against XSS and CSRF.
  • Pass the same path/domain to res.clearCookie that you used in res.cookie, or the browser will ignore the deletion.
  • Rotate secrets by supplying an array to cookieParser, keeping old secrets long enough to verify existing cookies.
Last updated June 14, 2026
Was this helpful?