unjwt 0.5.21 → 0.5.22

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
@@ -20,11 +20,12 @@ A collection of low-level JWT ([RFC 7519](https://datatracker.ietf.org/doc/html/
20
20
  ## Table of Contents
21
21
 
22
22
  - [Usage](#usage)
23
- - [Adapters](#adapters)
24
23
  - [JWS](#jws-json-web-signature-rfc-7515)
25
24
  - [JWE](#jwe-json-web-encryption-rfc-7516)
26
25
  - [JWK](#jwk-json-web-key-rfc-7517)
27
26
  - [Utility Functions](#utility-functions)
27
+ - [Adapters](#adapters)
28
+ - [H3 (Nuxt, Nitro)](#h3-nuxt-nitro)
28
29
  - [Development](#development)
29
30
  - [Credits](#credits)
30
31
  - [License](#license)
package/dist/h3.d.mts CHANGED
@@ -23,6 +23,13 @@ interface SessionJWE<T extends SessionDataT$1 = SessionDataT$1> {
23
23
  data: SessionData<T>;
24
24
  [kGetSessionPromise$1]?: Promise<SessionJWE<T>>;
25
25
  }
26
+ interface SessionHooksJWE {
27
+ onRead?: (session: SessionJWE, event: H3Event) => void | Promise<void>;
28
+ onUpdate?: (session: SessionJWE, event: H3Event) => void | Promise<void>;
29
+ onClear?: (event: H3Event) => void | Promise<void>;
30
+ onExpire?: (event: H3Event, error: any | undefined) => void | Promise<void>;
31
+ onError?: (event: H3Event, error: any) => void | Promise<void>;
32
+ }
26
33
  interface SessionManager<T extends SessionDataT$1 = SessionDataT$1> {
27
34
  readonly id: string | undefined;
28
35
  readonly createdAt: number;
@@ -31,7 +38,7 @@ interface SessionManager<T extends SessionDataT$1 = SessionDataT$1> {
31
38
  update: (update: SessionUpdate$1<T>) => Promise<SessionManager<T>>;
32
39
  clear: () => Promise<SessionManager<T>>;
33
40
  }
34
- interface SessionJWEConfig {
41
+ interface SessionConfigJWE {
35
42
  /** Shared secret used, string for PBES2 or Json Web Key (JWK) */
36
43
  secret: string | JWK_Symmetric | {
37
44
  privateKey: JWK_Private | JWK_Symmetric;
@@ -54,7 +61,12 @@ interface SessionJWEConfig {
54
61
  encryptOptions?: Omit<JWEEncryptOptions, "expiresIn">;
55
62
  decryptOptions?: JWTClaimValidationOptions;
56
63
  };
64
+ hooks?: SessionHooksJWE;
57
65
  }
66
+ /**
67
+ * @deprecated use `SessionConfigJWE` instead
68
+ */
69
+ type SessionJWEConfig = SessionConfigJWE;
58
70
  type CompatEvent$1 = {
59
71
  request: {
60
72
  headers: Headers;
@@ -68,15 +80,15 @@ type SessionUpdate$1<T extends SessionDataT$1 = SessionDataT$1> = Partial<Sessio
68
80
  /**
69
81
  * Create a session manager for the current request.
70
82
  */
71
- declare function useJWESession<T extends SessionDataT$1 = SessionDataT$1>(event: H3Event | CompatEvent$1, config: SessionJWEConfig): Promise<SessionManager<T>>;
83
+ declare function useJWESession<T extends SessionDataT$1 = SessionDataT$1>(event: H3Event | CompatEvent$1, config: SessionConfigJWE): Promise<SessionManager<T>>;
72
84
  /**
73
85
  * Get (and lazily initialize) the session for the current request.
74
86
  */
75
- declare function getJWESession<T extends SessionDataT$1 = SessionDataT$1>(event: H3Event | CompatEvent$1, config: SessionJWEConfig): Promise<SessionJWE<T>>;
87
+ declare function getJWESession<T extends SessionDataT$1 = SessionDataT$1>(event: H3Event | CompatEvent$1, config: SessionConfigJWE): Promise<SessionJWE<T>>;
76
88
  /**
77
89
  * Update the session (optionally mutating the session data) and re-issue the JWE token.
78
90
  */
79
- declare function updateJWESession<T extends SessionDataT$1 = SessionDataT$1>(event: H3Event, config: SessionJWEConfig, update?: SessionUpdate$1<T>): Promise<SessionJWE<T>>;
91
+ declare function updateJWESession<T extends SessionDataT$1 = SessionDataT$1>(event: H3Event, config: SessionConfigJWE, update?: SessionUpdate$1<T>): Promise<SessionJWE<T>>;
80
92
  /**
81
93
  * Produce a JWE for the current session.
82
94
  * Payload structure:
@@ -87,15 +99,15 @@ declare function updateJWESession<T extends SessionDataT$1 = SessionDataT$1>(eve
87
99
  * data: Record<string, any>;
88
100
  * }
89
101
  */
90
- declare function sealJWESession<T extends SessionDataT$1 = SessionDataT$1>(event: H3Event | CompatEvent$1, config: SessionJWEConfig): Promise<string>;
102
+ declare function sealJWESession<T extends SessionDataT$1 = SessionDataT$1>(event: H3Event | CompatEvent$1, config: SessionConfigJWE): Promise<string>;
91
103
  /**
92
104
  * Decrypt the JWE and return a Session-compatible object.
93
105
  */
94
- declare function unsealJWESession(_event: H3Event | CompatEvent$1, config: SessionJWEConfig, sealed: string): Promise<Partial<SessionJWE>>;
106
+ declare function unsealJWESession(_event: H3Event | CompatEvent$1, config: SessionConfigJWE, sealed: string): Promise<Partial<SessionJWE>>;
95
107
  /**
96
108
  * Clear the session (delete from context and drop cookie).
97
109
  */
98
- declare function clearJWESession(event: H3Event, config: Partial<SessionJWEConfig>): Promise<void>;
110
+ declare function clearJWESession(event: H3Event, config: Partial<SessionConfigJWE>): Promise<void>;
99
111
 
100
112
  /**
101
113
  * This is a fork of h3 library's session utility functions.
@@ -112,7 +124,14 @@ interface SessionJWS<T extends SessionDataT = SessionDataT> {
112
124
  data: SessionData<T>;
113
125
  [kGetSessionPromise]?: Promise<SessionJWS<T>>;
114
126
  }
115
- interface SessionJWSConfig {
127
+ interface SessionHooksJWS {
128
+ onRead?: (session: SessionJWS, event: H3Event) => void | Promise<void>;
129
+ onUpdate?: (session: SessionJWS, event: H3Event) => void | Promise<void>;
130
+ onClear?: (event: H3Event) => void | Promise<void>;
131
+ onExpire?: (event: H3Event, error: any | undefined) => void | Promise<void>;
132
+ onError?: (event: H3Event, error: any) => void | Promise<void>;
133
+ }
134
+ interface SessionConfigJWS {
116
135
  /**
117
136
  * JWK (private for signing with RS/ES/PS, or symmetric oct) used for signing.
118
137
  */
@@ -137,7 +156,12 @@ interface SessionJWSConfig {
137
156
  signOptions?: Omit<JWSSignOptions, "expiresIn">;
138
157
  verifyOptions?: JWTClaimValidationOptions;
139
158
  };
159
+ hooks?: SessionHooksJWS;
140
160
  }
161
+ /**
162
+ * @deprecated use `SessionConfigJWS` instead
163
+ */
164
+ type SessionJWSConfig = SessionConfigJWS;
141
165
  type CompatEvent = {
142
166
  request: {
143
167
  headers: Headers;
@@ -152,21 +176,21 @@ type SessionUpdate<T extends SessionDataT = SessionDataT> = Partial<SessionData<
152
176
  * Create a session manager for the current request using JWS (signed only, not encrypted).
153
177
  * NOTE: Contents are visible to clients (Base64URL-decoded JSON). Do not store secrets in session data.
154
178
  */
155
- declare function useJWSSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionJWSConfig): Promise<SessionManager<T>>;
179
+ declare function useJWSSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfigJWS): Promise<SessionManager<T>>;
156
180
  /**
157
181
  * Retrieve (and lazily initialize) the session.
158
182
  */
159
- declare function getJWSSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionJWSConfig): Promise<SessionJWS<T>>;
183
+ declare function getJWSSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfigJWS): Promise<SessionJWS<T>>;
160
184
  /**
161
185
  * Update session data (if provided) and reissue JWS.
162
186
  */
163
- declare function updateJWSSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionJWSConfig, update?: SessionUpdate<T>): Promise<SessionJWS<T>>;
187
+ declare function updateJWSSession<T extends SessionDataT = SessionDataT>(event: H3Event, config: SessionConfigJWS, update?: SessionUpdate<T>): Promise<SessionJWS<T>>;
164
188
  /**
165
189
  * Sign current session as a compact JWS.
166
190
  * Payload claims:
167
191
  * jti, iat, exp?, data, plus optional extraClaims (cannot override reserved)
168
192
  */
169
- declare function signJWSSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionJWSConfig): Promise<string>;
193
+ declare function signJWSSession<T extends SessionDataT = SessionDataT>(event: H3Event | CompatEvent, config: SessionConfigJWS): Promise<string>;
170
194
  /**
171
195
  * Verify and parse a compact JWS into a Session structure.
172
196
  * Performs:
@@ -175,11 +199,11 @@ declare function signJWSSession<T extends SessionDataT = SessionDataT>(event: H3
175
199
  * - ensures jti & iat presence
176
200
  * - enforces maxAge if provided
177
201
  */
178
- declare function verifyJWSSession(_event: H3Event | CompatEvent, config: SessionJWSConfig, token: string): Promise<Partial<SessionJWS>>;
202
+ declare function verifyJWSSession(_event: H3Event | CompatEvent, config: SessionConfigJWS, token: string): Promise<Partial<SessionJWS>>;
179
203
  /**
180
204
  * Destroy the session (context + cookie).
181
205
  */
182
- declare function clearJWSSession(event: H3Event, config: Partial<SessionJWSConfig>): Promise<void>;
206
+ declare function clearJWSSession(event: H3Event, config: Partial<SessionConfigJWS>): Promise<void>;
183
207
 
184
208
  export { JWEEncryptOptions, JWKSet, JWK_Private, JWK_Public, JWK_Symmetric, JWTClaimValidationOptions, JWTClaims, clearJWESession, clearJWSSession, getJWESession, getJWSSession, sealJWESession, signJWSSession, unsealJWESession, updateJWESession, updateJWSSession, useJWESession, useJWSSession, verifyJWSSession };
185
- export type { SessionData, SessionJWE, SessionJWEConfig, SessionJWS, SessionJWSConfig, SessionManager };
209
+ export type { SessionConfigJWE, SessionConfigJWS, SessionData, SessionHooksJWE, SessionHooksJWS, SessionJWE, SessionJWEConfig, SessionJWS, SessionJWSConfig, SessionManager };
package/dist/h3.mjs CHANGED
@@ -57,9 +57,22 @@ async function getJWESession(event, config) {
57
57
  }
58
58
  const existingSession = event.context.sessions[sessionName];
59
59
  if (existingSession) {
60
- return existingSession.expiresAt === void 0 ? existingSession[kGetSessionPromise$1] || existingSession : existingSession.expiresAt < Date.now() && isEvent(event) ? clearJWESession(event, config).then(
61
- () => getJWESession(event, config)
62
- ) : existingSession[kGetSessionPromise$1] || existingSession;
60
+ if (existingSession.expiresAt === void 0) {
61
+ const session2 = existingSession[kGetSessionPromise$1] || existingSession;
62
+ await config.hooks?.onRead?.(await session2, event);
63
+ return session2;
64
+ } else {
65
+ if (existingSession.expiresAt < Date.now() && isEvent(event)) {
66
+ await config.hooks?.onExpire?.(event, void 0);
67
+ return clearJWESession(event, config).then(
68
+ () => getJWESession(event, config)
69
+ );
70
+ } else {
71
+ const session2 = existingSession[kGetSessionPromise$1] || existingSession;
72
+ await config.hooks?.onRead?.(await session2, event);
73
+ return session2;
74
+ }
75
+ }
63
76
  }
64
77
  const session = {
65
78
  id: "",
@@ -83,7 +96,16 @@ async function getJWESession(event, config) {
83
96
  }
84
97
  }
85
98
  if (jweToken) {
86
- const promise = unsealJWESession(event, config, jweToken).catch(() => {
99
+ const promise = unsealJWESession(event, config, jweToken).catch(async (error_) => {
100
+ if (error_ instanceof Error) {
101
+ const message = error_.message;
102
+ if (message.includes("Token has expired") || message.includes("Token is too old")) {
103
+ await config.hooks?.onExpire?.(event, error_);
104
+ return void 0;
105
+ }
106
+ }
107
+ await config.hooks?.onError?.(event, error_);
108
+ return void 0;
87
109
  }).then((unsealed) => {
88
110
  if (unsealed) {
89
111
  Object.assign(session, unsealed);
@@ -106,6 +128,7 @@ async function getJWESession(event, config) {
106
128
  session.data = /* @__PURE__ */ Object.create(null);
107
129
  await updateJWESession(event, config);
108
130
  }
131
+ await config.hooks?.onRead?.(session, event);
109
132
  return session;
110
133
  }
111
134
  function _getReqHeader$1(event, name) {
@@ -127,6 +150,7 @@ async function updateJWESession(event, config, update) {
127
150
  }
128
151
  if (update) {
129
152
  Object.assign(session.data, update);
153
+ await config.hooks?.onUpdate?.(session, event);
130
154
  }
131
155
  if (config.cookie !== false) {
132
156
  const sealed = await sealJWESession(event, config);
@@ -211,7 +235,7 @@ async function unsealJWESession(_event, config, sealed) {
211
235
  data: data && typeof data === "object" ? data : /* @__PURE__ */ Object.create(null)
212
236
  };
213
237
  }
214
- function clearJWESession(event, config) {
238
+ async function clearJWESession(event, config) {
215
239
  const sessionName = config.name || DEFAULT_NAME$1;
216
240
  if (event.context.sessions?.[sessionName]) {
217
241
  delete event.context.sessions[sessionName];
@@ -220,9 +244,10 @@ function clearJWESession(event, config) {
220
244
  ...DEFAULT_COOKIE$1,
221
245
  ...config.cookie,
222
246
  // Optionally set expires in the past
223
- expires: /* @__PURE__ */ new Date(0)
247
+ expires: /* @__PURE__ */ new Date(0),
248
+ maxAge: void 0
224
249
  });
225
- return Promise.resolve();
250
+ await config.hooks?.onClear?.(event);
226
251
  }
227
252
  function getEncryptKey(secret) {
228
253
  if (typeof secret === "string") {
@@ -293,9 +318,22 @@ async function getJWSSession(event, config) {
293
318
  }
294
319
  const existingSession = event.context.sessions[sessionName];
295
320
  if (existingSession) {
296
- return existingSession.expiresAt === void 0 ? existingSession[kGetSessionPromise] || existingSession : existingSession.expiresAt < Date.now() && isEvent(event) ? clearJWSSession(event, config).then(
297
- () => getJWSSession(event, config)
298
- ) : existingSession[kGetSessionPromise] || existingSession;
321
+ if (existingSession.expiresAt === void 0) {
322
+ const session2 = existingSession[kGetSessionPromise] || existingSession;
323
+ await config.hooks?.onRead?.(await session2, event);
324
+ return session2;
325
+ } else {
326
+ if (existingSession.expiresAt < Date.now() && isEvent(event)) {
327
+ await config.hooks?.onExpire?.(event, void 0);
328
+ return clearJWSSession(event, config).then(
329
+ () => getJWSSession(event, config)
330
+ );
331
+ } else {
332
+ const session2 = existingSession[kGetSessionPromise] || existingSession;
333
+ await config.hooks?.onRead?.(await session2, event);
334
+ return session2;
335
+ }
336
+ }
299
337
  }
300
338
  const session = {
301
339
  id: "",
@@ -319,7 +357,16 @@ async function getJWSSession(event, config) {
319
357
  }
320
358
  }
321
359
  if (token) {
322
- const promise = verifyJWSSession(event, config, token).catch(() => {
360
+ const promise = verifyJWSSession(event, config, token).catch(async (error_) => {
361
+ if (error_ instanceof Error) {
362
+ const message = error_.message;
363
+ if (message.includes("Token has expired") || message.includes("Token is too old")) {
364
+ await config.hooks?.onExpire?.(event, error_);
365
+ return void 0;
366
+ }
367
+ }
368
+ await config.hooks?.onError?.(event, error_);
369
+ return void 0;
323
370
  }).then((unsealed) => {
324
371
  if (unsealed) {
325
372
  Object.assign(session, unsealed);
@@ -342,6 +389,7 @@ async function getJWSSession(event, config) {
342
389
  session.data = /* @__PURE__ */ Object.create(null);
343
390
  await updateJWSSession(event, config);
344
391
  }
392
+ await config.hooks?.onRead?.(session, event);
345
393
  return session;
346
394
  }
347
395
  function _getReqHeader(event, name) {
@@ -363,6 +411,7 @@ async function updateJWSSession(event, config, update) {
363
411
  }
364
412
  if (update) {
365
413
  Object.assign(session.data, update);
414
+ await config.hooks?.onUpdate?.(session, event);
366
415
  }
367
416
  if (config.cookie !== false) {
368
417
  const token = await signJWSSession(event, config);
@@ -432,7 +481,7 @@ async function verifyJWSSession(_event, config, token) {
432
481
  data: data && typeof data === "object" ? data : /* @__PURE__ */ Object.create(null)
433
482
  };
434
483
  }
435
- function clearJWSSession(event, config) {
484
+ async function clearJWSSession(event, config) {
436
485
  const sessionName = config.name || DEFAULT_NAME;
437
486
  if (event.context.sessions?.[sessionName]) {
438
487
  delete event.context.sessions[sessionName];
@@ -440,9 +489,10 @@ function clearJWSSession(event, config) {
440
489
  setCookie(event, sessionName, "", {
441
490
  ...DEFAULT_COOKIE,
442
491
  ...config.cookie,
443
- expires: /* @__PURE__ */ new Date(0)
492
+ expires: /* @__PURE__ */ new Date(0),
493
+ maxAge: void 0
444
494
  });
445
- return Promise.resolve();
495
+ await config.hooks?.onClear?.(event);
446
496
  }
447
497
  function getSignKey(key) {
448
498
  if ("privateKey" in key) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unjwt",
3
- "version": "0.5.21",
3
+ "version": "0.5.22",
4
4
  "description": "Low-level JWT utilities",
5
5
  "repository": "sandros94/unjwt",
6
6
  "license": "MIT",