0
# iron-session
1
2
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.
3
4
## Package Information
5
6
- **Package Name**: iron-session
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install iron-session` or `pnpm add iron-session`
10
11
## Core Imports
12
13
```typescript
14
import { getIronSession, sealData, unsealData, type IronSession, type SessionOptions } from "iron-session";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const { getIronSession, sealData, unsealData } = require("iron-session");
21
```
22
23
## Basic Usage
24
25
```typescript
26
import { getIronSession } from "iron-session";
27
28
// Next.js API Routes / Node.js Express
29
export async function handler(req, res) {
30
const session = await getIronSession(req, res, {
31
password: "complex_password_at_least_32_characters_long",
32
cookieName: "myapp_cookiename",
33
});
34
35
// Read session data
36
console.log(session.username);
37
38
// Set session data
39
session.username = "john_doe";
40
session.isLoggedIn = true;
41
42
// Save the session
43
await session.save();
44
}
45
46
// Next.js App Router (Route Handlers, Server Components, Server Actions)
47
import { cookies } from "next/headers";
48
49
export async function GET() {
50
const session = await getIronSession(cookies(), {
51
password: "complex_password_at_least_32_characters_long",
52
cookieName: "myapp_cookiename",
53
});
54
55
return Response.json({ username: session.username });
56
}
57
```
58
59
## Architecture
60
61
iron-session is built around several key components:
62
63
- **Stateless Design**: Session data is stored entirely in encrypted cookies, requiring no server-side storage
64
- **Cryptographic Security**: Uses @hapi/iron encryption with signed seals for data protection
65
- **Multi-Environment Support**: Works with Node.js/Express, Next.js (Pages/App Router), and Web APIs
66
- **Password Rotation**: Supports multiple passwords for seamless security updates
67
- **Type Safety**: Full TypeScript integration with generic session data types
68
69
## Capabilities
70
71
### Session Management
72
73
Core session functionality for creating, reading, updating, and destroying encrypted cookie-based sessions.
74
75
```typescript { .api }
76
/**
77
* Creates an encrypted session from HTTP request/response objects (Node.js/Express)
78
*/
79
function getIronSession<T extends object>(
80
req: IncomingMessage | Request,
81
res: Response | ServerResponse,
82
sessionOptions: SessionOptions
83
): Promise<IronSession<T>>;
84
85
/**
86
* Creates an encrypted session from Next.js cookie store (App Router)
87
*/
88
function getIronSession<T extends object>(
89
cookies: CookieStore,
90
sessionOptions: SessionOptions
91
): Promise<IronSession<T>>;
92
```
93
94
### Data Sealing and Unsealing
95
96
Direct encryption utilities for creating secure tokens and magic links without session cookies.
97
98
```typescript { .api }
99
/**
100
* Encrypts arbitrary data into a signed seal string
101
*/
102
function sealData(
103
data: unknown,
104
options: { password: Password; ttl?: number }
105
): Promise<string>;
106
107
/**
108
* Decrypts a seal string back to original data
109
*/
110
function unsealData<T>(
111
seal: string,
112
options: { password: Password; ttl?: number }
113
): Promise<T>;
114
```
115
116
**Usage Examples:**
117
118
```typescript
119
// Create a magic login link
120
const userId = 123;
121
const seal = await sealData(
122
{ userId, action: "login" },
123
{ password: "your_password", ttl: 3600 } // 1 hour
124
);
125
const magicLink = `https://yourapp.com/magic-login?token=${seal}`;
126
127
// Verify and use the magic link
128
const data = await unsealData(tokenFromUrl, {
129
password: "your_password",
130
ttl: 3600
131
});
132
console.log(data.userId); // 123
133
```
134
135
## Types
136
137
### Required Imports for Types
138
139
```typescript { .api }
140
import type { IncomingMessage, ServerResponse } from "http";
141
import type { CookieSerializeOptions } from "cookie";
142
```
143
144
### Session Object
145
146
```typescript { .api }
147
type IronSession<T> = T & {
148
/**
149
* Encrypts the session data and sets the cookie.
150
*/
151
readonly save: () => Promise<void>;
152
153
/**
154
* Destroys the session data and removes the cookie.
155
*/
156
readonly destroy: () => void;
157
158
/**
159
* Update the session configuration. You still need to call save() to send the new cookie.
160
*/
161
readonly updateConfig: (newSessionOptions: SessionOptions) => void;
162
};
163
```
164
165
### Configuration Types
166
167
```typescript { .api }
168
interface SessionOptions {
169
/**
170
* The cookie name that will be used inside the browser.
171
* Make sure it's unique given your application.
172
*/
173
cookieName: string;
174
175
/**
176
* The password(s) that will be used to encrypt the cookie.
177
* Must be at least 32 characters long.
178
*
179
* For password rotation, use an object with incrementing keys:
180
* { 1: 'old-password', 2: 'new-password' }
181
* The highest numbered key is used for new cookies.
182
*/
183
password: Password;
184
185
/**
186
* Session validity time in seconds. Default: 1209600 (14 days)
187
* ttl = 0 means no expiration
188
*/
189
ttl?: number;
190
191
/**
192
* Additional cookie configuration options.
193
* For session cookies (deleted when browser closes), use: { maxAge: undefined }
194
*/
195
cookieOptions?: CookieOptions;
196
}
197
198
/**
199
* Cookie store interface for Next.js cookies() API
200
*/
201
interface CookieStore {
202
get: (name: string) => { name: string; value: string } | undefined;
203
set: {
204
(name: string, value: string, cookie?: Partial<ResponseCookie>): void;
205
(options: ResponseCookie): void;
206
};
207
}
208
209
/**
210
* W3C CookieListItem specification with additional response properties
211
*/
212
interface ResponseCookie extends CookieListItem {
213
httpOnly?: boolean;
214
maxAge?: number;
215
priority?: 'low' | 'medium' | 'high';
216
}
217
218
/**
219
* CookieListItem as specified by W3C Cookie Store API
220
*/
221
interface CookieListItem {
222
/** A string with the name of a cookie */
223
name: string;
224
/** A string containing the value of the cookie */
225
value: string;
226
/** A number of milliseconds or Date interface containing the expires of the cookie */
227
expires?: Date | number;
228
domain?: string;
229
path?: string;
230
sameSite?: 'strict' | 'lax' | 'none';
231
secure?: boolean;
232
}
233
234
/**
235
* Map of password IDs to password strings for rotation
236
*/
237
type PasswordsMap = Record<string, string>;
238
239
/**
240
* Union type for password specification
241
*/
242
type Password = PasswordsMap | string;
243
244
/**
245
* Cookie serialization options (excluding encode)
246
*/
247
type CookieOptions = Omit<CookieSerializeOptions, "encode">;
248
```
249
250
## Default Configuration
251
252
```typescript { .api }
253
/**
254
* Default session options applied automatically
255
*/
256
const defaultOptions = {
257
ttl: 1209600, // 14 days in seconds (fourteenDaysInSeconds)
258
cookieOptions: {
259
httpOnly: true,
260
secure: true,
261
sameSite: "lax",
262
path: "/"
263
// maxAge is computed dynamically as ttl - 60 (timestampSkewSec)
264
}
265
};
266
```
267
268
## Error Handling
269
270
iron-session performs validation and throws descriptive errors for common issues:
271
272
- **Password validation**: "Password must be at least 32 characters long."
273
- **Cookie size limits**: "Cookie length is too big (X bytes), browsers will refuse it. Try to remove some data."
274
- **Headers sent**: "session.save() was called after headers were sent. Make sure to call it before any res.send() or res.end()"
275
- **Missing configuration**: "Missing cookie name." or "Missing password."
276
- **Bad usage**: "Bad usage: use getIronSession(req, res, options) or getIronSession(cookieStore, options)."
277
- **Invalid seals**: Expired, corrupted, or tampered session data returns empty session (no error thrown)
278
279
**Common Error Patterns:**
280
281
```typescript
282
try {
283
const session = await getIronSession(req, res, {
284
password: "short", // Error: Password too short
285
cookieName: "app-session"
286
});
287
} catch (error) {
288
console.error(error.message); // "iron-session: Bad usage. Password must be at least 32 characters long."
289
}
290
291
// Expired/invalid sessions don't throw - they return empty objects
292
const session = await getIronSession(req, res, validOptions);
293
console.log(session.userId); // undefined if session expired/invalid
294
```
295
296
## Environment Compatibility
297
298
### Node.js / Express
299
300
```typescript
301
import { getIronSession } from "iron-session";
302
303
app.get('/profile', async (req, res) => {
304
const session = await getIronSession(req, res, sessionOptions);
305
res.json({ user: session.user });
306
});
307
```
308
309
### Next.js Pages Router
310
311
```typescript
312
// pages/api/session.js
313
import { getIronSession } from "iron-session";
314
315
export default async function handler(req, res) {
316
const session = await getIronSession(req, res, sessionOptions);
317
// Use session...
318
}
319
```
320
321
### Next.js App Router (Route Handlers)
322
323
```typescript
324
// app/api/session/route.ts
325
import { cookies } from "next/headers";
326
import { getIronSession } from "iron-session";
327
328
export async function POST() {
329
const session = await getIronSession(cookies(), sessionOptions);
330
session.user = { id: 1, name: "John" };
331
await session.save();
332
return Response.json({ success: true });
333
}
334
```
335
336
### Next.js App Router (Server Components)
337
338
```typescript
339
// app/profile/page.tsx
340
import { cookies } from "next/headers";
341
import { getIronSession } from "iron-session";
342
343
async function ProfilePage() {
344
const session = await getIronSession(cookies(), sessionOptions);
345
346
if (!session.user) {
347
return <div>Please log in</div>;
348
}
349
350
return <div>Welcome, {session.user.name}</div>;
351
}
352
```
353
354
### Next.js App Router (Server Actions)
355
356
```typescript
357
// app/login/actions.ts
358
"use server";
359
import { cookies } from "next/headers";
360
import { getIronSession } from "iron-session";
361
362
export async function loginAction(formData: FormData) {
363
const session = await getIronSession(cookies(), sessionOptions);
364
365
// Authenticate user...
366
session.user = { id: userId, name: username };
367
await session.save();
368
}
369
```
370
371
## Security Features
372
373
- **Encryption**: All session data is encrypted using @hapi/iron cryptography
374
- **Signing**: Cookies are cryptographically signed to prevent tampering
375
- **Password Rotation**: Support for multiple passwords enables seamless security updates
376
- **Time-based Validation**: TTL (time-to-live) prevents replay attacks with expired tokens
377
- **Cookie Security**: Secure defaults with httpOnly, secure, and sameSite attributes
378
- **Size Limits**: Automatic validation against browser cookie size limits (4096 bytes)
379
- **Cross-platform Crypto**: Uses uncrypto for consistent behavior across Node.js and browsers
380
381
## Password Rotation Example
382
383
```typescript
384
// Current configuration
385
const sessionOptions = {
386
cookieName: "session",
387
password: {
388
1: "old_password_32_characters_minimum",
389
2: "new_password_32_characters_minimum" // This will be used for new sessions
390
}
391
};
392
393
// iron-session will:
394
// - Use password ID 2 for encrypting new sessions
395
// - Accept both password IDs 1 and 2 for decrypting existing sessions
396
// - Allow gradual migration as old sessions expire
397
```