`Cookie` in TypeScript
This article explains Cookie in TypeScript.
We walk through practical patterns for handling cookies safely and reliably in both the browser and the server.
YouTube Video
Cookie in TypeScript
Basic concepts of cookies
A cookie is a mechanism for storing small strings (name=value pairs) on the client, created via the Set-Cookie HTTP header or document.cookie. You can control their behavior with security attributes (HttpOnly, Secure, SameSite, etc.).
Basic operations in the browser: document.cookie
Below is the minimal example to write a cookie in the browser. Create a cookie by appending a string to document.cookie.
1// Set a simple cookie that expires in 7 days.
2// Note: Comments are in English per the user's preference.
3const setSimpleCookie = (name: string, value: string) => {
4 const days = 7;
5 const expires = new Date(Date.now() + days * 86400_000).toUTCString();
6 // name=value; Expires=...; Path=/
7 document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}; Expires=${expires}; Path=/`;
8};
9
10setSimpleCookie('theme', 'dark');- This code creates a cookie that expires in 7 days. It’s easy to use on the browser side, but since you can’t set
HttpOnly, you should avoid storing sensitive information.
Reading cookies (browser)
The following function is a helper that retrieves the value of the cookie with a specified name from document.cookie. document.cookie is returned as a string delimited by a semicolon and a space ('; '). Therefore, we split it and look for the desired cookie.
1// Parse document.cookie and return value for given name or null if not found.
2const getCookie = (name: string): string | null => {
3 const cookies = document.cookie ? document.cookie.split('; ') : [];
4 for (const cookie of cookies) {
5 const [k, ...rest] = cookie.split('=');
6 const v = rest.join('=');
7 if (decodeURIComponent(k) === name) {
8 return decodeURIComponent(v);
9 }
10 }
11 return null;
12};
13
14// Example usage:
15const theme = getCookie('theme'); // => "dark" if set
16console.log('theme cookie:', theme);- This function decodes both the cookie name and value to safely compare and retrieve them. It handles duplicate cookie names and encoded special characters, making it a simple yet robust implementation.
Understanding and applying secure attributes
Cookies have several important attributes, each controlling security and scope of behavior.
- The
HttpOnlyattribute prevents the cookie from being accessible from JavaScript, helping to mitigate XSS (cross-site scripting) attacks. Note that you cannot setHttpOnlyfrom the browser side. - The
Secureattribute restricts cookies to be sent only over HTTPS, reducing the risk of eavesdropping and tampering. - The
SameSiteattribute controls whether cookies are sent with cross-site requests and helps prevent CSRF (cross-site request forgery) attacks. - The
Pathattribute specifies the scope of request paths for which the cookie is sent, and theDomainattribute specifies the domain where the cookie is valid. - By setting the
ExpiresorMax-Ageattribute, you can control the cookie's expiration.
Example of adding SameSite / Secure in the browser (what's possible)
HttpOnly cannot be set on the client side. Below is an example of adding SameSite and Secure on the client side. However, Secure only takes effect on HTTPS pages.
1// Set cookie with SameSite and Secure attributes (Secure only effective over HTTPS).
2const setCookieWithAttributes = (name: string, value: string) => {
3 const maxAge = 60 * 60 * 24 * 7; // 7 days in seconds
4 // Note: HttpOnly cannot be set from JS; set it on server-side when you want to restrict JS access.
5 document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}; `
6 + `Max-Age=${maxAge}; `
7 + `Path=/; `
8 + `SameSite=Lax; `
9 + `Secure`;
10};
11
12setCookieWithAttributes('session_hint', 'true');SameSite=Laxis a safe and common choice. For stronger restrictions useSameSite=Strict, but legitimate navigations from external sites may stop working.
Setting cookies on the server (Set-Cookie) (Node / TypeScript)
On the server you can add HttpOnly via the Set-Cookie header, so session management should ideally be done server-side. Below is an example using Node's http module.
1// A minimal Node HTTP server in TypeScript that sets a secure HttpOnly cookie.
2// This example uses built-in 'crypto' for a random session id.
3import http from 'http';
4import crypto from 'crypto';
5
6const server = http.createServer((req, res) => {
7 if (req.url === '/login') {
8 const sessionId = crypto.randomBytes(16).toString('hex');
9 // Set cookie with HttpOnly, Secure, SameSite and Path
10 // Expires is optional — Max-Age preferred for relative lifetimes.
11 res.setHeader('Set-Cookie', `sid=${sessionId}; `
12 + `HttpOnly; `
13 + `Secure; `
14 + `SameSite=Strict; `
15 + `Path=/; `
16 + `Max-Age=3600`
17 );
18 res.writeHead(302, { Location: '/' });
19 res.end();
20 return;
21 }
22
23 res.writeHead(200, { 'Content-Type': 'text/plain' });
24 res.end('Hello\n');
25});
26
27server.listen(3000, () => {
28 console.log('Server running on http://localhost:3000');
29});- When you set the
HttpOnlyattribute on the server side, the cookie becomes inaccessible from JavaScript, making it harder for XSS (cross-site scripting) attacks to steal it. Additionally, by adding theSecureattribute so that cookies are always sent over HTTPS, you can prevent eavesdropping and tampering and improve communication security.
Cookie serialization/parsing implementation (a server-side helper)
Below is a simple server-side utility that builds a Set-Cookie header string.
1// Cookie serialization helper for server-side use.
2// Returns a properly formatted Set-Cookie header value.
3type CookieOptions = {
4 path?: string;
5 domain?: string;
6 maxAge?: number;
7 expires?: Date;
8 httpOnly?: boolean;
9 secure?: boolean;
10 sameSite?: 'Strict' | 'Lax' | 'None';
11};
12
13const serializeCookie = (name: string, value: string, opts: CookieOptions = {}): string => {
14 const parts: string[] = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];
15
16 if (opts.maxAge != null) parts.push(`Max-Age=${Math.floor(opts.maxAge)}`);
17 if (opts.expires) parts.push(`Expires=${opts.expires.toUTCString()}`);
18 if (opts.domain) parts.push(`Domain=${opts.domain}`);
19 parts.push(`Path=${opts.path ?? '/'}`);
20 if (opts.httpOnly) parts.push('HttpOnly');
21 if (opts.secure) parts.push('Secure');
22 if (opts.sameSite) parts.push(`SameSite=${opts.sameSite}`);
23
24 return parts.join('; ');
25};
26
27// Example usage:
28const headerValue = serializeCookie('uid', 'abc123', {
29 httpOnly: true,
30 secure: true,
31 sameSite: 'Lax',
32 maxAge: 3600
33});
34console.log(headerValue);
35// => "uid=abc123; Max-Age=3600; Path=/; HttpOnly; Secure; SameSite=Lax"
- This utility forms the basis for creating
Set-Cookieon a custom server. Libraries can handle many more edge cases.
Preventing tampering with signatures (HMAC)
It's dangerous to store important values directly in cookies. We introduce a method that signs values on the server to detect tampering. Here we use HMAC-SHA256. In production, you also need to manage token revocation on the server side.
1// A simple HMAC signing and verification helper for cookies.
2// Signing prevents client from tampering cookie values.
3import crypto from 'crypto';
4
5const SECRET = 'replace_with_env_secret'; // store in env var in production
6
7const signValue = (value: string) => {
8 const hmac = crypto.createHmac('sha256', SECRET);
9 hmac.update(value);
10 return `${value}.${hmac.digest('hex')}`;
11};
12
13const verifySignedValue = (signed: string): string | null => {
14 const idx = signed.lastIndexOf('.');
15 if (idx === -1) return null;
16 const value = signed.slice(0, idx);
17 const sig = signed.slice(idx + 1);
18
19 const hmac = crypto.createHmac('sha256', SECRET);
20 hmac.update(value);
21 const expected = hmac.digest('hex');
22 // use timing-safe comparison in production
23 if (crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
24 return value;
25 }
26 return null;
27};
28
29// Example usage:
30const signed = signValue('userId=42');
31console.log('signed:', signed);
32console.log('verified:', verifySignedValue(signed)); // => "userId=42"
- With this method, you can check whether the Cookie value has been tampered with. Do not include the signing key in the source code; manage it through secure means such as environment variables.
Cookies and CSRF mitigation (general patterns)
Sessions that use cookies need CSRF protection. Typical mitigations include:.
- Set
SameSitetoLaxorStrictto prevent unnecessary cross-site sending. UseSameSite=None; Secureonly when cross-origin communication is necessary. - Use CSRF tokens, validated by the server, for forms and API requests. Do not store the token in an
HttpOnlycookie; instead, provide it via the response body or meta tags, and have JavaScript read it only when necessary. - If the token can be accessed from JavaScript, be sure to also implement XSS protections (CSP, output escaping, etc.).
- Require reauthentication for sensitive actions and at login, and prevent session fixation attacks.
Below is a safe client example that sends the CSRF token in a header. This assumes the client has already received the token from the server, e.g., in the response body.
1// Example of sending CSRF token safely in a header using fetch.
2// Assumes CSRF token was provided securely (e.g., via response body or meta tag).
3async function sendProtectedRequest(url: string, csrfToken: string) {
4 const res = await fetch(url, {
5 method: 'POST',
6 credentials: 'same-origin', // include cookies for same-site requests
7 headers: {
8 'Content-Type': 'application/json',
9 'X-CSRF-Token': csrfToken
10 },
11 body: JSON.stringify({ action: 'doSomething' })
12 });
13 return res;
14}- If you specify
credentials: 'same-origin', only cookies for the same origin are sent. On the server, validate the value of theX-CSRF-Tokenheader and verify that the token matches. If cross-site requests are necessary, configure CORS carefully.
Cross-site (CORS) and the relationship with credentials
To send and receive cookies in cross-origin communication, the client must specify credentials: 'include' and the server must set Access-Control-Allow-Credentials: true. However, restrict this configuration to trusted origins and do not use Access-Control-Allow-Origin: *.
1async function fetchCrossOriginData() {
2 // Example: cross-origin fetch sending cookies.
3 // Server must set Access-Control-Allow-Credentials: true
4 // and a specific trusted origin.
5 const res = await fetch('https://api.example.com/data', {
6 credentials: 'include', // send cookies only to trusted domains
7 method: 'GET'
8 });
9 return res;
10}- The combination of CORS and cookies is very delicate from a security perspective. Manage allowed origins strictly with a whitelist and avoid unnecessary cross-site communication. Also, when using
SameSite=None; Secure, enforce HTTPS to prevent man-in-the-middle attacks.
Example: secure session cookie settings with Express (TypeScript)
In practice, use Express, the cookie library, express-session, and so on. Below is a simple example using express and cookie-parser. In practice, set secure to true and manage the secret via environment variables.
1// Express example using cookie-parser and setting a secure httpOnly cookie.
2// npm install express cookie-parser @types/express @types/cookie-parser
3import express from 'express';
4import cookieParser from 'cookie-parser';
5
6const app = express();
7app.use(cookieParser(process.env.COOKIE_SECRET));
8
9app.post('/login', (req, res) => {
10 // authenticate user (omitted)
11 const sessionId = 'generated-session-id';
12 res.cookie('sid', sessionId, {
13 httpOnly: true,
14 secure: true, // require HTTPS in production
15 sameSite: 'lax',
16 maxAge: 1000 * 60 * 60 // 1 hour
17 });
18 res.json({ ok: true });
19});
20
21app.listen(3000);- By using
cookieParser'ssecretfeature, you can easily work with signed cookies. However, in real applications, from the perspectives of security and scalability, you should not store data directly in cookies; instead, use a dedicated session store.
Cookie prefixes __Host- and __Secure-
Browsers enforce special rules for certain prefixes.
- The
__Secure-prefix If a cookie name starts with__Secure-, theSecureattribute is required. - The
__Host-prefix If it starts with__Host-,Secureis required, the path must be/(root), andDomainmust not be set.
Using these reduces misconfiguration and improves security.
Cookie best practices
To handle Cookies securely, consider the following points.
- Do not store sensitive information directly in cookies. Prefer a server-side session ID for access tokens.
- Set session cookies with
HttpOnly,Secure, andSameSite=Lax(or Strict). - Leverage prefixes like
__Host-and__Secure-. - Consider signatures (HMAC) and encryption to prevent tampering and eavesdropping.
- Enable
Secureand require HTTPS. - Aim for least privilege and short expirations.
- Use CSRF tokens.
- Beware of differences in
SameSitebehavior across browsers, especially older ones.
Common misconceptions about cookies
Regarding cookies, be mindful of the following common misconceptions.
- 'Adding
HttpOnlyremoves the impact of XSS.' WhileHttpOnlyprevents cookies from being accessed by JavaScript, XSS can still be used to issue arbitrary requests. You should also employ CSRF token verification, CSP (Content Security Policy), and input sanitization. - '
Secureis unnecessary for local development.' Simulating HTTPS and verifying behavior even in local environments improves test accuracy. At a minimum, HTTPS should be used in staging and production environments. - 'Long expiration periods are convenient.' If you set long cookie lifetimes, the period during which they can be abused if stolen increases. You can set shorter expirations and incorporate periodic re-authentication and token rotation.
Summary
While cookies are easy to use, mishandling them can introduce security vulnerabilities. To manage them properly with TypeScript, it's important to understand attributes like HttpOnly, Secure, and SameSite, and enforce secure server-side settings. By not storing sensitive data directly and combining signatures with short expirations, you can achieve safe and reliable session management.
You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.