Skip to main content

@temelj/request

HTTP request utilities for working with cookies, including parsing, serialization, and encryption capabilities.

Installation

npm install @temelj/request

Overview

The @temelj/request package provides comprehensive utilities for handling HTTP cookies with support for:
  • Cookie parsing and serialization
  • Cookie encryption and decryption with password-based security
  • Cookie header manipulation
  • Full support for cookie attributes (secure, httpOnly, sameSite, etc.)
The core Cookie interface represents an HTTP cookie with all standard attributes:
interface Cookie {
  name: string;
  value: string;
  domain?: string;
  expires?: Date;
  httpOnly?: boolean;
  maxAge?: number;
  path?: string;
  priority?: "low" | "medium" | "high";
  sameSite?: "strict" | "lax" | "none";
  secure?: boolean;
  partitioned?: boolean;
  extra?: Record<string, string>;
}
Parse a Set-Cookie header value into a Cookie object:
import { parseCookie } from "@temelj/request";

const cookie = parseCookie(
  "test=42; Expires=Mon, 01 Jan 2024 00:00:00 GMT; Max-Age=42; Domain=example.com; Path=/; HttpOnly; SameSite=Lax; Priority=high; Partitioned;"
);

console.log(cookie);
// {
//   name: "test",
//   value: "42",
//   domain: "example.com",
//   expires: Date("2024-01-01"),
//   httpOnly: true,
//   maxAge: 42,
//   path: "/",
//   priority: "high",
//   sameSite: "lax",
//   partitioned: true
// }
parseCookie returns undefined if the cookie string is invalid.
Convert a Cookie object into a Set-Cookie header value:
import { serializeCookie, type Cookie } from "@temelj/request";

const cookie: Cookie = {
  name: "session",
  value: "abc123",
  domain: "example.com",
  expires: new Date("2024-01-01"),
  httpOnly: true,
  maxAge: 3600,
  path: "/",
  priority: "high",
  sameSite: "lax",
  secure: true,
  partitioned: true,
};

const headerValue = serializeCookie(cookie);
console.log(headerValue);
// "session=abc123; Expires=Mon, 01 Jan 2024 00:00:00 GMT; Max-Age=3600; Domain=example.com; Path=/; Secure; HttpOnly; SameSite=Lax; Priority=high;; Partitioned;"
Work with multiple cookies in Cookie headers:
import { parseCookieHeader } from "@temelj/request";

const cookies = parseCookieHeader("session=abc123; user=john");
console.log(cookies);
// [
//   { name: "session", value: "abc123" },
//   { name: "user", value: "john" }
// ]
Encrypt cookie values with password-based encryption for secure transmission:
import { encryptCookieValue } from "@temelj/request";

const password = "a".repeat(32); // Minimum 32 characters
const encrypted = await encryptCookieValue("sensitive-data", { password });

console.log(encrypted);
// "1|base64_iv|base64_salt|base64_encrypted|base64_signature|base64_sign_salt"
The password must be at least 32 characters long. An error will be thrown if the password is shorter.
import { decryptCookieValue } from "@temelj/request";

const password = "a".repeat(32);
const decrypted = await decryptCookieValue(encrypted, { password });

console.log(decrypted);
// "sensitive-data"
decryptCookieValue returns undefined if decryption fails due to invalid signature or wrong password.

Serialize and parse encrypted cookies

import { serializeEncryptedCookie } from "@temelj/request";

const cookie = await serializeEncryptedCookie(
  { name: "session", value: "secret-token" },
  { password: "a".repeat(32) }
);

console.log(cookie);
// "session=1|...|...|...|...|..."
// The value is encrypted and cannot be read without the password

Encryption options

Customize the encryption algorithm and parameters:
interface CookieEncryptionOptions {
  password: string;
  algorithm?: string; // Default: "AES-CBC"
  integrityAlgorithm?: string; // Default: "SHA-256"
  ivBits?: number; // Default: 128
  keyBits?: number; // Default: 256
  saltsBits?: number; // Default: 256
}

Example with custom options

import { encryptCookieValue } from "@temelj/request";

const encrypted = await encryptCookieValue("data", {
  password: "a".repeat(32),
  algorithm: "AES-CBC",
  integrityAlgorithm: "SHA-256",
  ivBits: 128,
  keyBits: 256,
  saltsBits: 256,
});

Complete example

Here’s a complete example showing cookie creation, encryption, and parsing:
import {
  serializeEncryptedCookie,
  parseEncryptedCookie,
  type Cookie,
} from "@temelj/request";

const password = "my-super-secret-password-32-chars-long";

// Create and encrypt a cookie
const cookie: Cookie = {
  name: "user_session",
  value: JSON.stringify({ userId: "123", token: "secret" }),
  domain: "example.com",
  path: "/",
  httpOnly: true,
  secure: true,
  sameSite: "strict",
  maxAge: 86400, // 24 hours
};

const setCookieHeader = await serializeEncryptedCookie(cookie, { password });

// Send this header to the client
console.log("Set-Cookie:", setCookieHeader);

// Later, parse the encrypted cookie from the client
const parsedCookie = await parseEncryptedCookie(setCookieHeader, { password });

if (parsedCookie) {
  const sessionData = JSON.parse(parsedCookie.value);
  console.log("User ID:", sessionData.userId);
}

Type exports

export interface Cookie {
  name: string;
  value: string;
  domain?: string;
  expires?: Date;
  httpOnly?: boolean;
  maxAge?: number;
  path?: string;
  priority?: "low" | "medium" | "high";
  sameSite?: "strict" | "lax" | "none";
  secure?: boolean;
  partitioned?: boolean;
  extra?: Record<string, string>;
}

export function parseCookie(source: string): Cookie | undefined;
export function serializeCookie(cookie: Cookie): string;

export function parseEncryptedCookie(
  source: string,
  options: CookieEncryptionOptions
): Promise<Cookie | undefined>;

export function serializeEncryptedCookie(
  cookie: Cookie,
  options: CookieEncryptionOptions
): Promise<string>;

export function parseCookieHeader(header: string): Cookie[];
export function serializeCookieHeader(cookies: Cookie[]): string;

export function encryptCookieValue(
  value: string,
  options: CookieEncryptionOptions
): Promise<string>;

export function decryptCookieValue(
  value: string,
  options: CookieEncryptionOptions
): Promise<string | undefined>;

Security considerations

Passwords must be at least 32 characters long to ensure adequate security. The package uses PBKDF2 for key derivation and HMAC for integrity checking.
The default encryption uses AES-CBC with 256-bit keys. The encrypted cookie value includes the IV, salt, encrypted data, and HMAC signature for integrity verification.
The package uses timingSafeEqual for signature comparison to prevent timing attacks when verifying encrypted cookies.
Always use HTTPS when transmitting cookies with the secure: true flag to prevent interception.

Build docs developers (and LLMs) love