unjwt 0.5.25 → 0.5.27
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 +92 -50
- package/dist/adapters/h3.mjs +89 -31
- package/dist/adapters/h3v1.d.mts +1 -1
- package/dist/adapters/h3v2.d.mts +92 -50
- 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
|
@@ -7,38 +7,62 @@ import { H3Event } from 'h3';
|
|
|
7
7
|
import { c as JWSSignOptions } from '../shared/unjwt.BsLgL0DQ.mjs';
|
|
8
8
|
export { d as deriveJWKFromPassword, e as exportJWKToPEM, g as generateJWK, i as importJWKFromPEM } from '../shared/unjwt.BjP_dGnX.mjs';
|
|
9
9
|
|
|
10
|
+
type SessionData<T extends JWTClaims = JWTClaims> = Omit<T, "jti" | "iat" | "exp">;
|
|
11
|
+
type SessionUpdate<T extends JWTClaims = JWTClaims> = Partial<SessionData<T>> | ((oldData: SessionData<T>) => Partial<SessionData<T>> | undefined);
|
|
12
|
+
interface SessionManager<T extends JWTClaims = JWTClaims, ConfigMaxAge extends number | undefined = number | undefined> {
|
|
13
|
+
readonly id: string | undefined;
|
|
14
|
+
readonly createdAt: number;
|
|
15
|
+
readonly expiresAt: T extends {
|
|
16
|
+
exp: number;
|
|
17
|
+
} ? number : ConfigMaxAge;
|
|
18
|
+
readonly data: SessionData<T>;
|
|
19
|
+
update: (update: SessionUpdate<T>) => Promise<SessionManager<T>>;
|
|
20
|
+
clear: () => Promise<SessionManager<T>>;
|
|
21
|
+
}
|
|
22
|
+
|
|
10
23
|
/**
|
|
11
24
|
* This is a fork of h3 library's session utility functions.
|
|
12
25
|
* @source https://github.com/h3js/h3/blob/b4dce71c256911335f3402d09f30ffad120ad61a/src/utils/session.ts
|
|
13
26
|
* @license MIT https://github.com/h3js/h3/blob/b4dce71c256911335f3402d09f30ffad120ad61a/LICENSE
|
|
14
27
|
*/
|
|
15
28
|
|
|
16
|
-
type SessionDataT$1 = Omit<JWTClaims, "jti" | "iat" | "exp">;
|
|
17
|
-
type SessionData<T extends SessionDataT$1 = SessionDataT$1> = T;
|
|
18
29
|
declare const kGetSessionPromise$1: unique symbol;
|
|
19
|
-
interface SessionJWE<T extends
|
|
30
|
+
interface SessionJWE<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined> {
|
|
20
31
|
id: string;
|
|
21
32
|
createdAt: number;
|
|
22
|
-
expiresAt
|
|
33
|
+
expiresAt: T extends {
|
|
34
|
+
exp: number;
|
|
35
|
+
} ? number : MaxAge;
|
|
23
36
|
data: SessionData<T>;
|
|
24
|
-
[kGetSessionPromise$1]?: Promise<SessionJWE<T>>;
|
|
37
|
+
[kGetSessionPromise$1]?: Promise<SessionJWE<T, MaxAge>>;
|
|
25
38
|
}
|
|
26
|
-
interface SessionHooksJWE {
|
|
27
|
-
onRead?: (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
interface SessionHooksJWE<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined> {
|
|
40
|
+
onRead?: (args: {
|
|
41
|
+
session: SessionJWE<T, MaxAge>;
|
|
42
|
+
event: H3Event;
|
|
43
|
+
config: SessionConfigJWE<T, MaxAge>;
|
|
44
|
+
}) => void | Promise<void>;
|
|
45
|
+
onUpdate?: (args: {
|
|
46
|
+
session: SessionJWE<T, MaxAge>;
|
|
47
|
+
event: H3Event;
|
|
48
|
+
config: SessionConfigJWE<T, MaxAge>;
|
|
49
|
+
}) => void | Promise<void>;
|
|
50
|
+
onClear?: (args: {
|
|
51
|
+
event: H3Event;
|
|
52
|
+
config: Partial<SessionConfigJWE<T, MaxAge>>;
|
|
53
|
+
}) => void | Promise<void>;
|
|
54
|
+
onExpire?: (args: {
|
|
55
|
+
event: H3Event;
|
|
56
|
+
error: Error;
|
|
57
|
+
config: SessionConfigJWE<T, MaxAge>;
|
|
58
|
+
}) => void | Promise<void>;
|
|
59
|
+
onError?: (args: {
|
|
60
|
+
event: H3Event;
|
|
61
|
+
error: any;
|
|
62
|
+
config: SessionConfigJWE<T, MaxAge>;
|
|
63
|
+
}) => void | Promise<void>;
|
|
40
64
|
}
|
|
41
|
-
interface SessionConfigJWE {
|
|
65
|
+
interface SessionConfigJWE<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined> {
|
|
42
66
|
/** @deprecated use `key` instead */
|
|
43
67
|
secret?: string | JWK_Symmetric | {
|
|
44
68
|
privateKey: JWK_Private | JWK_Symmetric;
|
|
@@ -50,7 +74,7 @@ interface SessionConfigJWE {
|
|
|
50
74
|
publicKey?: JWK_Public;
|
|
51
75
|
};
|
|
52
76
|
/** Session lifetime in seconds (used to derive exp from iat) */
|
|
53
|
-
maxAge?:
|
|
77
|
+
maxAge?: MaxAge;
|
|
54
78
|
/** Default is "h3" */
|
|
55
79
|
name?: string;
|
|
56
80
|
/** Default is secure, httpOnly, path="/" */
|
|
@@ -64,7 +88,7 @@ interface SessionConfigJWE {
|
|
|
64
88
|
encryptOptions?: Omit<JWEEncryptOptions, "expiresIn">;
|
|
65
89
|
decryptOptions?: JWTClaimValidationOptions;
|
|
66
90
|
};
|
|
67
|
-
hooks?: SessionHooksJWE
|
|
91
|
+
hooks?: SessionHooksJWE<T, MaxAge>;
|
|
68
92
|
}
|
|
69
93
|
/**
|
|
70
94
|
* @deprecated use `SessionConfigJWE` instead
|
|
@@ -79,19 +103,18 @@ type CompatEvent$1 = {
|
|
|
79
103
|
headers: Headers;
|
|
80
104
|
context: any;
|
|
81
105
|
};
|
|
82
|
-
type SessionUpdate$1<T extends SessionDataT$1 = SessionDataT$1> = Partial<SessionData<T>> | ((oldData: SessionData<T>) => Partial<SessionData<T>> | undefined);
|
|
83
106
|
/**
|
|
84
107
|
* Create a session manager for the current request.
|
|
85
108
|
*/
|
|
86
|
-
declare function useJWESession<T extends
|
|
109
|
+
declare function useJWESession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: H3Event | CompatEvent$1, config: SessionConfigJWE<T, MaxAge>): Promise<SessionManager<T, MaxAge>>;
|
|
87
110
|
/**
|
|
88
111
|
* Get (and lazily initialize) the session for the current request.
|
|
89
112
|
*/
|
|
90
|
-
declare function getJWESession<T extends
|
|
113
|
+
declare function getJWESession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: H3Event | CompatEvent$1, config: SessionConfigJWE<T, MaxAge>): Promise<SessionJWE<T, MaxAge>>;
|
|
91
114
|
/**
|
|
92
115
|
* Update the session (optionally mutating the session data) and re-issue the JWE token.
|
|
93
116
|
*/
|
|
94
|
-
declare function updateJWESession<T extends
|
|
117
|
+
declare function updateJWESession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: H3Event, config: SessionConfigJWE<T, MaxAge>, update?: SessionUpdate<T>): Promise<SessionJWE<T, MaxAge>>;
|
|
95
118
|
/**
|
|
96
119
|
* Produce a JWE for the current session.
|
|
97
120
|
* Payload structure:
|
|
@@ -102,15 +125,15 @@ declare function updateJWESession<T extends SessionDataT$1 = SessionDataT$1>(eve
|
|
|
102
125
|
* data: Record<string, any>;
|
|
103
126
|
* }
|
|
104
127
|
*/
|
|
105
|
-
declare function sealJWESession<T extends
|
|
128
|
+
declare function sealJWESession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: H3Event | CompatEvent$1, config: SessionConfigJWE<T, MaxAge>): Promise<string>;
|
|
106
129
|
/**
|
|
107
130
|
* Decrypt the JWE and return a Session-compatible object.
|
|
108
131
|
*/
|
|
109
|
-
declare function unsealJWESession(_event: H3Event | CompatEvent$1, config: SessionConfigJWE, sealed: string): Promise<Partial<SessionJWE
|
|
132
|
+
declare function unsealJWESession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(_event: H3Event | CompatEvent$1, config: SessionConfigJWE<T, MaxAge>, sealed: string): Promise<Partial<SessionJWE<T, MaxAge>>>;
|
|
110
133
|
/**
|
|
111
134
|
* Clear the session (delete from context and drop cookie).
|
|
112
135
|
*/
|
|
113
|
-
declare function clearJWESession(event: H3Event, config: Partial<SessionConfigJWE
|
|
136
|
+
declare function clearJWESession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: H3Event, config: Partial<SessionConfigJWE<T, MaxAge>>): Promise<void>;
|
|
114
137
|
|
|
115
138
|
/**
|
|
116
139
|
* This is a fork of h3 library's session utility functions.
|
|
@@ -118,23 +141,43 @@ declare function clearJWESession(event: H3Event, config: Partial<SessionConfigJW
|
|
|
118
141
|
* @license MIT https://github.com/h3js/h3/blob/b4dce71c256911335f3402d09f30ffad120ad61a/LICENSE
|
|
119
142
|
*/
|
|
120
143
|
|
|
121
|
-
type SessionDataT = Omit<JWTClaims, "jti" | "iat" | "exp">;
|
|
122
144
|
declare const kGetSessionPromise: unique symbol;
|
|
123
|
-
interface SessionJWS<T extends
|
|
145
|
+
interface SessionJWS<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined> {
|
|
124
146
|
id: string;
|
|
125
147
|
createdAt: number;
|
|
126
|
-
expiresAt
|
|
148
|
+
expiresAt: T extends {
|
|
149
|
+
exp: number;
|
|
150
|
+
} ? number : MaxAge;
|
|
127
151
|
data: SessionData<T>;
|
|
128
|
-
[kGetSessionPromise]?: Promise<SessionJWS<T>>;
|
|
152
|
+
[kGetSessionPromise]?: Promise<SessionJWS<T, MaxAge>>;
|
|
129
153
|
}
|
|
130
|
-
interface SessionHooksJWS {
|
|
131
|
-
onRead?: (
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
154
|
+
interface SessionHooksJWS<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined> {
|
|
155
|
+
onRead?: (args: {
|
|
156
|
+
session: SessionJWS<T, MaxAge>;
|
|
157
|
+
event: H3Event;
|
|
158
|
+
config: SessionConfigJWS<T, MaxAge>;
|
|
159
|
+
}) => void | Promise<void>;
|
|
160
|
+
onUpdate?: (args: {
|
|
161
|
+
session: SessionJWS<T, MaxAge>;
|
|
162
|
+
event: H3Event;
|
|
163
|
+
config: SessionConfigJWS<T, MaxAge>;
|
|
164
|
+
}) => void | Promise<void>;
|
|
165
|
+
onClear?: (args: {
|
|
166
|
+
event: H3Event;
|
|
167
|
+
config: Partial<SessionConfigJWS<T, MaxAge>>;
|
|
168
|
+
}) => void | Promise<void>;
|
|
169
|
+
onExpire?: (args: {
|
|
170
|
+
event: H3Event;
|
|
171
|
+
error: Error;
|
|
172
|
+
config: SessionConfigJWS<T, MaxAge>;
|
|
173
|
+
}) => void | Promise<void>;
|
|
174
|
+
onError?: (args: {
|
|
175
|
+
event: H3Event;
|
|
176
|
+
error: any;
|
|
177
|
+
config: SessionConfigJWS<T, MaxAge>;
|
|
178
|
+
}) => void | Promise<void>;
|
|
136
179
|
}
|
|
137
|
-
interface SessionConfigJWS {
|
|
180
|
+
interface SessionConfigJWS<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined> {
|
|
138
181
|
/**
|
|
139
182
|
* JWK (private for signing with RS/ES/PS, or symmetric oct) used for signing.
|
|
140
183
|
*/
|
|
@@ -143,7 +186,7 @@ interface SessionConfigJWS {
|
|
|
143
186
|
publicKey: JWK_Public | JWK_Public[] | JWKSet;
|
|
144
187
|
};
|
|
145
188
|
/** Session lifetime in seconds (sets exp = iat + maxAge) */
|
|
146
|
-
maxAge?:
|
|
189
|
+
maxAge?: MaxAge;
|
|
147
190
|
/** Default cookie / header name base */
|
|
148
191
|
name?: string;
|
|
149
192
|
/** Cookie options (false to disable cookies) */
|
|
@@ -157,7 +200,7 @@ interface SessionConfigJWS {
|
|
|
157
200
|
signOptions?: Omit<JWSSignOptions, "expiresIn">;
|
|
158
201
|
verifyOptions?: JWTClaimValidationOptions;
|
|
159
202
|
};
|
|
160
|
-
hooks?: SessionHooksJWS
|
|
203
|
+
hooks?: SessionHooksJWS<T, MaxAge>;
|
|
161
204
|
}
|
|
162
205
|
/**
|
|
163
206
|
* @deprecated use `SessionConfigJWS` instead
|
|
@@ -172,26 +215,25 @@ type CompatEvent = {
|
|
|
172
215
|
headers: Headers;
|
|
173
216
|
context: any;
|
|
174
217
|
};
|
|
175
|
-
type SessionUpdate<T extends SessionDataT = SessionDataT> = Partial<SessionData<T>> | ((oldData: SessionData<T>) => Partial<SessionData<T>> | undefined);
|
|
176
218
|
/**
|
|
177
219
|
* Create a session manager for the current request using JWS (signed only, not encrypted).
|
|
178
220
|
* NOTE: Contents are visible to clients (Base64URL-decoded JSON). Do not store secrets in session data.
|
|
179
221
|
*/
|
|
180
|
-
declare function useJWSSession<T extends
|
|
222
|
+
declare function useJWSSession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: H3Event | CompatEvent, config: SessionConfigJWS<T, MaxAge>): Promise<SessionManager<T, MaxAge>>;
|
|
181
223
|
/**
|
|
182
224
|
* Retrieve (and lazily initialize) the session.
|
|
183
225
|
*/
|
|
184
|
-
declare function getJWSSession<T extends
|
|
226
|
+
declare function getJWSSession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: H3Event | CompatEvent, config: SessionConfigJWS<T, MaxAge>): Promise<SessionJWS<T, MaxAge>>;
|
|
185
227
|
/**
|
|
186
228
|
* Update session data (if provided) and reissue JWS.
|
|
187
229
|
*/
|
|
188
|
-
declare function updateJWSSession<T extends
|
|
230
|
+
declare function updateJWSSession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: H3Event, config: SessionConfigJWS<T, MaxAge>, update?: SessionUpdate<T>): Promise<SessionJWS<T, MaxAge>>;
|
|
189
231
|
/**
|
|
190
232
|
* Sign current session as a compact JWS.
|
|
191
233
|
* Payload claims:
|
|
192
234
|
* jti, iat, exp?, data, plus optional extraClaims (cannot override reserved)
|
|
193
235
|
*/
|
|
194
|
-
declare function signJWSSession<T extends
|
|
236
|
+
declare function signJWSSession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: H3Event | CompatEvent, config: SessionConfigJWS<T, MaxAge>): Promise<string>;
|
|
195
237
|
/**
|
|
196
238
|
* Verify and parse a compact JWS into a Session structure.
|
|
197
239
|
* Performs:
|
|
@@ -200,11 +242,11 @@ declare function signJWSSession<T extends SessionDataT = SessionDataT>(event: H3
|
|
|
200
242
|
* - ensures jti & iat presence
|
|
201
243
|
* - enforces maxAge if provided
|
|
202
244
|
*/
|
|
203
|
-
declare function verifyJWSSession(_event: H3Event | CompatEvent, config: SessionConfigJWS, token: string): Promise<Partial<SessionJWS
|
|
245
|
+
declare function verifyJWSSession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(_event: H3Event | CompatEvent, config: SessionConfigJWS<T, MaxAge>, token: string): Promise<Partial<SessionJWS<T, MaxAge>>>;
|
|
204
246
|
/**
|
|
205
247
|
* Destroy the session (context + cookie).
|
|
206
248
|
*/
|
|
207
|
-
declare function clearJWSSession(event: H3Event, config: Partial<SessionConfigJWS
|
|
249
|
+
declare function clearJWSSession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: H3Event, config: Partial<SessionConfigJWS<T, MaxAge>>): Promise<void>;
|
|
208
250
|
|
|
209
251
|
export { JWEEncryptOptions, JWKSet, JWK_Private, JWK_Public, JWK_Symmetric, JWTClaimValidationOptions, JWTClaims, clearJWESession, clearJWSSession, getJWESession, getJWSSession, sealJWESession, signJWSSession, unsealJWESession, updateJWESession, updateJWSSession, useJWESession, useJWSSession, verifyJWSSession };
|
|
210
|
-
export type { SessionConfigJWE, SessionConfigJWS, SessionData, SessionHooksJWE, SessionHooksJWS, SessionJWE, SessionJWEConfig, SessionJWS, SessionJWSConfig, SessionManager };
|
|
252
|
+
export type { SessionConfigJWE, SessionConfigJWS, SessionData, SessionHooksJWE, SessionHooksJWS, SessionJWE, SessionJWEConfig, SessionJWS, SessionJWSConfig, SessionManager, SessionUpdate };
|
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/h3v1.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { d as JWEDecryptOptions, e as JWEDecryptResult, b as JWEEncryptOptions, J as JWEHeaderParameters, c as JWEKeyLookupFunction, a as JWEKeyManagementHeaderParameters } from '../shared/unjwt.9mL1vSFP.mjs';
|
|
2
2
|
export { C as CompositeKey, f as ContentEncryptionAlgorithm, D as DeriveKeyOptions, e as DeriveKeyReturn, c as GenerateJWKOptions, d as GenerateJWKReturn, G as GenerateKeyAlgorithm, a as GenerateKeyOptions, b as GenerateKeyReturn, v as JWK, S as JWKAlgorithm, T as JWKPEMAlgorithm, J as JWKParameters, w as JWKSet, I as JWK_AES_CBC_HMAC, L as JWK_AES_GCM, H as JWK_AES_GCM_KW, F as JWK_AES_KW, s as JWK_Asymmetric, R as JWK_Asymmetric_Algorithm, j as JWK_EC, O as JWK_ECDH_ES, A as JWK_ECDSA, i as JWK_EC_Private, h as JWK_EC_Public, x as JWK_HMAC, p as JWK_OKP, o as JWK_OKP_Private, n as JWK_OKP_Public, P as JWK_OKP_SIGN, N as JWK_PBES2, u as JWK_Private, t as JWK_Public, m as JWK_RSA, B as JWK_RSA_ENC, z as JWK_RSA_PSS, l as JWK_RSA_Private, k as JWK_RSA_Public, y as JWK_RSA_SIGN, r as JWK_Symmetric, Q as JWK_Symmetric_Algorithm, q as JWK_oct, Y as JWT, Z as JWTClaimValidationOptions, X as JWTClaims, V as JoseHeaderParameters, K as KeyManagementAlgorithm, U as UnwrapKeyOptions, W as WrapKeyOptions, g as WrapKeyResult } from '../shared/unjwt.CtHrClHc.mjs';
|
|
3
|
-
export { SessionConfigJWE, SessionConfigJWS, SessionData, SessionHooksJWE, SessionHooksJWS, SessionJWE, SessionJWEConfig, SessionJWS, SessionJWSConfig, SessionManager, clearJWESession, clearJWSSession, getJWESession, getJWSSession, sealJWESession, signJWSSession, unsealJWESession, updateJWESession, updateJWSSession, useJWESession, useJWSSession, verifyJWSSession } from './h3.mjs';
|
|
3
|
+
export { SessionConfigJWE, SessionConfigJWS, SessionData, SessionHooksJWE, SessionHooksJWS, SessionJWE, SessionJWEConfig, SessionJWS, SessionJWSConfig, SessionManager, SessionUpdate, clearJWESession, clearJWSSession, getJWESession, getJWSSession, sealJWESession, signJWSSession, unsealJWESession, updateJWESession, updateJWSSession, useJWESession, useJWSSession, verifyJWSSession } from './h3.mjs';
|
|
4
4
|
export { d as deriveJWKFromPassword, e as exportJWKToPEM, g as generateJWK, i as importJWKFromPEM } from '../shared/unjwt.BjP_dGnX.mjs';
|
|
5
5
|
import 'cookie-es';
|
|
6
6
|
import 'h3';
|
package/dist/adapters/h3v2.d.mts
CHANGED
|
@@ -7,39 +7,63 @@ import { CookieSerializeOptions } from 'cookie-es';
|
|
|
7
7
|
import { c as JWSSignOptions } from '../shared/unjwt.BsLgL0DQ.mjs';
|
|
8
8
|
export { d as deriveJWKFromPassword, e as exportJWKToPEM, g as generateJWK, i as importJWKFromPEM } from '../shared/unjwt.BjP_dGnX.mjs';
|
|
9
9
|
|
|
10
|
-
type
|
|
11
|
-
type
|
|
10
|
+
type SessionData<T extends JWTClaims = JWTClaims> = Omit<T, "jti" | "iat" | "exp">;
|
|
11
|
+
type SessionUpdate<T extends JWTClaims = JWTClaims> = Partial<SessionData<T>> | ((oldData: SessionData<T>) => Partial<SessionData<T>> | undefined);
|
|
12
|
+
interface SessionManager<T extends JWTClaims = JWTClaims, ConfigMaxAge extends number | undefined = number | undefined> {
|
|
13
|
+
readonly id: string | undefined;
|
|
14
|
+
readonly createdAt: number;
|
|
15
|
+
readonly expiresAt: T extends {
|
|
16
|
+
exp: number;
|
|
17
|
+
} ? number : ConfigMaxAge;
|
|
18
|
+
readonly data: SessionData<T>;
|
|
19
|
+
update: (update: SessionUpdate<T>) => Promise<SessionManager<T>>;
|
|
20
|
+
clear: () => Promise<SessionManager<T>>;
|
|
21
|
+
}
|
|
22
|
+
|
|
12
23
|
declare const kGetSessionPromise$1: unique symbol;
|
|
13
|
-
interface SessionJWE<T extends
|
|
24
|
+
interface SessionJWE<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined> {
|
|
14
25
|
id: string;
|
|
15
26
|
createdAt: number;
|
|
16
|
-
expiresAt
|
|
27
|
+
expiresAt: T extends {
|
|
28
|
+
exp: number;
|
|
29
|
+
} ? number : MaxAge;
|
|
17
30
|
data: SessionData<T>;
|
|
18
|
-
[kGetSessionPromise$1]?: Promise<SessionJWE<T>>;
|
|
31
|
+
[kGetSessionPromise$1]?: Promise<SessionJWE<T, MaxAge>>;
|
|
19
32
|
}
|
|
20
|
-
interface SessionHooksJWE {
|
|
21
|
-
onRead?: (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
interface SessionHooksJWE<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined> {
|
|
34
|
+
onRead?: (args: {
|
|
35
|
+
session: SessionJWE<T, MaxAge>;
|
|
36
|
+
event: HTTPEvent;
|
|
37
|
+
config: SessionConfigJWE<T, MaxAge>;
|
|
38
|
+
}) => void | Promise<void>;
|
|
39
|
+
onUpdate?: (args: {
|
|
40
|
+
session: SessionJWE<T, MaxAge>;
|
|
41
|
+
event: HTTPEvent;
|
|
42
|
+
config: SessionConfigJWE<T, MaxAge>;
|
|
43
|
+
}) => void | Promise<void>;
|
|
44
|
+
onClear?: (args: {
|
|
45
|
+
event: HTTPEvent;
|
|
46
|
+
config: Partial<SessionConfigJWE<T, MaxAge>>;
|
|
47
|
+
}) => void | Promise<void>;
|
|
48
|
+
onExpire?: (args: {
|
|
49
|
+
event: HTTPEvent;
|
|
50
|
+
error: Error;
|
|
51
|
+
config: SessionConfigJWE<T, MaxAge>;
|
|
52
|
+
}) => void | Promise<void>;
|
|
53
|
+
onError?: (args: {
|
|
54
|
+
event: HTTPEvent;
|
|
55
|
+
error: any;
|
|
56
|
+
config: SessionConfigJWE<T, MaxAge>;
|
|
57
|
+
}) => void | Promise<void>;
|
|
34
58
|
}
|
|
35
|
-
interface SessionConfigJWE {
|
|
59
|
+
interface SessionConfigJWE<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined> {
|
|
36
60
|
/** Shared secret used, string for PBES2 or Json Web Key (JWK) */
|
|
37
61
|
key: string | JWK_Symmetric | {
|
|
38
62
|
privateKey: JWK_Private | JWK_Symmetric;
|
|
39
63
|
publicKey?: JWK_Public;
|
|
40
64
|
};
|
|
41
65
|
/** Session lifetime in seconds (used to derive exp from iat) */
|
|
42
|
-
maxAge?:
|
|
66
|
+
maxAge?: MaxAge;
|
|
43
67
|
/** Default is "h3" */
|
|
44
68
|
name?: string;
|
|
45
69
|
/** Default is secure, httpOnly, path="/" */
|
|
@@ -55,56 +79,75 @@ interface SessionConfigJWE {
|
|
|
55
79
|
encryptOptions?: Omit<JWEEncryptOptions, "expiresIn">;
|
|
56
80
|
decryptOptions?: JWTClaimValidationOptions;
|
|
57
81
|
};
|
|
58
|
-
hooks?: SessionHooksJWE
|
|
82
|
+
hooks?: SessionHooksJWE<T, MaxAge>;
|
|
59
83
|
}
|
|
60
|
-
type SessionUpdate$1<T extends SessionDataT$1 = SessionDataT$1> = Partial<SessionData<T>> | ((oldData: SessionData<T>) => Partial<SessionData<T>> | undefined);
|
|
61
84
|
/**
|
|
62
85
|
* Create a session manager for the current request.
|
|
63
86
|
*/
|
|
64
|
-
declare function useJWESession<T extends
|
|
87
|
+
declare function useJWESession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: HTTPEvent, config: SessionConfigJWE<T, MaxAge>): Promise<SessionManager<T, MaxAge>>;
|
|
65
88
|
/**
|
|
66
89
|
* Get the session for the current request.
|
|
67
90
|
*/
|
|
68
|
-
declare function getJWESession<T extends
|
|
91
|
+
declare function getJWESession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: HTTPEvent, config: SessionConfigJWE<T, MaxAge>): Promise<SessionJWE<T, MaxAge>>;
|
|
69
92
|
/**
|
|
70
93
|
* Update the session data for the current request.
|
|
71
94
|
*/
|
|
72
|
-
declare function updateJWESession<T extends
|
|
95
|
+
declare function updateJWESession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: HTTPEvent, config: SessionConfigJWE<T, MaxAge>, update?: SessionUpdate<T>): Promise<SessionJWE<T, MaxAge>>;
|
|
73
96
|
/**
|
|
74
97
|
* Produce a JWE for the current session.
|
|
75
98
|
*/
|
|
76
|
-
declare function sealJWESession<T extends
|
|
99
|
+
declare function sealJWESession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: HTTPEvent, config: SessionConfigJWE<T, MaxAge>): Promise<string>;
|
|
77
100
|
/**
|
|
78
101
|
* Decrypt the JWE and return a Session-compatible object.
|
|
79
102
|
*/
|
|
80
|
-
declare function unsealJWESession(_event: HTTPEvent, config: SessionConfigJWE, sealed: string): Promise<Partial<SessionJWE
|
|
103
|
+
declare function unsealJWESession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(_event: HTTPEvent, config: SessionConfigJWE<T, MaxAge>, sealed: string): Promise<Partial<SessionJWE<T, MaxAge>>>;
|
|
81
104
|
/**
|
|
82
105
|
* Clear the session (delete from context and drop cookie).
|
|
83
106
|
*/
|
|
84
|
-
declare function clearJWESession(event: HTTPEvent, config: Partial<SessionConfigJWE
|
|
107
|
+
declare function clearJWESession<T extends JWTClaims, MaxAge extends number | undefined>(event: HTTPEvent, config: Partial<SessionConfigJWE<T, MaxAge>>): Promise<void>;
|
|
85
108
|
|
|
86
|
-
type SessionDataT = Omit<JWTClaims, "jti" | "iat" | "exp">;
|
|
87
109
|
declare const kGetSessionPromise: unique symbol;
|
|
88
|
-
interface SessionJWS<T extends
|
|
110
|
+
interface SessionJWS<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined> {
|
|
89
111
|
id: string;
|
|
90
112
|
createdAt: number;
|
|
91
|
-
expiresAt
|
|
113
|
+
expiresAt: T extends {
|
|
114
|
+
exp: number;
|
|
115
|
+
} ? number : MaxAge;
|
|
92
116
|
data: SessionData<T>;
|
|
93
|
-
[kGetSessionPromise]?: Promise<SessionJWS<T>>;
|
|
117
|
+
[kGetSessionPromise]?: Promise<SessionJWS<T, MaxAge>>;
|
|
94
118
|
}
|
|
95
|
-
interface SessionHooksJWS {
|
|
96
|
-
onRead?: (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
119
|
+
interface SessionHooksJWS<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined> {
|
|
120
|
+
onRead?: (args: {
|
|
121
|
+
session: SessionJWS<T, MaxAge>;
|
|
122
|
+
event: HTTPEvent;
|
|
123
|
+
config: SessionConfigJWS<T, MaxAge>;
|
|
124
|
+
}) => void | Promise<void>;
|
|
125
|
+
onUpdate?: (args: {
|
|
126
|
+
session: SessionJWS<T, MaxAge>;
|
|
127
|
+
event: HTTPEvent;
|
|
128
|
+
config: SessionConfigJWS<T, MaxAge>;
|
|
129
|
+
}) => void | Promise<void>;
|
|
130
|
+
onClear?: (args: {
|
|
131
|
+
event: HTTPEvent;
|
|
132
|
+
config: Partial<SessionConfigJWS<T, MaxAge>>;
|
|
133
|
+
}) => void | Promise<void>;
|
|
134
|
+
onExpire?: (args: {
|
|
135
|
+
event: HTTPEvent;
|
|
136
|
+
error: Error;
|
|
137
|
+
config: SessionConfigJWS<T, MaxAge>;
|
|
138
|
+
}) => void | Promise<void>;
|
|
139
|
+
onError?: (args: {
|
|
140
|
+
event: HTTPEvent;
|
|
141
|
+
error: any;
|
|
142
|
+
config: SessionConfigJWS<T, MaxAge>;
|
|
143
|
+
}) => void | Promise<void>;
|
|
101
144
|
}
|
|
102
|
-
interface SessionConfigJWS {
|
|
145
|
+
interface SessionConfigJWS<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined> {
|
|
103
146
|
key: JWK_Symmetric | {
|
|
104
147
|
privateKey: JWK_Private;
|
|
105
148
|
publicKey: JWK_Public | JWK_Public[] | JWKSet;
|
|
106
149
|
};
|
|
107
|
-
maxAge?:
|
|
150
|
+
maxAge?: MaxAge;
|
|
108
151
|
name?: string;
|
|
109
152
|
cookie?: false | (CookieSerializeOptions & {
|
|
110
153
|
chunkMaxLength?: number;
|
|
@@ -115,15 +158,14 @@ interface SessionConfigJWS {
|
|
|
115
158
|
signOptions?: Omit<JWSSignOptions, "expiresIn">;
|
|
116
159
|
verifyOptions?: JWTClaimValidationOptions;
|
|
117
160
|
};
|
|
118
|
-
hooks?: SessionHooksJWS
|
|
161
|
+
hooks?: SessionHooksJWS<T, MaxAge>;
|
|
119
162
|
}
|
|
120
|
-
|
|
121
|
-
declare function
|
|
122
|
-
declare function
|
|
123
|
-
declare function
|
|
124
|
-
declare function
|
|
125
|
-
declare function
|
|
126
|
-
declare function clearJWSSession(event: HTTPEvent, config: Partial<SessionConfigJWS>): Promise<void>;
|
|
163
|
+
declare function useJWSSession<T extends JWTClaims, MaxAge extends number | undefined>(event: HTTPEvent, config: SessionConfigJWS<T, MaxAge>): Promise<SessionManager<T, MaxAge>>;
|
|
164
|
+
declare function getJWSSession<T extends JWTClaims, MaxAge extends number | undefined>(event: HTTPEvent, config: SessionConfigJWS<T, MaxAge>): Promise<SessionJWS<T, MaxAge>>;
|
|
165
|
+
declare function updateJWSSession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: HTTPEvent, config: SessionConfigJWS<T, MaxAge>, update?: SessionUpdate<T>): Promise<SessionJWS<T, MaxAge>>;
|
|
166
|
+
declare function signJWSSession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: HTTPEvent, config: SessionConfigJWS<T, MaxAge>): Promise<string>;
|
|
167
|
+
declare function verifyJWSSession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(_event: HTTPEvent, config: SessionConfigJWS<T, MaxAge>, token: string): Promise<Partial<SessionJWS<T, MaxAge>>>;
|
|
168
|
+
declare function clearJWSSession<T extends JWTClaims = JWTClaims, MaxAge extends number | undefined = number | undefined>(event: HTTPEvent, config: Partial<SessionConfigJWS<T, MaxAge>>): Promise<void>;
|
|
127
169
|
|
|
128
170
|
export { JWEEncryptOptions, JWKSet, JWK_Private, JWK_Public, JWK_Symmetric, JWTClaimValidationOptions, JWTClaims, clearJWESession, clearJWSSession, getJWESession, getJWSSession, sealJWESession, signJWSSession, unsealJWESession, updateJWESession, updateJWSSession, useJWESession, useJWSSession, verifyJWSSession };
|
|
129
|
-
export type { SessionConfigJWE, SessionConfigJWS, SessionData, SessionHooksJWE, SessionHooksJWS, SessionJWE, SessionJWS, SessionManager };
|
|
171
|
+
export type { SessionConfigJWE, SessionConfigJWS, SessionData, SessionHooksJWE, SessionHooksJWS, SessionJWE, SessionJWS, SessionManager, SessionUpdate };
|
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.27",
|
|
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
|
}
|