Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More ā†’
Socket
Sign inDemoInstall
Socket

iron-session

Package Overview
Dependencies
Maintainers
2
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

iron-session - npm Package Compare versions

Comparing version 8.0.0-beta.6 to 8.0.0

28

dist/index.d.ts
import * as http from 'http';
import { IncomingMessage, ServerResponse } from 'http';
import { CookieSerializeOptions } from 'cookie';

@@ -7,4 +6,2 @@

type Password = PasswordsMap | string;
type RequestType = IncomingMessage | Request;
type ResponseType = Response | ServerResponse;
/**

@@ -87,25 +84,16 @@ * {@link https://wicg.github.io/cookie-store/#dictdef-cookielistitem CookieListItem}

}
type OverridableOptions = Pick<SessionOptions, "cookieOptions" | "ttl">;
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: (destroyOptions?: OverridableOptions) => Promise<void>;
readonly destroy: () => Promise<void>;
/**
* Encrypts the session data and sets the cookie.
* Update the session configuration. You still need to call save() to send the new cookie.
*/
readonly save: (saveOptions?: OverridableOptions) => Promise<void>;
readonly updateConfig: (newSessionOptions: SessionOptions) => void;
};
declare function createSealData(_crypto: Crypto): (data: unknown, { password, ttl, }: {
password: Password;
ttl?: number;
}) => Promise<string>;
declare function createUnsealData(_crypto: Crypto): <T>(seal: string, { password, ttl, }: {
password: Password;
ttl?: number;
}) => Promise<T>;
declare function createGetIronSession(sealData: ReturnType<typeof createSealData>, unsealData: ReturnType<typeof createUnsealData>): {
<T extends object>(cookies: CookieStore, sessionOptions: SessionOptions): Promise<IronSession<T>>;
<T_1 extends object>(req: RequestType, res: ResponseType, sessionOptions: SessionOptions): Promise<IronSession<T_1>>;
};

