iron-session 8.0.0-beta.5 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,477 +1,186 @@
1
- # iron-session
1
+ # iron-session [![GitHub license](https://img.shields.io/github/license/vvo/iron-session?style=flat)](https://github.com/vvo/iron-session/blob/master/LICENSE) [![npm](https://img.shields.io/npm/v/iron-session)](https://www.npmjs.com/package/iron-session) [![Downloads](https://img.shields.io/npm/dm/next-iron-session.svg)](http://npm-stat.com/charts.html?package=iron-session)
2
2
 
3
- A runtime-agnostic stateless session utility. Works with Next.js, Node.js, Deno,
4
- Bun, and more.
3
+ **`iron-session` is a secure, stateless, and cookie-based session library for JavaScript.**
5
4
 
6
- The session data is stored in signed and encrypted cookies ("seals") which can
7
- only be decoded by your server. There are no session ids, making sessions
8
- "stateless" from the server point of view. This strategy of storing session data
9
- is the same technique used by frameworks like
5
+ <p align="center">Online demo: <a href="https://get-iron-session.vercel.app/">https://get-iron-session.vercel.app</a> 👀</p>
6
+
7
+ The session data is stored in signed and encrypted cookies which are decoded by your server code in a stateless fashion (= no network involved). This is the same technique used by frameworks like
10
8
  [Ruby On Rails](https://guides.rubyonrails.org/security.html#session-storage).
11
9
 
12
- ## Table of Contents
10
+ <p align="center"><i>⭐️ Featured in the <a href="https://nextjs.org/docs/authentication">Next.js documentation</a></i></p>
13
11
 
14
- <!-- - [Features](#features) -->
12
+ ## Table of Contents
15
13
 
14
+ - [Table of Contents](#table-of-contents)
16
15
  - [Installation](#installation)
17
16
  - [Usage](#usage)
18
- - [Options Definitions](#options-definitions)
17
+ - [Examples](#examples)
18
+ - [Project status](#project-status)
19
+ - [Session options](#session-options)
19
20
  - [API](#api)
20
- - [Iron Session Object](#iron-session-object)
21
- - [Functions](#iron-session-functions)
22
- - [Options](#iron-session-options)
23
- - [Example](#nextjs-example)
21
+ - [`getIronSession<T>(req, res, sessionOptions): Promise<IronSession<T>>`](#getironsessiontreq-res-sessionoptions-promiseironsessiont)
22
+ - [`getIronSession<T>(cookieStore, sessionOptions): Promise<IronSession<T>>`](#getironsessiontcookiestore-sessionoptions-promiseironsessiont)
23
+ - [`session.save(): Promise<void>`](#sessionsave-promisevoid)
24
+ - [`session.destroy(): void`](#sessiondestroy-void)
25
+ - [`sealData(data: unknown, { password, ttl }): Promise<string>`](#sealdatadata-unknown--password-ttl--promisestring)
26
+ - [`unSealData<T>(seal: string, { password, ttl }): Promise<T>`](#unsealdatatseal-string--password-ttl--promiset)
24
27
  - [FAQ](#faq)
25
- <!-- - [Contributing](#contributing) -->
26
- <!-- - [License](#license) -->
28
+ - [Why use pure cookies for sessions?](#why-use-pure-cookies-for-sessions)
29
+ - [How to invalidate sessions?](#how-to-invalidate-sessions)
30
+ - [Can I use something else than cookies?](#can-i-use-something-else-than-cookies)
31
+ - [How is this different from JWT?](#how-is-this-different-from-jwt)
27
32
  - [Credits](#credits)
28
33
  - [Good Reads](#good-reads)
29
34
 
30
35
  ## Installation
31
36
 
32
37
  ```sh
33
- npm add iron-session
34
- ```
35
-
36
- Change the package manager to whatever you use, of course. On Deno, you can use
37
- [esm.sh](https://esm.sh/):
38
-
39
- ```js
40
- import { getIronSession } from 'https://esm.sh/iron-session@latest'
38
+ pnpm add iron-session
41
39
  ```
42
40
 
43
41
  ## Usage
44
42
 
45
- Refer to the [examples](examples).
43
+ To get a session, there's a single method to know: `getIronSession`.
46
44
 
47
- 1. Define your session options
48
- 1. Initialize your session with:
49
- - sessionOptions and the respective parameters
50
- - the type definition of your session data
51
- 1. Set the session data variables
52
- 1. Set the data to or read the data from the browser cookie storage
53
- - session.save(): Set the session variables as an encrypted string to the browser cookie storage
54
- - session.destroy(): Set cookie value in the browser cookie storage as an empty value to clear the cookie data
55
- - Read the session variables by decrypting the encrypted string from the cookie browser storage
56
-
57
- ## Options Definitions
58
-
59
- Only two options are required: `password` and `cookieName`. Everything else is automatically computed and usually doesn't need to be changed.
60
-
61
- - `password`, **required**: Private key used to encrypt the cookie. It has to be at least 32 characters long. Use <https://1password.com/password-generator/> to generate strong passwords. `password` can be either a `string` or an `array` of objects like this: `[{id: 2, password: "..."}, {id: 1, password: "..."}]` to allow for password rotation.
62
- - `cookieName`, **required**: Name of the cookie to be stored
63
- - `ttl`, _optional_: In seconds. Default to the equivalent of 14 days. You can set this to `0` and iron-session will compute the maximum allowed value by cookies (~70 years).
64
- - `cookieOptions`, _optional_: Any option available from [jshttp/cookie#serialize](https://github.com/jshttp/cookie#cookieserializename-value-options) except for `encode` which is not a Set-Cookie Attribute. See [Mozilla Set-Cookie Attributes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#attributes) and [Chrome Cookie Fields](https://developer.chrome.com/docs/devtools/application/cookies/#fields). Default to:
45
+ ```ts
46
+ // Next.js API Routes and Node.js/Express/Connect.
47
+ import { getIronSession } from 'iron-session';
65
48
 
66
- ```js
67
- {
68
- httpOnly: true,
69
- secure: true, // true when using https, false otherwise
70
- sameSite: "lax", // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#lax
71
- // The next line makes sure browser will expire cookies before seals are considered expired by the server. It also allows for clock difference of 60 seconds maximum between servers and clients.
72
- maxAge: (ttl === 0 ? 2147483647 : ttl) - 60,
73
- path: "/",
74
- // other options:
75
- // domain, if you want the cookie to be valid for the whole domain and subdomains, use domain: example.com
76
- // expires, there should be no need to use this option, maxAge takes precedence
77
- // ...
49
+ export function get(req, res) {
50
+ const session = getIronSession(req, res, { password: "...", cookieName: "..." });
78
51
  }
79
- ```
80
-
81
- The final type definition for `CookieOptions` ends up to be
82
-
83
- `'domain' | 'path' | 'secure' | 'sameSite' | 'name' | 'value' | 'expires' | 'httpOnly' | 'maxAge' | 'priority'`
84
-
85
- ### Type Definitions from iron-session/dist/index.node.d.cts
86
52
 
87
- #### IronSessionOptions
88
-
89
- ```ts
90
- interface IronSessionOptions {
91
- /**
92
- * The cookie name that will be used inside the browser. Make sure it's unique
93
- * given your application.
94
- *
95
- * @example 'vercel-session'
96
- */
97
- cookieName: string;
98
- /**
99
- * The password(s) that will be used to encrypt the cookie. Can either be a string
100
- * or an object.
101
- *
102
- * When you provide multiple passwords then all of them will be used to decrypt
103
- * the cookie. But only the most recent (`= highest key`, `2` in the example)
104
- * password will be used to encrypt the cookie. This allows password rotation.
105
- *
106
- * @example { 1: 'password-1', 2: 'password-2' }
107
- */
108
- password: Password;
109
- /**
110
- * The time (in seconds) that the session will be valid for. Also sets the
111
- * `max-age` attribute of the cookie automatically (`= ttl - 60s`, so that the
112
- * cookie always expire before the session).
113
- *
114
- * `ttl = 0` means no expiration.
115
- *
116
- * @default 1209600
117
- */
118
- ttl?: number;
119
- /**
120
- * The options that will be passed to the cookie library.
121
- *
122
- * If you want to use "session cookies" (cookies that are deleted when the browser
123
- * is closed) then you need to pass `cookieOptions: { maxAge: undefined }`
124
- *
125
- * @see https://github.com/jshttp/cookie#options-1
126
- */
127
- cookieOptions?: CookieOptions;
53
+ export function post(req, res) {
54
+ const session = getIronSession(req, res, { password: "...", cookieName: "..." });
55
+ session.username = "Alison";
56
+ await session.save();
128
57
  }
129
58
  ```
130
59
 
131
- ##### CookieOptions
132
-
133
60
  ```ts
134
- /**
135
- * Set-Cookie Attributes do not include `encode`. We omit this from our `cookieOptions` type.
136
- *
137
- * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
138
- * @see https://developer.chrome.com/docs/devtools/application/cookies/
139
- */
140
- type CookieOptions = Omit<CookieSerializeOptions, 'encode'>
141
- ```
142
-
143
- ##### CookieSerializeOptions
61
+ // Next.js Route Handlers (App Router)
62
+ import { cookies } from 'next/header';
63
+ import { getIronSession } from 'iron-session';
144
64
 
145
- ```ts
146
- interface CookieSerializeOptions {
147
- /**
148
- * Specifies the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.3|Domain Set-Cookie attribute}. By default, no
149
- * domain is set, and most clients will consider the cookie to apply to only
150
- * the current domain.
151
- */
152
- domain?: string | undefined;
153
-
154
- /**
155
- * Specifies a function that will be used to encode a cookie's value. Since
156
- * value of a cookie has a limited character set (and must be a simple
157
- * string), this function can be used to encode a value into a string suited
158
- * for a cookie's value.
159
- *
160
- * The default function is the global `encodeURIComponent`, which will
161
- * encode a JavaScript string into UTF-8 byte sequences and then URL-encode
162
- * any that fall outside of the cookie range.
163
- */
164
- encode?(value: string): string;
165
-
166
- /**
167
- * Specifies the `Date` object to be the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.1|`Expires` `Set-Cookie` attribute}. By default,
168
- * no expiration is set, and most clients will consider this a "non-persistent cookie" and will delete
169
- * it on a condition like exiting a web browser application.
170
- *
171
- * *Note* the {@link https://tools.ietf.org/html/rfc6265#section-5.3|cookie storage model specification}
172
- * states that if both `expires` and `maxAge` are set, then `maxAge` takes precedence, but it is
173
- * possible not all clients by obey this, so if both are set, they should
174
- * point to the same date and time.
175
- */
176
- expires?: Date | undefined;
177
- /**
178
- * Specifies the boolean value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.6|`HttpOnly` `Set-Cookie` attribute}.
179
- * When truthy, the `HttpOnly` attribute is set, otherwise it is not. By
180
- * default, the `HttpOnly` attribute is not set.
181
- *
182
- * *Note* be careful when setting this to true, as compliant clients will
183
- * not allow client-side JavaScript to see the cookie in `document.cookie`.
184
- */
185
- httpOnly?: boolean | undefined;
186
- /**
187
- * Specifies the number (in seconds) to be the value for the `Max-Age`
188
- * `Set-Cookie` attribute. The given number will be converted to an integer
189
- * by rounding down. By default, no maximum age is set.
190
- *
191
- * *Note* the {@link https://tools.ietf.org/html/rfc6265#section-5.3|cookie storage model specification}
192
- * states that if both `expires` and `maxAge` are set, then `maxAge` takes precedence, but it is
193
- * possible not all clients by obey this, so if both are set, they should
194
- * point to the same date and time.
195
- */
196
- maxAge?: number | undefined;
197
- /**
198
- * Specifies the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.4|`Path` `Set-Cookie` attribute}.
199
- * By default, the path is considered the "default path".
200
- */
201
- path?: string | undefined;
202
- /**
203
- * Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute][rfc-west-cookie-priority-00-4.1].
204
- *
205
- * - `'low'` will set the `Priority` attribute to `Low`.
206
- * - `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set.
207
- * - `'high'` will set the `Priority` attribute to `High`.
208
- *
209
- * More information about the different priority levels can be found in
210
- * [the specification][rfc-west-cookie-priority-00-4.1].
211
- *
212
- * **note** This is an attribute that has not yet been fully standardized, and may change in the future.
213
- * This also means many clients may ignore this attribute until they understand it.
214
- */
215
- priority?: 'low' | 'medium' | 'high' | undefined;
216
- /**
217
- * Specifies the boolean or string to be the value for the {@link https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7|`SameSite` `Set-Cookie` attribute}.
218
- *
219
- * - `true` will set the `SameSite` attribute to `Strict` for strict same
220
- * site enforcement.
221
- * - `false` will not set the `SameSite` attribute.
222
- * - `'lax'` will set the `SameSite` attribute to Lax for lax same site
223
- * enforcement.
224
- * - `'strict'` will set the `SameSite` attribute to Strict for strict same
225
- * site enforcement.
226
- * - `'none'` will set the SameSite attribute to None for an explicit
227
- * cross-site cookie.
228
- *
229
- * More information about the different enforcement levels can be found in {@link https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7|the specification}.
230
- *
231
- * *note* This is an attribute that has not yet been fully standardized, and may change in the future. This also means many clients may ignore this attribute until they understand it.
232
- */
233
- sameSite?: true | false | 'lax' | 'strict' | 'none' | undefined;
234
- /**
235
- * Specifies the boolean value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.5|`Secure` `Set-Cookie` attribute}. When truthy, the
236
- * `Secure` attribute is set, otherwise it is not. By default, the `Secure` attribute is not set.
237
- *
238
- * *Note* be careful when setting this to `true`, as compliant clients will
239
- * not send the cookie back to the server in the future if the browser does
240
- * not have an HTTPS connection.
241
- */
242
- secure?: boolean | undefined;
65
+ export function GET() {
66
+ const session = getIronSession(cookies(), { password: "...", cookieName: "..." });
243
67
  }
244
68
 
69
+ export function POST() {
70
+ const session = getIronSession(cookies(), { password: "...", cookieName: "..." });
71
+ session.username = "Alison";
72
+ await session.save();
73
+ }
245
74
  ```
246
75
 
247
- ## API
248
-
249
- ## Iron Session Object
250
-
251
- ### getIronSession(req: Request | IncomingMessage, res: Response | ServerResponse<IncomingMessage>, userSessionOptions: IronSessionOptions): Promise<IronSession<T>>
76
+ ```tsx
77
+ // Next.js Server Components and Server Actions (App Router)
78
+ import { cookies } from 'next/header';
79
+ import { getIronSession } from 'iron-session';
252
80
 
253
- ```ts
254
- const session = getIronSession<IronSessionData>(req, res, sessionOptions)
255
- ```
256
-
257
- The API Route Handler that uses `getIronSession` and returns the Response needs to be called from a client-side environment (ie. a 'use client' file).
81
+ async function getIronSession() {
82
+ const session = await getIronSession(cookies(), { password: "...", cookieName: "..." });
83
+ }
258
84
 
259
- ### getServerActionIronSession(userSessionOptions: IronSessionOptions, cookieHandler: ICookieHandler): Promise<IronSession<T>>
85
+ function Profile() {
86
+ const session = await getIronSession();
260
87
 
261
- ```ts
262
- const session = getServerActionIronSession<IronSessionData>(sessionOptions, cookies())
88
+ return <div>{session.username}</div>;
89
+ }
263
90
  ```
264
91
 
265
- The `getServerActionIronSession` implementation uses the `cookies()` function from next/headers to set the cookies so that Iron Session can be used in NextJS Server Actions and React Server Components in a server-side environment (ie. a 'use server' file).
92
+ ## Examples
266
93
 
267
- ## Iron Session Functions
94
+ We have many different patterns and examples on the online demo, have a look: https://get-iron-session.vercel.app/.
268
95
 
269
- ### session.save(saveOptions?: OverridableOptions)
96
+ ## Project status
270
97
 
271
- Saves the session and sets the cookie header to be sent once the response is sent.
98
+ Production ready and maintained.
272
99
 
273
- ```ts
274
- await session.save()
275
- ```
100
+ ## Session options
276
101
 
277
- ### session.destroy(destroyOptions?: OverridableOptions)
102
+ Two options are required: `password` and `cookieName`. Everything else is automatically computed and usually doesn't need to be changed.****
278
103
 
279
- Empties the session object and sets the cookie header to be sent once the response is sent. The browser will then set the cookie value as an empty value.
280
-
281
- ```ts
282
- await session.destroy()
283
- ```
104
+ - `password`, **required**: Private key used to encrypt the cookie. It has to be at least 32 characters long. Use <https://1password.com/password-generator/> to generate strong passwords. `password` can be either a `string` or an `array` of objects like this: `[{id: 2, password: "..."}, {id: 1, password: "..."}]` to allow for password rotation.
105
+ - `cookieName`, **required**: Name of the cookie to be stored
106
+ - `ttl`, _optional_: In seconds. Default to the equivalent of 14 days. You can set this to `0` and iron-session will compute the maximum allowed value by cookies.
107
+ - `cookieOptions`, _optional_: Any option available from [jshttp/cookie#serialize](https://github.com/jshttp/cookie#cookieserializename-value-options) except for `encode` which is not a Set-Cookie Attribute. See [Mozilla Set-Cookie Attributes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#attributes) and [Chrome Cookie Fields](https://developer.chrome.com/docs/devtools/application/cookies/#fields). Default to:
284
108
 
285
- Upon calling either `session.save()` or `session.destroy()` the session values are saved to the browser cookie storage.
109
+ ```js
110
+ {
111
+ httpOnly: true,
112
+ secure: true, // set this to false in local (non-HTTPS) development
113
+ sameSite: "lax",// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#lax
114
+ maxAge: (ttl === 0 ? 2147483647 : ttl) - 60, // Expire cookie before the session expires.
115
+ path: "/",
116
+ }
117
+ ```
286
118
 
287
- ## Iron Session Options
119
+ ## API
288
120
 
289
- ### Default Options
121
+ ### `getIronSession<T>(req, res, sessionOptions): Promise<IronSession<T>>`
290
122
 
291
123
  ```ts
292
- const defaultOptions: Required<OverridableOptions> = {
293
- ttl: fourteenDaysInSeconds,
294
- cookieOptions: { httpOnly: true, secure: true, sameSite: 'lax', path: '/' },
295
- }
124
+ const session = getIronSession<SessionData>(req, res, sessionOptions);
296
125
  ```
297
126
 
298
- ### User Session Options
299
-
300
- You may apply options during the Iron Session object initialization. These options will superseded and override any options set in Default Options. For example: refer to `cookieOptions` in `lib/session.ts` in the below [NextJS Example](#nextjs-example).
301
-
302
- ### Override Options
303
-
304
- You may apply options during the `.save()` or `.destroy()` function calls. These options will superseded and override any options set in Default Options and User Session Options.
305
-
306
- For example:
127
+ ### `getIronSession<T>(cookieStore, sessionOptions): Promise<IronSession<T>>`
307
128
 
308
129
  ```ts
309
- type OverridableOptions = {
310
- ttl?: number;
311
- cookieOptions?: CookieOptions;
312
- }
130
+ const session = getIronSession<SessionData>(cookies(), sessionOptions);
313
131
  ```
314
132
 
315
- ```ts
316
- await session.save({ cookieOptions: { priority: 'high'} })
317
- ```
133
+ ### `session.save(): Promise<void>`
318
134
 
319
- ## NextJS Example
320
-
321
- #### lib/session.ts
135
+ Saves the session. This is an asynchronous operation. It must be done and awaited before headers are sent to the client.
322
136
 
323
137
  ```ts
324
- import {
325
- IronSessionOptions, getIronSession, IronSessionData, getServerActionIronSession
326
- } from 'iron-session'
327
-
328
- import { cookies } from 'next/headers';
329
-
330
- export const sessionOptions: IronSessionOptions = {
331
- password: 'change-this-this-is-not-a-secure-password',
332
- cookieName: 'cookieNameInBrowser',
333
- cookieOptions: {
334
- secure: process.env.NODE_ENV === 'production',
335
- },
336
- }
337
-
338
- declare module 'iron-session' {
339
- interface IronSessionData {
340
- cookieVariable?: string;
341
- }
342
- }
343
-
344
- const getSession = async (req: Request, res: Response) => {
345
- const session = getIronSession<IronSessionData>(req, res, sessionOptions)
346
- return session
347
- }
348
-
349
- const getServerActionSession = async () => {
350
- const session = getServerActionIronSession<IronSessionData>(sessionOptions, cookies())
351
- return session
352
- }
353
-
354
- export {
355
- getSession,
356
- getServerActionSession
357
- }
138
+ await session.save()
358
139
  ```
359
140
 
360
- ### getIronSession
141
+ ### `session.destroy(): void`
361
142
 
362
- #### src/app/clientActions.ts
143
+ Destroys the session. This is a synchronous operation as it only removes the cookie. It must be done before headers are sent to the client.
363
144
 
364
145
  ```ts
365
- 'use client'
366
-
367
- export const submitCookieToStorageRouteHandler = async (cookie: string) => {
368
- await fetch('http://localhost:3000/api/submitIronSessionCookie', {
369
- method: 'POST',
370
- body: JSON.stringify({
371
- cookie,
372
- }),
373
- headers: {
374
- 'Content-Type': 'application/json',
375
- },
376
- })
377
- }
378
-
379
- export const readCookieFromStorageRouteHandler = async (): Promise<string> => {
380
- const responseWithCookieFromStorage = await fetch('http://localhost:3000/api/readIronSessionCookie', {
381
- method: 'GET',
382
- headers: {
383
- 'Content-Type': 'application/json',
384
- },
385
- })
386
- const data = await responseWithCookieFromStorage.json();
387
- const cookieValue = data?.cookieInStorage || 'No Cookie In Storage'
388
- return cookieValue
389
- }
146
+ await session.destroy()
390
147
  ```
391
148
 
392
- #### src/api/submitIronSessionCookie/route.ts
149
+ ### `sealData(data: unknown, { password, ttl }): Promise<string>`
393
150
 
394
- ```ts
395
- import { getSession } from '../../../../lib/session'
396
-
397
- export async function POST(request: Request) {
398
- try {
399
- const requestBody = await request.json()
400
- const { cookie }: { cookie: string } = requestBody
401
- const response = new Response()
402
- const session = await getSession(request, response)
403
- session.cookieVariable = cookie
404
- await session.save()
405
- return response
406
- } catch (error: unknown) {
407
- console.error((error as Error).message)
408
- return new Response(JSON.stringify({ message: (error as Error).message }), { status: 500 })
409
- }
410
- }
411
- ```
151
+ This is the underlying method and seal mechanism that powers `iron-session`. You can use it to seal any `data` you want and pass it around. One usecase are magic links: you generate a seal that contains a user id to login and send it to a route on your website (like `/magic-login`). Once received, you can safely decode the seal with `unsealData` and log the user in.
412
152
 
413
- #### src/api/readIronSessionCookie/route.ts
153
+ ### `unSealData<T>(seal: string, { password, ttl }): Promise<T>`
414
154
 
415
- ```ts
416
- import { NextResponse } from 'next/server'
417
- import { getSession } from '../../../../lib/session'
418
-
419
- export async function GET(request: Request, response: Response) {
420
- try {
421
- const session = await getSession(request, response)
422
- const cookeValue = session.cookieVariable || 'No Cookie Stored!'
423
- return NextResponse.json({ cookieInStorage: cookeValue })
424
- } catch (error: unknown) {
425
- console.error((error as Error).message)
426
- return new Response(JSON.stringify({ message: (error as Error).message }), { status: 500 })
427
- }
428
- }
429
- ```
155
+ This is the opposite of `sealData` and allow you to decode a seal to get the original data back.
430
156
 
431
- ### getServerActionIronSession
157
+ ## FAQ
432
158
 
433
- #### src/app/serverActions.ts
159
+ ### Why use pure cookies for sessions?
434
160
 
435
- ```ts
436
- 'use server'
161
+ This makes your sessions stateless: since the data is passed around in cookies, you do not need any server or service to store session data.
437
162
 
438
- import { getServerActionSession } from '../../lib/session'
163
+ More information can also be found on the [Ruby On Rails website](https://guides.rubyonrails.org/security.html#session-storage) which uses the same technique.
439
164
 
440
- export const submitCookieToStorageServerAction = async (cookie: string) => {
441
- const session = await getServerActionSession()
442
- session.cookieVariable = cookie
443
- await session.save()
444
- }
445
-
446
- export const readCookieFromStorageServerAction = async (): Promise<string> => {
447
- const session = await getServerActionSession()
448
- return session.cookieVariable || 'No Cookie Stored!'
449
- }
450
- ```
165
+ ### How to invalidate sessions?
451
166
 
452
- #### next.config.js
167
+ Sessions cannot be instantly invalidated (or "disconnect this customer") as there is typically no state stored about sessions on the server by default. However, in most applications, the first step upon receiving an authenticated request is to validate the user and their permissions in the database. So, to easily disconnect customers (or invalidate sessions), you can add an `isBlocked`` state in the database and create a UI to block customers.
453
168
 
454
- ```ts
455
- /** @type {import('next').NextConfig} */
456
- const nextConfig = {
457
- experimental: {
458
- serverActions: true,
459
- },
460
- }
169
+ Then, every time a request is received that involves reading or altering sensitive data, make sure to check this flag.
461
170
 
462
- module.exports = nextConfig
463
- ```
171
+ ### Can I use something else than cookies?
464
172
 
465
- ## FAQ
173
+ Yes, we expose `sealData` and `unsealData` which are not tied to cookies. This way you can seal and unseal any object in your application and move seals around to login users.
466
174
 
467
- ### When should I use getIronSession or getServerActionIronSession?
175
+ ### How is this different from [JWT](https://jwt.io/)?
468
176
 
469
- Use `getIronSession` when you wish to use Iron Session in a client-side environment with API Route Handlers and use `getServerActionIronSession` when you wish to use Iron Session in a server-side environment with Server Components.
177
+ Not so much:
470
178
 
471
- For NextJS projects using App Router with Server Actions enabled in their `next.config.js` file, using `getServerActionIronSession` is preferable for two reasons:
179
+ - JWT is a standard, it stores metadata in the JWT token themselves to ensure communication between different systems is flawless.
180
+ - JWT tokens are not encrypted, the payload is visible by customers if they manage to inspect the seal. You would have to use [JWE](https://tools.ietf.org/html/rfc7516) to achieve the same.
181
+ - @hapi/iron mechanism is not a standard, it's a way to sign and encrypt data into seals
472
182
 
473
- - allows Iron Session to be called and used from a server-side environment
474
- - allows for more concise code. Server Actions can be called directly from your components without the need for a manually created API route. You can see the smaller amount of code used for `getServerActionIronSession` compared to `getIronSession` in the example.
183
+ Depending on your own needs and preferences, `iron-session` may or may not fit you.
475
184
 
476
185
  ## Credits
477
186