or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-iron-session

Secure, stateless, and cookie-based session library for JavaScript

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/iron-session@8.0.x

To install, run

npx @tessl/cli install tessl/npm-iron-session@8.0.0

index.mddocs/

iron-session

iron-session is a secure, stateless, and cookie-based session library for JavaScript that provides encrypted session storage using signed cookies with @hapi/iron cryptography, eliminating the need for server-side session storage or external services.

Package Information

  • Package Name: iron-session
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install iron-session or pnpm add iron-session

Core Imports

import { getIronSession, sealData, unsealData, type IronSession, type SessionOptions } from "iron-session";

For CommonJS:

const { getIronSession, sealData, unsealData } = require("iron-session");

Basic Usage

import { getIronSession } from "iron-session";

// Next.js API Routes / Node.js Express
export async function handler(req, res) {
  const session = await getIronSession(req, res, {
    password: "complex_password_at_least_32_characters_long",
    cookieName: "myapp_cookiename",
  });
  
  // Read session data
  console.log(session.username);
  
  // Set session data
  session.username = "john_doe";
  session.isLoggedIn = true;
  
  // Save the session
  await session.save();
}

// Next.js App Router (Route Handlers, Server Components, Server Actions)
import { cookies } from "next/headers";

export async function GET() {
  const session = await getIronSession(cookies(), {
    password: "complex_password_at_least_32_characters_long", 
    cookieName: "myapp_cookiename",
  });
  
  return Response.json({ username: session.username });
}

Architecture

iron-session is built around several key components:

  • Stateless Design: Session data is stored entirely in encrypted cookies, requiring no server-side storage
  • Cryptographic Security: Uses @hapi/iron encryption with signed seals for data protection
  • Multi-Environment Support: Works with Node.js/Express, Next.js (Pages/App Router), and Web APIs
  • Password Rotation: Supports multiple passwords for seamless security updates
  • Type Safety: Full TypeScript integration with generic session data types

Capabilities

Session Management

Core session functionality for creating, reading, updating, and destroying encrypted cookie-based sessions.

/**
 * Creates an encrypted session from HTTP request/response objects (Node.js/Express)
 */
function getIronSession<T extends object>(
  req: IncomingMessage | Request,
  res: Response | ServerResponse,
  sessionOptions: SessionOptions
): Promise<IronSession<T>>;

/**
 * Creates an encrypted session from Next.js cookie store (App Router)
 */
function getIronSession<T extends object>(
  cookies: CookieStore,
  sessionOptions: SessionOptions
): Promise<IronSession<T>>;

Data Sealing and Unsealing

Direct encryption utilities for creating secure tokens and magic links without session cookies.

/**
 * Encrypts arbitrary data into a signed seal string
 */
function sealData(
  data: unknown,
  options: { password: Password; ttl?: number }
): Promise<string>;

/**
 * Decrypts a seal string back to original data
 */
function unsealData<T>(
  seal: string,
  options: { password: Password; ttl?: number }
): Promise<T>;

Usage Examples:

// Create a magic login link
const userId = 123;
const seal = await sealData(
  { userId, action: "login" }, 
  { password: "your_password", ttl: 3600 } // 1 hour
);
const magicLink = `https://yourapp.com/magic-login?token=${seal}`;

// Verify and use the magic link
const data = await unsealData(tokenFromUrl, {
  password: "your_password",
  ttl: 3600
});
console.log(data.userId); // 123

Types

Required Imports for Types

import type { IncomingMessage, ServerResponse } from "http";
import type { CookieSerializeOptions } from "cookie";

Session Object

type IronSession<T> = T & {
  /**
   * Encrypts the session data and sets the cookie.
   */
  readonly save: () => Promise<void>;

  /**
   * Destroys the session data and removes the cookie.
   */
  readonly destroy: () => void;

  /**
   * Update the session configuration. You still need to call save() to send the new cookie.
   */
  readonly updateConfig: (newSessionOptions: SessionOptions) => void;
};

Configuration Types

interface SessionOptions {
  /**
   * The cookie name that will be used inside the browser.
   * Make sure it's unique given your application.
   */
  cookieName: string;

  /**
   * The password(s) that will be used to encrypt the cookie.
   * Must be at least 32 characters long.
   * 
   * For password rotation, use an object with incrementing keys:
   * { 1: 'old-password', 2: 'new-password' }
   * The highest numbered key is used for new cookies.
   */
  password: Password;

  /**
   * Session validity time in seconds. Default: 1209600 (14 days)
   * ttl = 0 means no expiration
   */
  ttl?: number;

  /**
   * Additional cookie configuration options.
   * For session cookies (deleted when browser closes), use: { maxAge: undefined }
   */
  cookieOptions?: CookieOptions;
}

/**
 * Cookie store interface for Next.js cookies() API
 */
interface CookieStore {
  get: (name: string) => { name: string; value: string } | undefined;
  set: {
    (name: string, value: string, cookie?: Partial<ResponseCookie>): void;
    (options: ResponseCookie): void;
  };
}