@@ -129,2 +117,2 @@ declare const sealData: (data: unknown, { password, ttl, }: {

export { CookieStore, IronSession, SessionOptions, createGetIronSession, createSealData, createUnsealData, getIronSession, sealData, unsealData };
export { type IronSession, type SessionOptions, getIronSession, sealData, unsealData };

@@ -66,3 +66,2 @@ import { serialize, parse } from 'cookie';

id: mostRecentPasswordId.toString(),
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
secret: passwordsMap[mostRecentPasswordId]

@@ -103,11 +102,9 @@ };

}
function mergeOptions(sessionOptions, overrides) {
function getSessionConfig(sessionOptions) {
const options = {
...defaultOptions,
...sessionOptions,
...overrides,
cookieOptions: {
...defaultOptions.cookieOptions,
...sessionOptions.cookieOptions,
...overrides?.cookieOptions
...sessionOptions.cookieOptions || {}
}

@@ -124,3 +121,3 @@ };

}
var badUsageMessage = "iron-session: Bad usage: use getIronSession(req, res, options) or getIronSession(cookies, options).";
var badUsageMessage = "iron-session: Bad usage: use getIronSession(req, res, options) or getIronSession(cookieStore, options).";
function createGetIronSession(sealData2, unsealData2) {

@@ -146,3 +143,3 @@ return getIronSession2;

if (!sessionOptions) {
throw new Error("iron-session: Bad usage. Missing options.");
throw new Error(badUsageMessage);
}

@@ -161,11 +158,16 @@ if (!sessionOptions.cookieName) {

}
const options = mergeOptions(sessionOptions);
const sealFromCookies = getCookie(req, options.cookieName);
let sessionConfig = getSessionConfig(sessionOptions);
const sealFromCookies = getCookie(req, sessionConfig.cookieName);
const session = sealFromCookies ? await unsealData2(sealFromCookies, {
password: passwordsMap,
ttl: options.ttl
ttl: sessionConfig.ttl
}) : {};
Object.defineProperties(session, {
updateConfig: {
value: function updateConfig(newSessionOptions) {
sessionConfig = getSessionConfig(newSessionOptions);
}
},
save: {
value: async function save(saveOptions) {
value: async function save() {
if ("headersSent" in res && res.headersSent) {

@@ -176,11 +178,10 @@ throw new Error(

}
const mergedOptions = mergeOptions(sessionOptions, saveOptions);
const seal = await sealData2(session, {
password: passwordsMap,
ttl: mergedOptions.ttl
ttl: sessionConfig.ttl
});
const cookieValue = serialize(
mergedOptions.cookieName,
sessionConfig.cookieName,
seal,
mergedOptions.cookieOptions
sessionConfig.cookieOptions
);

@@ -196,9 +197,8 @@ if (cookieValue.length > 4096) {

destroy: {
value: async function destroy(destroyOptions) {
value: function destroy() {
Object.keys(session).forEach((key) => {
delete session[key];
});
const mergedOptions = mergeOptions(sessionOptions, destroyOptions);
const cookieValue = serialize(mergedOptions.cookieName, "", {
...mergedOptions.cookieOptions,
const cookieValue = serialize(sessionConfig.cookieName, "", {
...sessionConfig.cookieOptions,
maxAge: 0

@@ -214,5 +214,2 @@ });

async function getIronSessionFromCookieStore(cookieStore, sessionOptions, sealData2, unsealData2) {
if (!sessionOptions) {
throw new Error("iron-session: Bad usage. Missing options.");
}
if (!sessionOptions.cookieName) {

@@ -230,5 +227,5 @@ throw new Error("iron-session: Bad usage. Missing cookie name.");

}
const options = mergeOptions(sessionOptions);
const sessionConfig = getSessionConfig(sessionOptions);
const sealFromCookies = getServerActionCookie(
options.cookieName,
sessionConfig.cookieName,
cookieStore

@@ -238,13 +235,12 @@ );

password: passwordsMap,
ttl: options.ttl
ttl: sessionConfig.ttl
}) : {};
Object.defineProperties(session, {
save: {
value: async function save(saveOptions) {
const mergedOptions = mergeOptions(sessionOptions, saveOptions);
value: async function save() {
const seal = await sealData2(session, {
password: passwordsMap,
ttl: mergedOptions.ttl
ttl: sessionConfig.ttl
});
const cookieLength = mergedOptions.cookieName.length + seal.length + JSON.stringify(mergedOptions.cookieOptions).length;
const cookieLength = sessionConfig.cookieName.length + seal.length + JSON.stringify(sessionConfig.cookieOptions).length;
if (cookieLength > 4096) {

@@ -256,5 +252,5 @@ throw new Error(

cookieStore.set(
mergedOptions.cookieName,
sessionConfig.cookieName,
seal,
mergedOptions.cookieOptions
sessionConfig.cookieOptions
);

@@ -264,9 +260,8 @@ }

destroy: {
value: async function destroy(destroyOptions) {
value: function destroy() {
Object.keys(session).forEach((key) => {
delete session[key];
});
const mergedOptions = mergeOptions(sessionOptions, destroyOptions);
const cookieOptions = { ...mergedOptions.cookieOptions, maxAge: 0 };
cookieStore.set(mergedOptions.cookieName, "", cookieOptions);
const cookieOptions = { ...sessionConfig.cookieOptions, maxAge: 0 };
cookieStore.set(sessionConfig.cookieName, "", cookieOptions);
}

@@ -281,4 +276,4 @@ }

export { createGetIronSession, createSealData, createUnsealData, getIronSession, sealData, unsealData };
export { getIronSession, sealData, unsealData };
//# sourceMappingURL=out.js.map
//# sourceMappingURL=index.js.map
{
"name": "iron-session",
"version": "8.0.0-beta.6",
"version": "8.0.0",
"description": "Secure, stateless, and cookie-based session library for JavaScript",

@@ -45,5 +45,4 @@ "keywords": [

"devDependencies": {
"@release-it/conventional-changelog": "8.0.1",
"@types/cookie": "0.5.4",
"@types/node": "20.9.0",
"@types/node": "18.18.10",
"@typescript-eslint/eslint-plugin": "6.11.0",

@@ -53,3 +52,3 @@ "@typescript-eslint/parser": "6.11.0",

"concurrently": "8.2.2",
"eslint": "8.53.0",
"eslint": "8.54.0",
"eslint-config-prettier": "9.0.0",

@@ -63,8 +62,7 @@ "eslint-import-resolver-node": "0.3.9",

"publint": "0.2.5",
"release-it": "17.0.0",
"tsup": "7.2.0",
"tsx": "4.1.2",
"tsup": "8.0.0",
"tsx": "4.1.4",
"typescript": "5.2.2"
},
"packageManager": "pnpm@8.10.2",
"packageManager": "pnpm@8.10.5",
"publishConfig": {

@@ -78,3 +76,2 @@ "access": "public",

"lint": "tsc --noEmit && tsc --noEmit -p examples/next/tsconfig.json && pnpm eslint . && publint",
"release": "pnpm lint",
"test": "c8 -r text -r lcov node --loader tsx --test src/*.test.ts && pnpm build",

@@ -81,0 +78,0 @@ "test:watch": "node --loader tsx --test --watch src/*.test.ts"

@@ -5,3 +5,5 @@ # 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)

The session data is stored in signed and encrypted cookies which are decoded by your server code in a stateless fashion (= no I/O involved). This is the same technique used by frameworks like
<p align="center">Online demo: <a href="https://get-iron-session.vercel.app/">https://get-iron-session.vercel.app</a> šŸ‘€</p>
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
[Ruby On Rails](https://guides.rubyonrails.org/security.html#session-storage).

@@ -16,2 +18,4 @@

- [Usage](#usage)
- [Examples](#examples)
- [Project status](#project-status)
- [Session options](#session-options)

@@ -21,4 +25,11 @@ - [API](#api)

- [`getIronSession<T>(cookieStore, sessionOptions): Promise<IronSession<T>>`](#getironsessiontcookiestore-sessionoptions-promiseironsessiont)
- [session.save()](#sessionsave)
- [session.destroy()](#sessiondestroy)
- [`session.save(): Promise<void>`](#sessionsave-promisevoid)
- [`session.destroy(): void`](#sessiondestroy-void)
- [`sealData(data: unknown, { password, ttl }): Promise<string>`](#sealdatadata-unknown--password-ttl--promisestring)
- [`unSealData<T>(seal: string, { password, ttl }): Promise<T>`](#unsealdatatseal-string--password-ttl--promiset)
- [FAQ](#faq)
- [Why use pure cookies for sessions?](#why-use-pure-cookies-for-sessions)
- [How to invalidate sessions?](#how-to-invalidate-sessions)
- [Can I use something else than cookies?](#can-i-use-something-else-than-cookies)
- [How is this different from JWT?](#how-is-this-different-from-jwt)
- [Credits](#credits)

@@ -38,3 +49,3 @@ - [Good Reads](#good-reads)

```ts
// Next.js Pages with API Route and Node.js/Express/Connect.
// Next.js API Routes and Node.js/Express/Connect.
import { getIronSession } from 'iron-session';

@@ -54,3 +65,3 @@

```ts
// Next.js App Router with route handlers
// Next.js Route Handlers (App Router)
import { cookies } from 'next/header';

@@ -64,3 +75,3 @@ import { getIronSession } from 'iron-session';

export function POST() {
const session = getIronSession(req, res, { password: "...", cookieName: "..." });
const session = getIronSession(cookies(), { password: "...", cookieName: "..." });
session.username = "Alison";

@@ -71,4 +82,4 @@ await session.save();

```ts
// Next.js App Router with server component or server action
```tsx
// Next.js Server Components and Server Actions (App Router)
import { cookies } from 'next/header';

@@ -88,6 +99,13 @@ import { getIronSession } from 'iron-session';

## Examples
We have many different patterns and examples on the online demo, have a look: https://get-iron-session.vercel.app/.
## Project status
āœ… Production ready and maintained.
## Session options
Two options are required: `password` and `cookieName`. Everything else is automatically computed and usually doesn't need to be changed.
Two options are required: `password` and `cookieName`. Everything else is automatically computed and usually doesn't need to be changed.****

@@ -123,5 +141,5 @@ - `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.

### session.save()
### `session.save(): Promise<void>`
Saves the session.
Saves the session. This is an asynchronous operation. It must be done and awaited before headers are sent to the client.

@@ -132,5 +150,5 @@ ```ts

### session.destroy()
### `session.destroy(): void`
Destroys the session.
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.

@@ -141,2 +159,38 @@ ```ts

### `sealData(data: unknown, { password, ttl }): Promise<string>`
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.
### `unSealData<T>(seal: string, { password, ttl }): Promise<T>`
This is the opposite of `sealData` and allow you to decode a seal to get the original data back.
## FAQ
### Why use pure cookies for sessions?
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.
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.
### How to invalidate sessions?
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.
Then, every time a request is received that involves reading or altering sensitive data, make sure to check this flag.
### Can I use something else than cookies?
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.
### How is this different from [JWT](https://jwt.io/)?
Not so much:
- JWT is a standard, it stores metadata in the JWT token themselves to ensure communication between different systems is flawless.
- 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.
- @hapi/iron mechanism is not a standard, it's a way to sign and encrypt data into seals
Depending on your own needs and preferences, `iron-session` may or may not fit you.
## Credits

@@ -143,0 +197,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with āš”ļø by Socket Inc