Cookies
Learn how browser cookies store small values, travel with requests, and use attributes like Expires, Max-Age, SameSite, Secure, and HttpOnly.
- 01Read and write cookies safelyUse
document.cookie, encoding, updating, and deletion without confusing attributes for readable data. - 02Choose the right attributesExplain when
Max-Age,Expires,Path,Domain,SameSite,Secure, andHttpOnlymatter. - 03Pick the right storageDecide when a cookie, localStorage, or neither belongs in a real app.
Cookies in one minute
A cookie is a tiny name=value record that a browser stores for a site. Unlike a normal variable, a matching cookie can be sent back to the server automatically on future requests. That one idea powers login sessions, language choices, A/B test buckets, and consent flags.
Cookies are not general-purpose storage. They are small, string-based, and they ride along with requests. That is useful when the server needs the value, and wasteful or risky when it does not. A typical practical limit is around 4 KB per cookie, but browser rules vary, so keep cookies boring and tiny.
At an event, staff stamp your hand once and check it when you return. Cookies work similarly: a server gives the browser a value, and the browser sends it again when the request matches the cookie rules.
- In real life: Staff stamp your hand
- In JavaScript: The server sends
Set-Cookie: session=abc - In real life: The stamp stays with you
- In JavaScript: The browser stores the cookie
- In real life: Staff check it when you return
- In JavaScript: The browser sends
Cookie: session=abcon matching requests - In real life: Staff recognize the stamp
- In JavaScript: The server recognizes your browser or session
Where the analogy stops: A hand stamp shows a person returned. A cookie only shows that a browser sent a value, so servers still need security checks.
| Idea | Meaning | Why it matters |
|---|---|---|
| Value | A string like theme=dark | The part JavaScript may read if the cookie is not HttpOnly. |
| Attributes | Rules like Max-Age, Path, SameSite, Secure | They control lifetime and sending, but are not read back through document.cookie. |
| Automatic sending | Browser adds matching cookies to requests | Great for sessions; bad for large data. |
| Visibility | Normal cookies are readable; HttpOnly cookies are not | Never store secrets in JavaScript-readable cookies. |
The rest of this lesson makes each of those rows concrete. You will write real demo cookies on this site, inspect the odd document.cookie API, simulate SameSite decisions, and decide when cookies are the wrong tool.
Expires & Max-Age: how long the ticket works
LIFETIMEA cookie without Expires or Max-Age is a session cookie. The browser may keep it until the browsing session ends. To make the lifetime explicit, use one of these attributes:
| Attribute | Example | Meaning |
|---|---|---|
Max-Age | Max-Age=3600 | Valid for 3,600 seconds from now. If both attributes exist, this wins. |
Expires | Expires=Wed, 21 Oct 2030 07:28:00 GMT | Valid until an absolute HTTP date. Use the Date and time lesson for safe date handling. |
| Delete | Max-Age=0 | Overwrite the same name, path, and domain with an expired lifetime. |
When you create an Expires string, use a real date formatted for HTTP, often from date.toUTCString(). If you need a refresher, revisit the Date & time lesson. For most app code, Max-Age is easier because it is just seconds from now.
A hand stamp can say it is valid only today or only in one area. Cookie attributes decide where and when the browser may use the value.
- In real life: Valid only today
- In JavaScript:
ExpiresorMax-Age - In real life: Valid in one event area
- In JavaScript:
PathandDomain - In real life: Checked only at secure entrances
- In JavaScript:
Secure - In real life: Hidden from visitors
- In JavaScript:
HttpOnly
Where the analogy stops: A hand stamp is visible. HttpOnly cookies are deliberately hidden from JavaScript, though the browser can still send them.
SameSite: should another site be allowed to send your ticket?
SIMULATORSameSite is a request-sending rule. It helps reduce CSRF (cross-site request forgery), where a malicious site tries to make your browser submit a request to a site where you are already signed in. The browser decides whether the cookie rides along.
Strict: send only for same-site requests.Lax: send for same-site requests and top-level cross-siteGETnavigations, such as normal links. Most modern browsers treat a missing SameSite as Lax-like.None: allow cross-site sending, but modern browsers requireSecure. Third-party-cookie restrictions may still block tracking-style cases.
LaxLax blocks cross-site POST forms, iframes, images, and fetch-like subrequests to reduce CSRF risk.
Secure & HttpOnly: transport and visibility
SAFETYSecure and HttpOnly solve different problems. Secure says the cookie is only sent over HTTPS. Localhost behavior has varied across browser features, so for real applications treat Secure cookies as HTTPS-only. HttpOnly says JavaScript cannot read the cookie at all.
Set-Cookie: session=abc123; Path=/; HttpOnly; Secure; SameSite=LaxSet-Cookie: widget_id=public; Path=/; Secure; SameSite=NoneHttpOnly is a server-set attribute. If you type document.cookie = "session=abc; HttpOnly", you do not get a sealed session cookie. Use a server Set-Cookie header for session tokens, and never store secrets in cookies that JavaScript can read.
That is why authentication cookies are usually set by the server, not by client code: HttpOnly; Secure; SameSite=Lax makes the browser carry the session while keeping page scripts from reading it.
Where you’ll use cookies
SORTERThe deciding question is: does the server need this small value on matching requests? If yes, a cookie may fit. If JavaScript alone needs the value, the next lesson’s localStorage or sessionStorage may be better. If the value is truly secret, keep it out of the browser.
- Session ID that proves who is signed in
- Dark mode theme used only after the app loads
- A secret API key for a paid service
- Tracking consent choice that the server must respect
- A large shopping cart with many product details
- A CSRF signing secret
Choose the safest storage home for each piece of data.
Common misconceptions
- “Writing
document.cookiereplaces all cookies.” It writes one cookie. - “I can read attributes later.” Reads show visible
name=valuepairs only. - “Deleting means setting an empty value.” Empty value is still a cookie; expire it with
Max-Age=0or a pastExpires. - “Secure hides a cookie from JavaScript.”
HttpOnlyhides it;Securecontrols HTTPS sending. - “SameSite replaces CSRF protection.” It helps a lot, but real apps still use careful methods, tokens, and server checks.
- “Cookies are a good place for secrets.” Only server-set
HttpOnlycookies are appropriate for session tokens; never store secret API keys in browser-readable storage.
Practice exercises
5 EXERCISESRead the starter code. What exact text does it print?
const raw = "cf_demo_theme=dark; cf_demo_name=Ada%20Lovelace";
const cookies = Object.fromEntries(
raw.split("; ").map((pair) => pair.split("=").map(decodeURIComponent))
);
console.log(cookies.cf_demo_name);const raw = "cf_demo_theme=dark; cf_demo_name=Ada%20Lovelace";
const cookies = Object.fromEntries(
raw.split("; ").map((pair) => pair.split("=").map(decodeURIComponent))
);
console.log(cookies.cf_demo_name);The second cookie value is Ada%20Lovelace; decoding it prints Ada Lovelace.
Which attribute value belongs in the delete write?
document.cookie = "cf_demo_theme=dark; Path=/";
// Now delete the same cookie.document.cookie = "cf_demo_theme=; Max-Age=0; Path=/";Overwriting the same cookie with Max-Age=0 tells the browser to remove it. Keep the same path.
This app stores a session token from JavaScript. Explain what is wrong and write the safer server header.
document.cookie = "token=secret.jwt.value; Max-Age=3600; Path=/; Secure";Set-Cookie: token=secret.jwt.value; Path=/; Max-Age=3600; HttpOnly; Secure; SameSite=LaxA session token should be set by the server with HttpOnly, so page JavaScript cannot read it. Secure alone is not enough.
A different site submits a POST form to your app. Your session cookie is SameSite=Lax. Is it sent or blocked?
// Cross-site POST form with SameSite=Lax
console.log("blocked");// Cross-site POST form with SameSite=Lax
console.log("blocked");A cross-site POST form does not get a SameSite=Lax cookie, so the cookie is blocked.
Your server renders dark mode before the app hydrates. Pick cookie or localStorage for the theme and justify your choice.
document.cookie = "theme=dark; Max-Age=31536000; Path=/; SameSite=Lax";If the server renders the first paint with the theme, a tiny cookie is reasonable. If only client JavaScript needs it after load, localStorage is also fine.
Check your understanding
7 QUESTIONSQuestion 1 of 7What does assigning to
document.cookiedo?Choose an answer to see the explanation.
Question 2 of 7What does this print?
Read the code, then predictconst raw = "theme=dark; name=Ada%20Lovelace"; const pairs = raw.split("; ").map((pair) => pair.split("=")); console.log(decodeURIComponent(pairs[1][1]));Choose an answer to see the explanation.
Question 3 of 7If both
ExpiresandMax-Ageare present, which one wins?Choose an answer to see the explanation.
Question 4 of 7A cross-site POST form submits to your site. Which SameSite value sends the cookie?
Choose an answer to see the explanation.
Question 5 of 7Which cookie attribute prevents JavaScript from reading the cookie?
Choose an answer to see the explanation.
Question 6 of 7What readable pair does this simplified cookie read print?
Read the code, then predictconst write = "theme=dark; Max-Age=3600; Path=/; SameSite=Lax"; const readable = write.split(";")[0]; console.log(readable);Choose an answer to see the explanation.
Question 7 of 7When is the Cookie Store API a better fit than
document.cookie?Choose an answer to see the explanation.
Key takeaways
- A cookie is a small
name=valuerecord with request-sending rules. document.cookiereads visible cookies as one string and writes one cookie at a time.Max-AgebeatsExpires; deleting is an expired overwrite with the same name/path/domain.SameSitehelps control cross-site sending;NonerequiresSecure.Securemeans HTTPS sending;HttpOnlymeans JavaScript cannot read it.- Use Cookie Store API only after feature detection, and keep fallbacks.
Final definition: a cookie is a tiny browser-stored string that follows matching requests according to attributes set by JavaScript or, more powerfully, by the server.
Up next: localStorage & sessionStorage.