als-cookie v4.2.0
als-cookie
als-cookie
is a JavaScript library for managing cookies in both Node.js and browser environments, offering enhanced functionality and flexibility for modern applications.
Key Features
- Cross-Environment Support: Seamless cookie handling for both Node.js and browser environments.
- Flexible Management: Provides APIs to manage cookie settings dynamically with robust options validation.
- Integrated Options Handling: Includes
als-cookie-options
for reliable cookie options serialization. - Error Logging: Customizable error logging for better debugging.
- Ease of Use: Simple APIs for common operations like setting, getting, and removing cookies.
- Cookie Storage: A built-in lightweight storage mechanism synchronized between the client and server.
Change log for v4.2
Added Features
Custom Storage Key and Size Configuration
- You can now configure the storage key and maximum size for
cookie.store
using the static properties:Cookie.storageKey
- Sets the reserved key used for storing data incookie.store
. Default:'cookiestorage'
.Cookie.maxSize
- Sets the maximum size (in bytes) for the serialized storage. Default:2048
(2KB).
- You can now configure the storage key and maximum size for
Per-Item Options in
cookie.store
store.setItem(key, value, options)
now supports cookie-specific options such asmaxAge
,path
, etc.- Example:
cookie.store.setItem('theme', 'dark', { maxAge: 60 * 60, path: '/' });
Dynamic Default Path
- By default, when using
store.setItem()
, thepath
is now dynamically set to the currentpathname
(e.g.,/current/path
) instead of/
. This ensures that cookies are scoped to the current path unless otherwise specified.
- By default, when using
Error Handling Improvements
Graceful Error Handling in the Browser
- If
document.cookie
is inaccessible in the browser, the library now logs the error using the provided logger instead of throwing it. This prevents breaking the execution flow in restricted environments.
- If
Enhanced Parsing Error Logging
- Errors encountered during cookie parsing are no longer thrown but are instead logged via the configured logger, providing more robust error handling.
Code Improvements
- Code Refactoring and Optimization
- Minor improvements to code structure for better maintainability and performance.
Installation
Install the library for Node.js using npm:
npm install als-cookie
const Cookie = require('als-cookie')
const cookie = new Cookie()
For browser usage, include the minified version:
<script src="node-modules/als-cookie/cookie.min.js"></script>
or
<script src="node-modules/als-cookie/cookie.js"></script>
API Reference
Interface bellow describes api for NodeJS and Browser's Cookie class. Pay attention, some properties available only in NodeJS or Browser's version.
- For additional information:
- CookieOptions - als-cookie-options
- Crypt - als-crypt
class Cookie {
static prefix: string = 'secure:'; // Default prefix for encrypted cookies.
static cryptOptions: Crypt.Options = { ...Crypt.defaultOptions }; // Default cryptographic options for encryption and decryption.
static logger = console.error // Default function that logs or handles errors during cookie processing.
static cookieOptions = {}
static set storageKey(value) { CookieStore.storageKey = value }
static set maxSize(value) { CookieStore.maxSize = value }
static get storageKey() { return CookieStore.storageKey }
static get maxSize() { return CookieStore.maxSize }
/**
* Middleware for Express.js to attach `cookieManager` to the request object.
* 🚀 **Node.js only**
* @param options - Middleware options for cookie handling.
* @returns Middleware function for Express.js.
*/
static mw(options: {
cookieOptions?: CookieOptions; // Default cookie options to apply.
prefix?: string; // Prefix for encrypted cookie keys.
logger?: (error: Error) => void,// Logger function for error handling.
cryptOptions?: Crypt.Options; // Cryptographic options for encryption and decryption.
}): (req: Request, res: Response, next: NextFunction) => void
/**
* Constructor for Cookie.
* @param cookieOptions - Default cookie options.
* @param logger - Logger function for error handling.
*/
constructor(cookieOptions?: CookieOptions = Cookie.cookieOptions, logger?: LoggerFunction = Cookie.logger);
/**
* Enables encryption for cookie values with a specific prefix and options.
* 🚀 **Node.js only**
* @param prefix - The prefix to use for encrypted cookies.
* @param cryptOptions - Cryptographic options for encryption and decryption.
* @returns The current instance of the Cookie class.
* @throws Error if the prefix is invalid.
*/
encrypt(prefix: string = Cookie.prefix, cryptOptions: Crypt.Options = Cookie.cryptOptions): this;
/**
* Parses a cookie string into an object of key-value pairs.
* Decrypts values with the specified prefix if encryption is enabled.
*
* @param str - The cookie string to parse.
* @returns An object containing key-value pairs of parsed cookies.
*/
parse(str: string): Record<string, string>;
/**
* Serializes a cookie key-value pair into a cookie string.
* @param key - The name of the cookie.
* @param value - The value of the cookie.
* @param options - Cookie attributes (e.g., path, domain, maxAge).
* @param req - Optional request object for context.
* @returns A string formatted as a valid cookie header.
*/
serialize( key: string, value: string, options?: CookieOptions, req?: Request ): string;
/**
* Creates a new `CookieRequest` instance for managing cookies
* in the current request-response cycle.
* 🚀 **Node.js only**
* @param req - The HTTP request object.
* @param res - The HTTP response object.
* @returns An instance of `CookieRequest`.
*/
request(req: Request, res: Response): CookieRequest
// 🌐 **Browser only**:
/**
* Sets a cookie in document.cookie.
*
* @param key - The cookie name.
* @param value - The cookie value.
* @param options - Cookie options.
* @returns The current instance of Cookie.
*/
setItem(key: string, value: string, options?: CookieOptions): this;
/**
* Removes a cookie from document.cookie.
*
* @param key - The cookie name.
* @param options - Cookie options.
* @returns The current instance of CookieRequest for chaining.
*/
removeItem(key: string, options?: CookieOptions): this;
// Retrieves all cookies from document.cookie.
getAll(): Record<string, string | { value: string; options: CookieOptions }>;
/**
* Retrieves a specific cookie value by its name.
*
* @param key - The cookie name.
* @returns The cookie value or `undefined` if not found.
*/
getItem(key: string): string | undefined;
removeAll(options={}): this // removes all cookies in document.cookie by options
}
interface CookieOptions {
domain?: string; // Specifies the domain for the cookie.
path?: string; // Specifies the path for the cookie.
expires?: Date; // Specifies the expiration date of the cookie.
maxAge?: number; // Specifies the number of seconds until the cookie expires.
httpOnly?: boolean; // Specifies whether the cookie is HTTP-only. (Node.js only)
secure?: boolean; // Ensures the cookie is sent only over HTTPS. Ignored in non-secure environments.
partitioned?: boolean; // Specifies whether the cookie is partitioned (experimental).
priority?: 'low' | 'medium' | 'high'; // Specifies the priority of the cookie (`low`, `medium`, `high`).
sameSite?: 'strict' | 'lax' | 'none'; // Specifies the SameSite attribute of the cookie (`strict`, `lax`, `none`).
[key: string]: any;
}
// CookieRequest class for managing cookies in an HTTP request-response cycle.
class CookieRequest {
private req: Request; // The HTTP request object.
private res: Response; // The HTTP response object.
private cookie: Cookie; // Instance of the Cookie class for managing cookie serialization and parsing.
private _reqCookies: Record<string, string> | null; // Cached cookies parsed from `req.headers.cookie`.
/**
* Constructs a new CookieRequest instance.
*
* @param cookie - Instance of the Cookie class.
* @param req - The HTTP request object.
* @param res - The HTTP response object.
*/
constructor(cookie: Cookie, req: Request, res: Response);
/**
* Getter for cookies parsed from the request headers (`req.headers.cookie`).
*
* @returns Parsed cookies as an object of key-value pairs.
*/
get reqCookies(): Record<string, string>;
/**
* Getter for cookies currently set in the response (`res.getHeader('Set-Cookie')`).
*
* @returns Array of currently set cookies.
*/
get cookies(): string[];
/**
* Sets a cookie in the response.
*
* @param key - The cookie name.
* @param value - The cookie value.
* @param options - Cookie options.
* @returns The current instance of CookieRequest for chaining.
*/
setCookie(key: string, value: string, options?: CookieOptions): this;
setItem(key: string, value: string, options?: CookieOptions): this; // Alias for `setCookie` method.
/**
* Removes a cookie from the response.
*
* @param key - The cookie name.
* @param options - Cookie options.
* @returns The current instance of CookieRequest for chaining.
*/
removeCookie(key: string, options?: CookieOptions): this;
removeItem(key: string, options?: CookieOptions): this; // Alias for `removeCookie` method.
/**
* Retrieves all cookies from both the request and response.
*
* @param withOptions - If true, includes options for each cookie.
* @returns An object of all cookies, optionally including options.
*/
getAll(withOptions?: boolean): Record<string, string | { value: string; options: CookieOptions }>;
/**
* Retrieves a specific cookie value by its name.
*
* @param key - The cookie name.
* @returns The cookie value or `undefined` if not found.
*/
getItem(key: string): string | undefined;
}
Examples
Node.js Example
The middleware integrates seamlessly with Node.js applications to enhance cookie handling.
const express = require("express");
const Cookie = require("als-cookie");
const app = express();
app.use(Cookie.mw({ prefix: "s:", logger: console.error }));
app.get("/", (req, res) => {
res.cookieManager.setCookie("user", "JohnDoe", { httpOnly: true });
res.end("Cookie set");
});
app.listen(3000, () => console.log('Server running on port 3000'));
Examples for methods:
serialize and parse:
const cookie = new Cookie();
const cookieString = cookie.serialize('session', 'abc123', { httpOnly: true });
console.log(cookieString); // "session=abc123; HttpOnly"
const parsedCookies = cookie.parse('session=abc123; theme=dark');
console.log(parsedCookies); // { session: 'abc123', theme: 'dark' }
getAll and getItem:
const request = cookie.request(req, res);
request.setCookie('user', 'JohnDoe', { path: '/' });
console.log(request.getAll()); // { user: 'JohnDoe' }
console.log(request.getItem('user')); // 'JohnDoe'
setItem and removeItem:
cookie.setItem('theme', 'dark', { path: '/' });
cookie.removeItem('theme', { path: '/' });
console.log(cookie.getItem('theme')); // undefined
Browser Example
const cookie = new Cookie()
cookie.setItem('theme', 'dark', { path: '/', maxAge: 3600 });
const theme = cookie.getItem('theme');
console.log(theme); // 'dark'
cookie.removeItem('theme', { path: '/' });
Encryption
als-cookie
supports cookie's value encryption with als-crypt
const cookie = new Cookie().encrypt('s:')
const request = cookie.request(req,res)
request.setCookie('s:user','JohnDoeEncrypted')
console.log(res.getHeader('Set-Cookie'))
// s:user=badf059f3d8b2eaa30eaafbfcfef76ef:fcd035b3117811e20beb353c6647a10879feb747921a6c0cb65247701128eb99
request.getItem('s:user') // JohnDoeEncrypted
Auth example
This example demonstrates how to use als-cookie to implement a simple cookie-based authentication mechanism. The setup includes three main routes: a home page (/), a login page (/login), and a logout page (/logout). Below is a detailed breakdown:
const http = require('http')
const Cookie = require('als-cookie')
const layout = (inner, title) => /*html*/`<!DOCTYPE html>
<html>
<head><title>${title}</title></head>
<body>${inner}</body>
</html>`
const redirect = layout(/*html*/`<meta http-equiv="refresh" content="3; url=/">
<p>If not redirected <a href="/">click here</a>.</p>
`, 'Redirecting...')
const routes = {
'/': (req, res) => {
const user = req.cookieManager.reqCookies['s:user']
const content = user
? /*html*/`<div>Hello ${user}</div><div><a href="/logout">Logout</a></div>`
: /*html*/`<div>You are not logged in</div><div><a href="/login">Login</a></div>`
res.end(layout(content, 'Test Cookie'))
},
'/logout': (req, res) => {
req.cookieManager.removeCookie('s:user')
res.end(redirect)
},
'/login': (req, res) => {
const cookieOptions = { httpOnly: true, maxAge: 1000 * 60 * 60 * 24 * 7, sameSite: 'Strict', secure: true }
req.cookieManager.setCookie('s:user', 'Alex', cookieOptions)
res.end(redirect)
}
}
const server = http.createServer((req, res) => {
const mw = Cookie.mw({ prefix: 's:', logger: console.error });
mw(req, res, () => { routes[req.url] ? routes[req.url](req, res) : res.end(layout('404')) });
})
server.listen(3000)
Cookie Storage (cookieStorage
)
als-cookie
provides a convenient cookieStorage
implementation, similar to localStorage
, but synchronized between the client and server via cookies. This storage is designed for lightweight usage and is ideal for shared data, such as user preferences or small session states.
Key Features
- 2KB Storage Limit: The
cookieStorage
is limited to 2KB, as the remaining cookie space is reserved for authentication or other cookies. - Automatic Serialization: You can store objects directly in the storage, and they will automatically be serialized and deserialized as JSON strings.
- Shared Storage: The
cookieStorage
works seamlessly across the client and server, allowing you to synchronize small data between the browser and backend. - Reserved Key: The storage is implemented under a single reserved key,
cookiestorage
. Avoid using this key for other purposes.
Browser Example
const cookie = new Cookie();
// Set items in cookieStorage
cookie.store.setItem('theme', 'dark');
cookie.store.setItem('language', 'en');
// Get stored values
console.log(cookie.store.getItem('theme')); // 'dark'
// Remove an item
cookie.store.removeItem('theme');
console.log(cookie.store.getItem('theme')); // undefined
// Clear the storage
cookie.store.clear();
console.log(cookie.store.getItem('language')); // undefined
Node.js Example
const cookie = new Cookie();
const request = cookie.request(req, res);
request.store.setItem('session', 'active');
Express with middleware example:
const http = require('http');
const Cookie = require('als-cookie');
http.createServer((req, res) => {
// Attach middleware
const mw = Cookie.mw({ prefix: 's:', logger: console.error });
mw(req, res, () => {
const store = req.cookieManager.store;
// Set and retrieve a value
store.setItem('session', 'active');
console.log(store.getItem('session')); // 'active'
// Remove the value
store.removeItem('session');
// Respond to the client
res.end('Cookie storage updated');
});
}).listen(3000);
Methods
getItem(key: string): string | undefined
Retrieves the value associated with the given key. If the key is not found, returns undefined
.
Example:
cookie.store.setItem('theme', 'dark');
console.log(cookie.store.getItem('theme')); // 'dark'
setItem(key: string, value: any): void
Stores a value under the specified key. The value can be any JSON-compatible object, as it is automatically serialized.
Example:
cookie.store.setItem('user', { name: 'John', age: 30 });
console.log(cookie.store.getItem('user')); // { name: 'John', age: 30 }
removeItem(key: string): void
Deletes the specified key and its value from the storage.
Example:
cookie.store.setItem('theme', 'dark');
cookie.store.removeItem('theme');
console.log(cookie.store.getItem('theme')); // undefined
clear(): void
Removes all keys and values from the storage.
Example:
cookie.store.setItem('theme', 'dark');
cookie.store.setItem('language', 'en');
cookie.store.clear();
console.log(cookie.store.getItem('theme')); // undefined
Notes
- The storage is limited to 2KB. Attempting to store data beyond this limit will throw an error:
"Maximum limit exceeded."
- Data is serialized and stored under the reserved key
cookiestorage
. Avoid manually modifying this key to prevent conflicts. cookieStorage
is not suitable for large or sensitive data. For more advanced use cases, consider alternative storage solutions.