unjwt 0.5.25 → 0.5.26
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 +7 -5
- package/dist/adapters/h3.d.mts +48 -10
- package/dist/adapters/h3.mjs +89 -31
- package/dist/adapters/h3v2.d.mts +48 -10
- package/dist/adapters/h3v2.mjs +89 -31
- package/package.json +11 -5
package/README.md
CHANGED
|
@@ -15,7 +15,8 @@ A collection of low-level JWT ([RFC 7519](https://datatracker.ietf.org/doc/html/
|
|
|
15
15
|
- **JWK (JSON Web Key, [RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517))**: generate, import, export, wrap, and unwrap keys in JWK format or as `CryptoKey` objects.
|
|
16
16
|
|
|
17
17
|
- **Adapters** for popular frameworks (PRs welcome for more!):
|
|
18
|
-
- [H3 (Nuxt, Nitro)](./src/adapters/
|
|
18
|
+
- [H3 v1 (Nuxt v4, Nitro v2)](./src/adapters/h3v1/): `useJWSSession()`, `useJWESession()`
|
|
19
|
+
- [H3 v2 (Nuxt v5, Nitro v3)](./src/adapters/h3v2/): `useJWSSession()`, `useJWESession()`
|
|
19
20
|
|
|
20
21
|
## Table of Contents
|
|
21
22
|
|
|
@@ -25,7 +26,8 @@ A collection of low-level JWT ([RFC 7519](https://datatracker.ietf.org/doc/html/
|
|
|
25
26
|
- [JWK](#jwk-json-web-key-rfc-7517)
|
|
26
27
|
- [Utility Functions](#utility-functions)
|
|
27
28
|
- [Adapters](#adapters)
|
|
28
|
-
- [H3 (Nuxt, Nitro)](#h3-nuxt-nitro)
|
|
29
|
+
- [H3 v1 (Nuxt up to v4, Nitro up to v2)](#h3-v1-nuxt-v4-nitro-v2)
|
|
30
|
+
- [H3 v2 (Nuxt v5, Nitro v3)](#h3-v2-nuxt-v5-nitro-v3)
|
|
29
31
|
- [Development](#development)
|
|
30
32
|
- [Credits](#credits)
|
|
31
33
|
- [License](#license)
|
|
@@ -616,7 +618,7 @@ Both helpers expose the same API: read `session.id` / `session.data`, call `sess
|
|
|
616
618
|
import { defineEventHandler } from "h3";
|
|
617
619
|
import { useJWESession, useJWSSession, generateJWK } from "unjwt/adapters/h3v1";
|
|
618
620
|
|
|
619
|
-
const keys = await generateJWK("RS256");
|
|
621
|
+
const keys = await generateJWK("RS256"); // Make sure to persist these keys somewhere!
|
|
620
622
|
|
|
621
623
|
export default defineEventHandler(async (event) => {
|
|
622
624
|
const privateSession = await useJWESession(event, {
|
|
@@ -663,7 +665,7 @@ import {
|
|
|
663
665
|
generateJWK,
|
|
664
666
|
} from "unjwt/adapters/h3v2";
|
|
665
667
|
|
|
666
|
-
const atJwk = await generateJWK("RS256");
|
|
668
|
+
const atJwk = await generateJWK("RS256"); // Make sure to persist these keys somewhere!
|
|
667
669
|
|
|
668
670
|
const jweOptions = {
|
|
669
671
|
key: "refresh_token_secret",
|
|
@@ -675,7 +677,7 @@ const jwsOptions = {
|
|
|
675
677
|
name: "access_token",
|
|
676
678
|
maxAge: 15 * 60, // 15 minutes
|
|
677
679
|
hooks: {
|
|
678
|
-
async onExpire(event,
|
|
680
|
+
async onExpire({ event, config }) {
|
|
679
681
|
const refreshSession = await getJWESession(event, jweOptions);
|
|
680
682
|
if (!refreshSession.data.sub) {
|
|
681
683
|
// no valid refresh session, nothing to do
|
package/dist/adapters/h3.d.mts
CHANGED
|
@@ -24,11 +24,30 @@ interface SessionJWE<T extends SessionDataT$1 = SessionDataT$1> {
|
|
|
24
24
|
[kGetSessionPromise$1]?: Promise<SessionJWE<T>>;
|
|
25
25
|
}
|
|
26
26
|
interface SessionHooksJWE {
|
|
27
|
-
onRead?: (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
onRead?: (args: {
|
|
28
|
+
session: SessionJWE;
|
|
29
|
+
event: H3Event;
|
|
30
|
+
config: SessionConfigJWE;
|
|
31
|
+
}) => void | Promise<void>;
|
|
32
|
+
onUpdate?: (args: {
|
|
33
|
+
session: SessionJWE;
|
|
34
|
+
event: H3Event;
|
|
35
|
+
config: SessionConfigJWE;
|
|
36
|
+
}) => void | Promise<void>;
|
|
37
|
+
onClear?: (args: {
|
|
38
|
+
event: H3Event;
|
|
39
|
+
config: Partial<SessionConfigJWE>;
|
|
40
|
+
}) => void | Promise<void>;
|
|
41
|
+
onExpire?: (args: {
|
|
42
|
+
event: H3Event;
|
|
43
|
+
error: Error;
|
|
44
|
+
config: SessionConfigJWE;
|
|
45
|
+
}) => void | Promise<void>;
|
|
46
|
+
onError?: (args: {
|
|
47
|
+
event: H3Event;
|
|
48
|
+
error: any;
|
|
49
|
+
config: SessionConfigJWE;
|
|
50
|
+
}) => void | Promise<void>;
|
|
32
51
|
}
|
|
33
52
|
interface SessionManager<T extends SessionDataT$1 = SessionDataT$1> {
|
|
34
53
|
readonly id: string | undefined;
|
|
@@ -128,11 +147,30 @@ interface SessionJWS<T extends SessionDataT = SessionDataT> {
|
|
|
128
147
|
[kGetSessionPromise]?: Promise<SessionJWS<T>>;
|
|
129
148
|
}
|
|
130
149
|
interface SessionHooksJWS {
|
|
131
|
-
onRead?: (
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
150
|
+
onRead?: (args: {
|
|
151
|
+
session: SessionJWS;
|
|
152
|
+
event: H3Event;
|
|
153
|
+
config: SessionConfigJWS;
|
|
154
|
+
}) => void | Promise<void>;
|
|
155
|
+
onUpdate?: (args: {
|
|
156
|
+
session: SessionJWS;
|
|
157
|
+
event: H3Event;
|
|
158
|
+
config: SessionConfigJWS;
|
|
159
|
+
}) => void | Promise<void>;
|
|
160
|
+
onClear?: (args: {
|
|
161
|
+
event: H3Event;
|
|
162
|
+
config: Partial<SessionConfigJWS>;
|
|
163
|
+
}) => void | Promise<void>;
|
|
164
|
+
onExpire?: (args: {
|
|
165
|
+
event: H3Event;
|
|
166
|
+
error: Error;
|
|
167
|
+
config: SessionConfigJWS;
|
|
168
|
+
}) => void | Promise<void>;
|
|
169
|
+
onError?: (args: {
|
|
170
|
+
event: H3Event;
|
|
171
|
+
error: any;
|
|
172
|
+
config: SessionConfigJWS;
|
|
173
|
+
}) => void | Promise<void>;
|
|
136
174
|
}
|
|
137
175
|
interface SessionConfigJWS {
|
|
138
176
|
/**
|
package/dist/adapters/h3.mjs
CHANGED
|
@@ -59,12 +59,22 @@ async function getJWESession(event, config) {
|
|
|
59
59
|
if (existingSession) {
|
|
60
60
|
const session2 = existingSession[kGetSessionPromise$1] ? await existingSession[kGetSessionPromise$1] : existingSession;
|
|
61
61
|
if (session2.expiresAt !== void 0 && session2.expiresAt < Date.now() && isEvent(event)) {
|
|
62
|
-
await config.hooks?.onExpire?.(
|
|
62
|
+
await config.hooks?.onExpire?.({
|
|
63
|
+
event,
|
|
64
|
+
error: new Error(
|
|
65
|
+
`JWT "exp" (Expiration Time) Claim validation failed: Token has expired (exp: ${new Date(session2.expiresAt * 1e3).toISOString()})`
|
|
66
|
+
),
|
|
67
|
+
config
|
|
68
|
+
});
|
|
63
69
|
return clearJWESession(event, config).then(
|
|
64
70
|
() => getJWESession(event, config)
|
|
65
71
|
);
|
|
66
72
|
}
|
|
67
|
-
await config.hooks?.onRead?.(
|
|
73
|
+
await config.hooks?.onRead?.({
|
|
74
|
+
event,
|
|
75
|
+
session: session2,
|
|
76
|
+
config
|
|
77
|
+
});
|
|
68
78
|
return session2;
|
|
69
79
|
}
|
|
70
80
|
const session = {
|
|
@@ -74,27 +84,35 @@ async function getJWESession(event, config) {
|
|
|
74
84
|
data: /* @__PURE__ */ Object.create(null)
|
|
75
85
|
};
|
|
76
86
|
event.context.sessions[sessionName] = session;
|
|
77
|
-
let
|
|
87
|
+
let token;
|
|
78
88
|
if (config.sessionHeader !== false) {
|
|
79
89
|
const headerName = typeof config.sessionHeader === "string" ? config.sessionHeader.toLowerCase() : `x-${sessionName.toLowerCase()}-session`;
|
|
80
90
|
const headerValue = _getReqHeader$1(event, headerName);
|
|
81
91
|
if (typeof headerValue === "string") {
|
|
82
|
-
|
|
92
|
+
token = headerValue.startsWith("Bearer ") ? headerValue.slice(7).trim() : headerValue;
|
|
83
93
|
}
|
|
84
94
|
}
|
|
85
|
-
if (!
|
|
95
|
+
if (!token) {
|
|
86
96
|
const cookieHeader = _getReqHeader$1(event, "cookie");
|
|
87
97
|
if (cookieHeader) {
|
|
88
|
-
|
|
98
|
+
token = parse(String(cookieHeader))[sessionName];
|
|
89
99
|
}
|
|
90
100
|
}
|
|
91
|
-
if (
|
|
92
|
-
const promise = unsealJWESession(event, config,
|
|
101
|
+
if (token) {
|
|
102
|
+
const promise = unsealJWESession(event, config, token).catch(async (error_) => {
|
|
93
103
|
if (error_ instanceof Error && (error_.message.includes("Token has expired") || error_.message.includes("Token is too old"))) {
|
|
94
|
-
await config.hooks?.onExpire?.(
|
|
104
|
+
await config.hooks?.onExpire?.({
|
|
105
|
+
event,
|
|
106
|
+
error: error_,
|
|
107
|
+
config
|
|
108
|
+
});
|
|
95
109
|
return void 0;
|
|
96
110
|
}
|
|
97
|
-
await config.hooks?.onError?.(
|
|
111
|
+
await config.hooks?.onError?.({
|
|
112
|
+
event,
|
|
113
|
+
error: error_,
|
|
114
|
+
config
|
|
115
|
+
});
|
|
98
116
|
return void 0;
|
|
99
117
|
}).then((unsealed) => {
|
|
100
118
|
if (unsealed) {
|
|
@@ -117,7 +135,11 @@ async function getJWESession(event, config) {
|
|
|
117
135
|
session.expiresAt = config.maxAge ? session.createdAt + config.maxAge * 1e3 : void 0;
|
|
118
136
|
await updateJWESession(event, config);
|
|
119
137
|
}
|
|
120
|
-
await config.hooks?.onRead?.(
|
|
138
|
+
await config.hooks?.onRead?.({
|
|
139
|
+
event,
|
|
140
|
+
session,
|
|
141
|
+
config
|
|
142
|
+
});
|
|
121
143
|
return session;
|
|
122
144
|
}
|
|
123
145
|
function _getReqHeader$1(event, name) {
|
|
@@ -139,7 +161,11 @@ async function updateJWESession(event, config, update) {
|
|
|
139
161
|
}
|
|
140
162
|
if (update) {
|
|
141
163
|
Object.assign(session.data, update);
|
|
142
|
-
await config.hooks?.onUpdate?.(
|
|
164
|
+
await config.hooks?.onUpdate?.({
|
|
165
|
+
event,
|
|
166
|
+
session,
|
|
167
|
+
config
|
|
168
|
+
});
|
|
143
169
|
}
|
|
144
170
|
if (config.cookie !== false) {
|
|
145
171
|
const sealed = await sealJWESession(event, config);
|
|
@@ -195,11 +221,11 @@ async function unsealJWESession(_event, config, sealed) {
|
|
|
195
221
|
const { payload } = await decrypt(sealed, key, {
|
|
196
222
|
...config.jwe?.decryptOptions,
|
|
197
223
|
requiredClaims: [
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
224
|
+
.../* @__PURE__ */ new Set([
|
|
225
|
+
...config.jwe?.decryptOptions?.requiredClaims || [],
|
|
226
|
+
"jti",
|
|
227
|
+
"iat"
|
|
228
|
+
])
|
|
203
229
|
],
|
|
204
230
|
maxTokenAge: config.maxAge,
|
|
205
231
|
algorithms: alg ? [alg] : void 0,
|
|
@@ -235,7 +261,10 @@ async function clearJWESession(event, config) {
|
|
|
235
261
|
expires: /* @__PURE__ */ new Date(0),
|
|
236
262
|
maxAge: void 0
|
|
237
263
|
});
|
|
238
|
-
await config.hooks?.onClear?.(
|
|
264
|
+
await config.hooks?.onClear?.({
|
|
265
|
+
event,
|
|
266
|
+
config
|
|
267
|
+
});
|
|
239
268
|
}
|
|
240
269
|
function getEncryptKey(key) {
|
|
241
270
|
if (!key) {
|
|
@@ -334,12 +363,22 @@ async function getJWSSession(event, config) {
|
|
|
334
363
|
if (existingSession) {
|
|
335
364
|
const session2 = existingSession[kGetSessionPromise] ? await existingSession[kGetSessionPromise] : existingSession;
|
|
336
365
|
if (session2.expiresAt !== void 0 && session2.expiresAt < Date.now() && isEvent(event)) {
|
|
337
|
-
await config.hooks?.onExpire?.(
|
|
366
|
+
await config.hooks?.onExpire?.({
|
|
367
|
+
event,
|
|
368
|
+
error: new Error(
|
|
369
|
+
`JWT "exp" (Expiration Time) Claim validation failed: Token has expired (exp: ${new Date(session2.expiresAt * 1e3).toISOString()})`
|
|
370
|
+
),
|
|
371
|
+
config
|
|
372
|
+
});
|
|
338
373
|
return clearJWSSession(event, config).then(
|
|
339
374
|
() => getJWSSession(event, config)
|
|
340
375
|
);
|
|
341
376
|
}
|
|
342
|
-
await config.hooks?.onRead?.(
|
|
377
|
+
await config.hooks?.onRead?.({
|
|
378
|
+
event,
|
|
379
|
+
session: session2,
|
|
380
|
+
config
|
|
381
|
+
});
|
|
343
382
|
return session2;
|
|
344
383
|
}
|
|
345
384
|
const session = {
|
|
@@ -354,7 +393,7 @@ async function getJWSSession(event, config) {
|
|
|
354
393
|
const headerName = typeof config.sessionHeader === "string" ? config.sessionHeader.toLowerCase() : `x-${sessionName.toLowerCase()}-session`;
|
|
355
394
|
const headerValue = _getReqHeader(event, headerName);
|
|
356
395
|
if (typeof headerValue === "string") {
|
|
357
|
-
token = headerValue;
|
|
396
|
+
token = headerValue.startsWith("Bearer ") ? headerValue.slice(7).trim() : headerValue;
|
|
358
397
|
}
|
|
359
398
|
}
|
|
360
399
|
if (!token) {
|
|
@@ -366,10 +405,18 @@ async function getJWSSession(event, config) {
|
|
|
366
405
|
if (token) {
|
|
367
406
|
const promise = verifyJWSSession(event, config, token).catch(async (error_) => {
|
|
368
407
|
if (error_ instanceof Error && (error_.message.includes("Token has expired") || error_.message.includes("Token is too old"))) {
|
|
369
|
-
await config.hooks?.onExpire?.(
|
|
408
|
+
await config.hooks?.onExpire?.({
|
|
409
|
+
event,
|
|
410
|
+
error: error_,
|
|
411
|
+
config
|
|
412
|
+
});
|
|
370
413
|
return void 0;
|
|
371
414
|
}
|
|
372
|
-
await config.hooks?.onError?.(
|
|
415
|
+
await config.hooks?.onError?.({
|
|
416
|
+
event,
|
|
417
|
+
error: error_,
|
|
418
|
+
config
|
|
419
|
+
});
|
|
373
420
|
return void 0;
|
|
374
421
|
}).then((unsealed) => {
|
|
375
422
|
if (unsealed) {
|
|
@@ -392,7 +439,11 @@ async function getJWSSession(event, config) {
|
|
|
392
439
|
session.expiresAt = config.maxAge ? session.createdAt + config.maxAge * 1e3 : void 0;
|
|
393
440
|
await updateJWSSession(event, config);
|
|
394
441
|
}
|
|
395
|
-
await config.hooks?.onRead?.(
|
|
442
|
+
await config.hooks?.onRead?.({
|
|
443
|
+
event,
|
|
444
|
+
session,
|
|
445
|
+
config
|
|
446
|
+
});
|
|
396
447
|
return session;
|
|
397
448
|
}
|
|
398
449
|
function _getReqHeader(event, name) {
|
|
@@ -414,7 +465,11 @@ async function updateJWSSession(event, config, update) {
|
|
|
414
465
|
}
|
|
415
466
|
if (update) {
|
|
416
467
|
Object.assign(session.data, update);
|
|
417
|
-
await config.hooks?.onUpdate?.(
|
|
468
|
+
await config.hooks?.onUpdate?.({
|
|
469
|
+
event,
|
|
470
|
+
session,
|
|
471
|
+
config
|
|
472
|
+
});
|
|
418
473
|
}
|
|
419
474
|
if (config.cookie !== false) {
|
|
420
475
|
const token = await signJWSSession(event, config);
|
|
@@ -467,11 +522,11 @@ async function verifyJWSSession(_event, config, token) {
|
|
|
467
522
|
const { payload } = await verify(token, jwk, {
|
|
468
523
|
...config.jws?.verifyOptions,
|
|
469
524
|
requiredClaims: [
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
525
|
+
.../* @__PURE__ */ new Set([
|
|
526
|
+
...config.jws?.verifyOptions?.requiredClaims || [],
|
|
527
|
+
"jti",
|
|
528
|
+
"iat"
|
|
529
|
+
])
|
|
475
530
|
],
|
|
476
531
|
typ: typ || "JWT",
|
|
477
532
|
algorithms: alg ? [alg] : void 0,
|
|
@@ -501,7 +556,10 @@ async function clearJWSSession(event, config) {
|
|
|
501
556
|
expires: /* @__PURE__ */ new Date(0),
|
|
502
557
|
maxAge: void 0
|
|
503
558
|
});
|
|
504
|
-
await config.hooks?.onClear?.(
|
|
559
|
+
await config.hooks?.onClear?.({
|
|
560
|
+
event,
|
|
561
|
+
config
|
|
562
|
+
});
|
|
505
563
|
}
|
|
506
564
|
function getSignKey(key) {
|
|
507
565
|
if (!key) {
|
package/dist/adapters/h3v2.d.mts
CHANGED
|
@@ -18,11 +18,30 @@ interface SessionJWE<T extends SessionDataT$1 = SessionDataT$1> {
|
|
|
18
18
|
[kGetSessionPromise$1]?: Promise<SessionJWE<T>>;
|
|
19
19
|
}
|
|
20
20
|
interface SessionHooksJWE {
|
|
21
|
-
onRead?: (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
onRead?: (args: {
|
|
22
|
+
session: SessionJWE;
|
|
23
|
+
event: HTTPEvent;
|
|
24
|
+
config: SessionConfigJWE;
|
|
25
|
+
}) => void | Promise<void>;
|
|
26
|
+
onUpdate?: (args: {
|
|
27
|
+
session: SessionJWE;
|
|
28
|
+
event: HTTPEvent;
|
|
29
|
+
config: SessionConfigJWE;
|
|
30
|
+
}) => void | Promise<void>;
|
|
31
|
+
onClear?: (args: {
|
|
32
|
+
event: HTTPEvent;
|
|
33
|
+
config: Partial<SessionConfigJWE>;
|
|
34
|
+
}) => void | Promise<void>;
|
|
35
|
+
onExpire?: (args: {
|
|
36
|
+
event: HTTPEvent;
|
|
37
|
+
error: Error;
|
|
38
|
+
config: SessionConfigJWE;
|
|
39
|
+
}) => void | Promise<void>;
|
|
40
|
+
onError?: (args: {
|
|
41
|
+
event: HTTPEvent;
|
|
42
|
+
error: any;
|
|
43
|
+
config: SessionConfigJWE;
|
|
44
|
+
}) => void | Promise<void>;
|
|
26
45
|
}
|
|
27
46
|
interface SessionManager<T extends SessionDataT$1 = SessionDataT$1> {
|
|
28
47
|
readonly id: string | undefined;
|
|
@@ -93,11 +112,30 @@ interface SessionJWS<T extends SessionDataT = SessionDataT> {
|
|
|
93
112
|
[kGetSessionPromise]?: Promise<SessionJWS<T>>;
|
|
94
113
|
}
|
|
95
114
|
interface SessionHooksJWS {
|
|
96
|
-
onRead?: (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
115
|
+
onRead?: (args: {
|
|
116
|
+
session: SessionJWS;
|
|
117
|
+
event: HTTPEvent;
|
|
118
|
+
config: SessionConfigJWS;
|
|
119
|
+
}) => void | Promise<void>;
|
|
120
|
+
onUpdate?: (args: {
|
|
121
|
+
session: SessionJWS;
|
|
122
|
+
event: HTTPEvent;
|
|
123
|
+
config: SessionConfigJWS;
|
|
124
|
+
}) => void | Promise<void>;
|
|
125
|
+
onClear?: (args: {
|
|
126
|
+
event: HTTPEvent;
|
|
127
|
+
config: Partial<SessionConfigJWS>;
|
|
128
|
+
}) => void | Promise<void>;
|
|
129
|
+
onExpire?: (args: {
|
|
130
|
+
event: HTTPEvent;
|
|
131
|
+
error: Error;
|
|
132
|
+
config: SessionConfigJWS;
|
|
133
|
+
}) => void | Promise<void>;
|
|
134
|
+
onError?: (args: {
|
|
135
|
+
event: HTTPEvent;
|
|
136
|
+
error: any;
|
|
137
|
+
config: SessionConfigJWS;
|
|
138
|
+
}) => void | Promise<void>;
|
|
101
139
|
}
|
|
102
140
|
interface SessionConfigJWS {
|
|
103
141
|
key: JWK_Symmetric | {
|
package/dist/adapters/h3v2.mjs
CHANGED
|
@@ -49,12 +49,22 @@ async function getJWESession(event, config) {
|
|
|
49
49
|
if (existingSession) {
|
|
50
50
|
const session2 = existingSession[kGetSessionPromise$1] ? await existingSession[kGetSessionPromise$1] : existingSession;
|
|
51
51
|
if (session2.expiresAt !== void 0 && session2.expiresAt < Date.now() && hasWritableResponse$1(event)) {
|
|
52
|
-
await config.hooks?.onExpire?.(
|
|
52
|
+
await config.hooks?.onExpire?.({
|
|
53
|
+
event,
|
|
54
|
+
error: new Error(
|
|
55
|
+
`JWT "exp" (Expiration Time) Claim validation failed: Token has expired (exp: ${new Date(session2.expiresAt * 1e3).toISOString()})`
|
|
56
|
+
),
|
|
57
|
+
config
|
|
58
|
+
});
|
|
53
59
|
return clearJWESession(event, config).then(
|
|
54
60
|
() => getJWESession(event, config)
|
|
55
61
|
);
|
|
56
62
|
}
|
|
57
|
-
await config.hooks?.onRead?.(
|
|
63
|
+
await config.hooks?.onRead?.({
|
|
64
|
+
event,
|
|
65
|
+
session: session2,
|
|
66
|
+
config
|
|
67
|
+
});
|
|
58
68
|
return session2;
|
|
59
69
|
}
|
|
60
70
|
const session = {
|
|
@@ -64,27 +74,35 @@ async function getJWESession(event, config) {
|
|
|
64
74
|
data: new NullProtoObj()
|
|
65
75
|
};
|
|
66
76
|
context.sessions[sessionName] = session;
|
|
67
|
-
let
|
|
77
|
+
let token;
|
|
68
78
|
if (config.sessionHeader !== false) {
|
|
69
79
|
const headerName = typeof config.sessionHeader === "string" ? config.sessionHeader.toLowerCase() : `x-${sessionName.toLowerCase()}-session`;
|
|
70
80
|
const headerValue = event.req.headers.get(headerName);
|
|
71
81
|
if (typeof headerValue === "string") {
|
|
72
|
-
|
|
82
|
+
token = headerValue.startsWith("Bearer ") ? headerValue.slice(7).trim() : headerValue;
|
|
73
83
|
}
|
|
74
84
|
}
|
|
75
|
-
if (!
|
|
76
|
-
|
|
85
|
+
if (!token) {
|
|
86
|
+
token = getChunkedCookie(event, sessionName);
|
|
77
87
|
}
|
|
78
|
-
if (
|
|
79
|
-
const promise = unsealJWESession(event, config,
|
|
88
|
+
if (token) {
|
|
89
|
+
const promise = unsealJWESession(event, config, token).catch(async (error_) => {
|
|
80
90
|
if (error_ instanceof Error) {
|
|
81
91
|
const message = error_.message;
|
|
82
92
|
if (message.includes("Token has expired") || message.includes("Token is too old")) {
|
|
83
|
-
await config.hooks?.onExpire?.(
|
|
93
|
+
await config.hooks?.onExpire?.({
|
|
94
|
+
event,
|
|
95
|
+
error: error_,
|
|
96
|
+
config
|
|
97
|
+
});
|
|
84
98
|
return void 0;
|
|
85
99
|
}
|
|
86
100
|
}
|
|
87
|
-
await config.hooks?.onError?.(
|
|
101
|
+
await config.hooks?.onError?.({
|
|
102
|
+
event,
|
|
103
|
+
error: error_,
|
|
104
|
+
config
|
|
105
|
+
});
|
|
88
106
|
return void 0;
|
|
89
107
|
}).then((unsealed) => {
|
|
90
108
|
if (unsealed) {
|
|
@@ -102,7 +120,11 @@ async function getJWESession(event, config) {
|
|
|
102
120
|
session.expiresAt = config.maxAge ? session.createdAt + config.maxAge * 1e3 : void 0;
|
|
103
121
|
await updateJWESession(event, config);
|
|
104
122
|
}
|
|
105
|
-
await config.hooks?.onRead?.(
|
|
123
|
+
await config.hooks?.onRead?.({
|
|
124
|
+
event,
|
|
125
|
+
session,
|
|
126
|
+
config
|
|
127
|
+
});
|
|
106
128
|
return session;
|
|
107
129
|
}
|
|
108
130
|
async function updateJWESession(event, config, update) {
|
|
@@ -114,7 +136,11 @@ async function updateJWESession(event, config, update) {
|
|
|
114
136
|
}
|
|
115
137
|
if (update) {
|
|
116
138
|
Object.assign(session.data, update);
|
|
117
|
-
await config.hooks?.onUpdate?.(
|
|
139
|
+
await config.hooks?.onUpdate?.({
|
|
140
|
+
event,
|
|
141
|
+
session,
|
|
142
|
+
config
|
|
143
|
+
});
|
|
118
144
|
}
|
|
119
145
|
if (config.cookie !== false && hasWritableResponse$1(event)) {
|
|
120
146
|
const sealed = await sealJWESession(event, config);
|
|
@@ -167,11 +193,11 @@ async function unsealJWESession(_event, config, sealed) {
|
|
|
167
193
|
const { payload } = await decrypt(sealed, key, {
|
|
168
194
|
...config.jwe?.decryptOptions,
|
|
169
195
|
requiredClaims: [
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
196
|
+
.../* @__PURE__ */ new Set([
|
|
197
|
+
...config.jwe?.decryptOptions?.requiredClaims || [],
|
|
198
|
+
"jti",
|
|
199
|
+
"iat"
|
|
200
|
+
])
|
|
175
201
|
],
|
|
176
202
|
maxTokenAge: config.maxAge,
|
|
177
203
|
algorithms: alg ? [alg] : void 0,
|
|
@@ -207,7 +233,10 @@ async function clearJWESession(event, config) {
|
|
|
207
233
|
expires: /* @__PURE__ */ new Date(0),
|
|
208
234
|
maxAge: void 0
|
|
209
235
|
});
|
|
210
|
-
await config.hooks?.onClear?.(
|
|
236
|
+
await config.hooks?.onClear?.({
|
|
237
|
+
event,
|
|
238
|
+
config
|
|
239
|
+
});
|
|
211
240
|
}
|
|
212
241
|
}
|
|
213
242
|
function getSessionFromContext$1(event, sessionName) {
|
|
@@ -304,12 +333,22 @@ async function getJWSSession(event, config) {
|
|
|
304
333
|
if (existingSession) {
|
|
305
334
|
const session2 = existingSession[kGetSessionPromise] ? await existingSession[kGetSessionPromise] : existingSession;
|
|
306
335
|
if (session2.expiresAt !== void 0 && session2.expiresAt < Date.now() && hasWritableResponse(event)) {
|
|
307
|
-
await config.hooks?.onExpire?.(
|
|
336
|
+
await config.hooks?.onExpire?.({
|
|
337
|
+
event,
|
|
338
|
+
error: new Error(
|
|
339
|
+
`JWT "exp" (Expiration Time) Claim validation failed: Token has expired (exp: ${new Date(session2.expiresAt * 1e3).toISOString()})`
|
|
340
|
+
),
|
|
341
|
+
config
|
|
342
|
+
});
|
|
308
343
|
return clearJWSSession(event, config).then(
|
|
309
344
|
() => getJWSSession(event, config)
|
|
310
345
|
);
|
|
311
346
|
}
|
|
312
|
-
await config.hooks?.onRead?.(
|
|
347
|
+
await config.hooks?.onRead?.({
|
|
348
|
+
event,
|
|
349
|
+
session: session2,
|
|
350
|
+
config
|
|
351
|
+
});
|
|
313
352
|
return session2;
|
|
314
353
|
}
|
|
315
354
|
const session = {
|
|
@@ -324,7 +363,7 @@ async function getJWSSession(event, config) {
|
|
|
324
363
|
const headerName = typeof config.sessionHeader === "string" ? config.sessionHeader.toLowerCase() : `x-${sessionName.toLowerCase()}-session`;
|
|
325
364
|
const headerValue = event.req.headers.get(headerName);
|
|
326
365
|
if (typeof headerValue === "string") {
|
|
327
|
-
token = headerValue;
|
|
366
|
+
token = headerValue.startsWith("Bearer ") ? headerValue.slice(7).trim() : headerValue;
|
|
328
367
|
}
|
|
329
368
|
}
|
|
330
369
|
if (!token) {
|
|
@@ -333,10 +372,18 @@ async function getJWSSession(event, config) {
|
|
|
333
372
|
if (token) {
|
|
334
373
|
const promise = verifyJWSSession(event, config, token).catch(async (error_) => {
|
|
335
374
|
if (error_ instanceof Error && (error_.message.includes("Token has expired") || error_.message.includes("Token is too old"))) {
|
|
336
|
-
await config.hooks?.onExpire?.(
|
|
375
|
+
await config.hooks?.onExpire?.({
|
|
376
|
+
event,
|
|
377
|
+
error: error_,
|
|
378
|
+
config
|
|
379
|
+
});
|
|
337
380
|
return void 0;
|
|
338
381
|
}
|
|
339
|
-
await config.hooks?.onError?.(
|
|
382
|
+
await config.hooks?.onError?.({
|
|
383
|
+
event,
|
|
384
|
+
error: error_,
|
|
385
|
+
config
|
|
386
|
+
});
|
|
340
387
|
return void 0;
|
|
341
388
|
}).then((unsealed) => {
|
|
342
389
|
if (unsealed) {
|
|
@@ -354,7 +401,11 @@ async function getJWSSession(event, config) {
|
|
|
354
401
|
session.expiresAt = config.maxAge ? session.createdAt + config.maxAge * 1e3 : void 0;
|
|
355
402
|
await updateJWSSession(event, config);
|
|
356
403
|
}
|
|
357
|
-
await config.hooks?.onRead?.(
|
|
404
|
+
await config.hooks?.onRead?.({
|
|
405
|
+
event,
|
|
406
|
+
session,
|
|
407
|
+
config
|
|
408
|
+
});
|
|
358
409
|
return session;
|
|
359
410
|
}
|
|
360
411
|
async function updateJWSSession(event, config, update) {
|
|
@@ -366,7 +417,11 @@ async function updateJWSSession(event, config, update) {
|
|
|
366
417
|
}
|
|
367
418
|
if (update) {
|
|
368
419
|
Object.assign(session.data, update);
|
|
369
|
-
await config.hooks?.onUpdate?.(
|
|
420
|
+
await config.hooks?.onUpdate?.({
|
|
421
|
+
event,
|
|
422
|
+
session,
|
|
423
|
+
config
|
|
424
|
+
});
|
|
370
425
|
}
|
|
371
426
|
if (config.cookie !== false && hasWritableResponse(event)) {
|
|
372
427
|
const token = await signJWSSession(event, config);
|
|
@@ -420,11 +475,11 @@ async function verifyJWSSession(_event, config, token) {
|
|
|
420
475
|
const { payload } = await verify(token, jwk, {
|
|
421
476
|
...config.jws?.verifyOptions,
|
|
422
477
|
requiredClaims: [
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
478
|
+
.../* @__PURE__ */ new Set([
|
|
479
|
+
...config.jws?.verifyOptions?.requiredClaims || [],
|
|
480
|
+
"jti",
|
|
481
|
+
"iat"
|
|
482
|
+
])
|
|
428
483
|
],
|
|
429
484
|
typ: typ || "JWT",
|
|
430
485
|
algorithms: alg ? [alg] : void 0,
|
|
@@ -455,7 +510,10 @@ async function clearJWSSession(event, config) {
|
|
|
455
510
|
expires: /* @__PURE__ */ new Date(0),
|
|
456
511
|
maxAge: void 0
|
|
457
512
|
});
|
|
458
|
-
await config.hooks?.onClear?.(
|
|
513
|
+
await config.hooks?.onClear?.({
|
|
514
|
+
event,
|
|
515
|
+
config
|
|
516
|
+
});
|
|
459
517
|
}
|
|
460
518
|
}
|
|
461
519
|
function getSessionFromContext(event, sessionName) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unjwt",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.26",
|
|
4
4
|
"description": "Low-level JWT utilities",
|
|
5
5
|
"repository": "sandros94/unjwt",
|
|
6
6
|
"license": "MIT",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"eslint": "^9.36.0",
|
|
74
74
|
"eslint-config-unjs": "^0.5.0",
|
|
75
75
|
"h3v1": "npm:h3@^1.15.4",
|
|
76
|
-
"h3v2": "npm:h3@^2.0.1-rc.
|
|
76
|
+
"h3v2": "npm:h3@^2.0.1-rc.5",
|
|
77
77
|
"jose": "^6.1.0",
|
|
78
78
|
"prettier": "^3.6.2",
|
|
79
79
|
"supertest": "^7.1.4",
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
},
|
|
84
84
|
"peerDependencies": {
|
|
85
85
|
"cookie-es": "^1.2.2 || ^2.0.0",
|
|
86
|
-
"h3": "^1.15.4 || >=2.0.1-rc.
|
|
87
|
-
"rou3": "^0.7.
|
|
86
|
+
"h3": "^1.15.4 || >=2.0.1-rc.5 || ^2.0.1",
|
|
87
|
+
"rou3": "^0.7.10"
|
|
88
88
|
},
|
|
89
89
|
"peerDependenciesMeta": {
|
|
90
90
|
"cookie-es": {
|
|
@@ -92,7 +92,13 @@
|
|
|
92
92
|
},
|
|
93
93
|
"h3": {
|
|
94
94
|
"optional": true
|
|
95
|
+
},
|
|
96
|
+
"rou3": {
|
|
97
|
+
"optional": true
|
|
95
98
|
}
|
|
96
99
|
},
|
|
97
|
-
"
|
|
100
|
+
"resolutions": {
|
|
101
|
+
"@eslint/plugin-kit": "^0.3.4"
|
|
102
|
+
},
|
|
103
|
+
"packageManager": "pnpm@10.19.0"
|
|
98
104
|
}
|