cookie
js/security/cookie.ts
fino:security/cookie - cookie serialization, parsing, signing, and sealing.
HTTP cookie specification: https://www.rfc-editor.org/rfc/rfc6265
Use this module for HTTP cookie values that need browser-compatible attributes or tamper-evident storage. Plain serialization and parsing handle request and response header syntax. Signing appends an HMAC so the original value can be recovered only when it has not been modified. Sealing encrypts and authenticates the value for cookies that must not be readable by clients.
The helpers do not implement session storage or key rotation. Applications should store secrets outside source code, rotate them deliberately, and avoid putting large or highly sensitive payloads in cookies.
import {
serializeCookie,
signCookie,
verifyCookie,
} from 'fino:security/cookie';
const signed = signCookie('user-123', sessionSecret);
const header = serializeCookie('sid', signed, {
path: '/',
httpOnly: true,
secure: true,
sameSite: 'Lax',
});
const value = verifyCookie(signed, sessionSecret);
Types
type BufferLike = SecurityBufferLike
Byte-oriented secret input accepted by cookie signing and sealing helpers.
Strings are encoded as UTF-8. Uint8Array, ArrayBuffer, and other
ArrayBufferView values are read as bytes.
Interfaces
interface CookieOptions {
Options used when serializing a single Set-Cookie header value.
Attributes are emitted only when provided or set to true. Values are not
validated for header injection, browser prefix rules, finite expiration
values, and SameSite=None / Secure coupling. Callers should still pass
trusted domain, path, and policy strings.
import type { CookieOptions } from 'fino:security/cookie';
const options: CookieOptions = {
path: '/',
httpOnly: true,
secure: true,
sameSite: 'Lax',
};
Properties
domain?: string
Optional Domain attribute.
Omit it to create a host-only cookie. The value is emitted unchanged.
import type { CookieOptions } from 'fino:security/cookie';
const options: CookieOptions = { domain: 'example.com' };
path?: string
Optional Path attribute.
Defaults to no emitted path attribute; many applications pass /.
import type { CookieOptions } from 'fino:security/cookie';
const options: CookieOptions = { path: '/' };
expires?: Date
Optional absolute expiration time.
When provided, it is formatted with Date.prototype.toUTCString().
import type { CookieOptions } from 'fino:security/cookie';
const options: CookieOptions = { expires: new Date(Date.now() + 3600_000) };
maxAge?: number
Optional Max-Age value in seconds.
The value is floored before serialization. Pass 0 to expire the cookie.
import type { CookieOptions } from 'fino:security/cookie';
const options: CookieOptions = { maxAge: 3600 };
httpOnly?: boolean
Whether to emit the HttpOnly attribute.
Defaults to omitted. Enable it for cookies that client-side scripts should not read.
import type { CookieOptions } from 'fino:security/cookie';
const options: CookieOptions = { httpOnly: true };
secure?: boolean
Whether to emit the Secure attribute.
Defaults to omitted. Enable it for cookies that should only be sent over
HTTPS, and when using SameSite=None.
import type { CookieOptions } from 'fino:security/cookie';
const options: CookieOptions = { secure: true };
sameSite?: 'Strict' | 'Lax' | 'None'
Optional SameSite policy.
Defaults to omitted. Use None only with secure: true for browser
compatibility.
import type { CookieOptions } from 'fino:security/cookie';
const options: CookieOptions = { sameSite: 'Lax' };
Functions
function serializeCookie(name: string, value: string, options: CookieOptions = {}): string
Serialize one Set-Cookie header value, URI-encoding the cookie value.
The cookie name must use valid token characters or the function throws
Error. The value is encoded with encodeURIComponent(). Expiration
attributes must be finite, SameSite=None requires secure: true, and the
__Secure- / __Host- prefixes enforce browser-compatible constraints.
import { serializeCookie } from 'fino:security/cookie';
const header = serializeCookie('sid', 'abc123', {
path: '/',
httpOnly: true,
secure: true,
});
function parseCookieHeader(header: string): Record<string, string>
Parse a Cookie request header into a plain object.
Malformed segments without = are skipped. Names are trimmed; values are
URI-decoded with decodeURIComponent(), so malformed percent escapes throw.
Later duplicate cookie names overwrite earlier values.
import { parseCookieHeader } from 'fino:security/cookie';
const cookies = parseCookieHeader('sid=abc; theme=dark');
function signCookie(value: string, secret: BufferLike): string
Sign a cookie value with HMAC-SHA-256 and return payload.signature.
The payload is base64url-encoded UTF-8 text, and the signature covers the encoded payload. This authenticates but does not encrypt the cookie value.
import { signCookie } from 'fino:security/cookie';
const signed = signCookie('user-123', 'secret');
function verifyCookie(signed: string, secret: BufferLike): string | null
Verify a signed cookie value and return the original UTF-8 value.
Returns null when the token is malformed, the signature does not match, or
the payload cannot be decoded. Signature comparison is timing-safe. This does
not check expiration; store and verify any expiry in the signed payload.
import { signCookie, verifyCookie } from 'fino:security/cookie';
const signed = signCookie('user-123', 'secret');
const value = verifyCookie(signed, 'secret');
function sealCookie(value: string, secret: BufferLike): string
Encrypt and authenticate a cookie value using AES-256-GCM and a random IV.
The secret is normalized to a 32-byte key. The returned v1.iv.ciphertext.tag
value hides the plaintext and detects tampering. A fresh 96-bit IV is used
for each seal operation.
import { sealCookie } from 'fino:security/cookie';
const sealed = sealCookie(JSON.stringify({ sub: 'user-123' }), 'secret');
function unsealCookie(sealed: string, secret: BufferLike): string | null
Decrypt a sealed cookie value and return the original UTF-8 string.
Returns null for unsupported versions, malformed parts, decode failures, or
AES-GCM authentication failures. This authenticates and decrypts the value but
does not enforce expiration unless you include one in the plaintext.
import { sealCookie, unsealCookie } from 'fino:security/cookie';
const sealed = sealCookie('user-123', 'secret');
const value = unsealCookie(sealed, 'secret');
Classes
class CookieJar {
Mutable cookie jar populated from a request Cookie header.
Queue cookie changes with set() or delete(). Framework integrations can
call _apply() to append queued Set-Cookie headers to a response. The jar
also updates its in-memory values immediately, so handlers can read their own
writes during a request.
import { CookieJar } from 'fino:security/cookie';
const jar = new CookieJar('sid=123');
jar.set('theme', 'dark', { path: '/' });
console.log(jar.get('theme'));
Constructors
constructor(header: string | null)
Parse a Cookie header into a mutable jar.
null creates an empty jar. Parsing uses parseCookieHeader(), including
its URI-decoding behavior for cookie values.
const jar = new CookieJar(request.headers.get('cookie'));
Methods
get(name: string): string | undefined
Read one cookie value from the current jar state.
Returns undefined when the cookie was not present or has been deleted
locally.
const sid = jar.get('sid');
all(): Record<string, string>
Return all current cookie values as a plain object copy.
const values = jar.all();
set(name: string, value: string, options: CookieOptions = {}): void
Queue a Set-Cookie header and update this jar's current value.
Cookie options are passed to serializeCookie().
jar.set('sid', session.id, { httpOnly: true, path: '/' });
delete(name: string, options: CookieOptions = {}): void
Queue an expired Set-Cookie header and remove this jar's current value.
jar.delete('sid', { path: '/' });