/**
 * W3C CookieListItem specification with additional response properties
 */
interface ResponseCookie extends CookieListItem {
  httpOnly?: boolean;
  maxAge?: number;
  priority?: 'low' | 'medium' | 'high';
}

/**
 * CookieListItem as specified by W3C Cookie Store API
 */
interface CookieListItem {
  /** A string with the name of a cookie */
  name: string;
  /** A string containing the value of the cookie */
  value: string;
  /** A number of milliseconds or Date interface containing the expires of the cookie */
  expires?: Date | number;
  domain?: string;
  path?: string;
  sameSite?: 'strict' | 'lax' | 'none';
  secure?: boolean;
}

/**
 * Map of password IDs to password strings for rotation
 */
type PasswordsMap = Record<string, string>;

/**
 * Union type for password specification
 */
type Password = PasswordsMap | string;

/**
 * Cookie serialization options (excluding encode)
 */
type CookieOptions = Omit<CookieSerializeOptions, "encode">;

Default Configuration

/**
 * Default session options applied automatically
 */
const defaultOptions = {
  ttl: 1209600, // 14 days in seconds (fourteenDaysInSeconds)
  cookieOptions: {
    httpOnly: true,
    secure: true,
    sameSite: "lax",
    path: "/"
    // maxAge is computed dynamically as ttl - 60 (timestampSkewSec)
  }
};

Error Handling

iron-session performs validation and throws descriptive errors for common issues:

  • Password validation: "Password must be at least 32 characters long."
  • Cookie size limits: "Cookie length is too big (X bytes), browsers will refuse it. Try to remove some data."
  • Headers sent: "session.save() was called after headers were sent. Make sure to call it before any res.send() or res.end()"
  • Missing configuration: "Missing cookie name." or "Missing password."
  • Bad usage: "Bad usage: use getIronSession(req, res, options) or getIronSession(cookieStore, options)."
  • Invalid seals: Expired, corrupted, or tampered session data returns empty session (no error thrown)

Common Error Patterns:

try {
  const session = await getIronSession(req, res, {
    password: "short", // Error: Password too short
    cookieName: "app-session"
  });
} catch (error) {
  console.error(error.message); // "iron-session: Bad usage. Password must be at least 32 characters long."
}

// Expired/invalid sessions don't throw - they return empty objects
const session = await getIronSession(req, res, validOptions);
console.log(session.userId); // undefined if session expired/invalid

Environment Compatibility

Node.js / Express

import { getIronSession } from "iron-session";

app.get('/profile', async (req, res) => {
  const session = await getIronSession(req, res, sessionOptions);
  res.json({ user: session.user });
});

Next.js Pages Router

// pages/api/session.js
import { getIronSession } from "iron-session";

export default async function handler(req, res) {
  const session = await getIronSession(req, res, sessionOptions);
  // Use session...
}

Next.js App Router (Route Handlers)

// app/api/session/route.ts
import { cookies } from "next/headers";
import { getIronSession } from "iron-session";

export async function POST() {
  const session = await getIronSession(cookies(), sessionOptions);
  session.user = { id: 1, name: "John" };
  await session.save();
  return Response.json({ success: true });
}

Next.js App Router (Server Components)

// app/profile/page.tsx
import { cookies } from "next/headers";
import { getIronSession } from "iron-session";

async function ProfilePage() {
  const session = await getIronSession(cookies(), sessionOptions);
  
  if (!session.user) {
    return <div>Please log in</div>;
  }
  
  return <div>Welcome, {session.user.name}</div>;
}

Next.js App Router (Server Actions)

// app/login/actions.ts
"use server";
import { cookies } from "next/headers";
import { getIronSession } from "iron-session";

export async function loginAction(formData: FormData) {
  const session = await getIronSession(cookies(), sessionOptions);
  
  // Authenticate user...
  session.user = { id: userId, name: username };
  await session.save();
}

Security Features

  • Encryption: All session data is encrypted using @hapi/iron cryptography
  • Signing: Cookies are cryptographically signed to prevent tampering
  • Password Rotation: Support for multiple passwords enables seamless security updates
  • Time-based Validation: TTL (time-to-live) prevents replay attacks with expired tokens
  • Cookie Security: Secure defaults with httpOnly, secure, and sameSite attributes
  • Size Limits: Automatic validation against browser cookie size limits (4096 bytes)
  • Cross-platform Crypto: Uses uncrypto for consistent behavior across Node.js and browsers

Password Rotation Example

// Current configuration
const sessionOptions = {
  cookieName: "session",
  password: {
    1: "old_password_32_characters_minimum",
    2: "new_password_32_characters_minimum"  // This will be used for new sessions
  }
};

// iron-session will:
// - Use password ID 2 for encrypting new sessions
// - Accept both password IDs 1 and 2 for decrypting existing sessions
// - Allow gradual migration as old sessions expire