unjwt 0.5.9 → 0.5.11
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 +3 -3
- package/dist/index.d.mts +5 -6
- package/dist/index.mjs +5 -5
- package/dist/jwe.d.mts +2 -3
- package/dist/jwe.mjs +4 -4
- package/dist/jwk.d.mts +2 -3
- package/dist/jwk.mjs +2 -2
- package/dist/jws.d.mts +2 -3
- package/dist/jws.mjs +4 -4
- package/dist/shared/{unjwt.8w7jp2aw.d.mts → unjwt.BvhKNVNR.d.mts} +28 -30
- package/dist/shared/{unjwt.D9da8HQF.d.mts → unjwt.CN1C8TlR.d.mts} +90 -15
- package/dist/shared/{unjwt.Ca03jPX3.mjs → unjwt.C_D0RMCp.mjs} +1 -1
- package/dist/shared/unjwt.Ce8yMcp_.mjs +298 -0
- package/dist/shared/{unjwt.DH1p_WL8.d.mts → unjwt.Cz90HQhy.d.mts} +11 -12
- package/dist/shared/{unjwt.B2olxeGL.mjs → unjwt.DVMpKj8x.mjs} +22 -86
- package/dist/shared/unjwt.D_JFPtpW.mjs +161 -0
- package/dist/shared/{unjwt.DRUXIabl.mjs → unjwt.DuBBF25X.mjs} +19 -8
- package/dist/shared/{unjwt.D_Mabhgz.d.mts → unjwt.QRureeXk.d.mts} +14 -70
- package/dist/shared/unjwt.df8yQ5_5.d.mts +128 -0
- package/dist/utils.d.mts +2 -2
- package/dist/utils.mjs +1 -1
- package/package.json +12 -11
- package/dist/shared/unjwt.BHpknTpg.mjs +0 -93
- package/dist/shared/unjwt.BvIkEGGz.d.mts +0 -52
- package/dist/shared/unjwt.CbvzYE-m.d.mts +0 -58
- package/dist/shared/unjwt.wHjOCapq.mjs +0 -279
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
import { i as importKey, g as getJWKFromSet } from './unjwt.DRUXIabl.mjs';
|
|
2
|
-
import { a as isJWK, b as base64UrlEncode, t as textEncoder, c as textDecoder, d as base64UrlDecode, e as isJWKSet, m as maybeArray } from './unjwt.BHpknTpg.mjs';
|
|
3
|
-
import { s as sign$1, v as verify$1 } from './unjwt.Ca03jPX3.mjs';
|
|
4
|
-
|
|
5
|
-
async function sign(payload, key, options = {}) {
|
|
6
|
-
const { protectedHeader: additionalProtectedHeader } = options;
|
|
7
|
-
let { alg } = options;
|
|
8
|
-
if (!alg) {
|
|
9
|
-
if (isJWK(key) && key.alg) {
|
|
10
|
-
alg = key.alg;
|
|
11
|
-
} else {
|
|
12
|
-
throw new TypeError('JWS "alg" (Algorithm) must be provided in options');
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
validateKeyLength(key, alg);
|
|
16
|
-
const signingKey = await importKey(key, alg);
|
|
17
|
-
const protectedHeader = {
|
|
18
|
-
...additionalProtectedHeader,
|
|
19
|
-
...isJWK(key) && key.kid ? { kid: additionalProtectedHeader?.kid || key.kid } : {},
|
|
20
|
-
// Include kid if available
|
|
21
|
-
alg,
|
|
22
|
-
typ: additionalProtectedHeader?.typ ?? (typeof payload === "object" && !(payload instanceof Uint8Array) ? "JWT" : void 0)
|
|
23
|
-
// Default typ to JWT for objects
|
|
24
|
-
};
|
|
25
|
-
if (protectedHeader.typ === void 0 && typeof payload === "object" && !(payload instanceof Uint8Array)) {
|
|
26
|
-
protectedHeader.typ = "JWT";
|
|
27
|
-
protectedHeader.cty ||= "json";
|
|
28
|
-
}
|
|
29
|
-
if (protectedHeader.b64 === true) {
|
|
30
|
-
delete protectedHeader.b64;
|
|
31
|
-
}
|
|
32
|
-
let computedPayload = void 0;
|
|
33
|
-
if (options.expiresIn !== void 0 && protectedHeader.typ === "JWT" && typeof payload === "object" && !(payload instanceof Uint8Array) && !payload.exp) {
|
|
34
|
-
computedPayload = { ...payload };
|
|
35
|
-
const currentTime = Math.round(
|
|
36
|
-
(options.currentDate ?? /* @__PURE__ */ new Date()).getTime() / 1e3
|
|
37
|
-
);
|
|
38
|
-
computedPayload.iat ||= currentTime;
|
|
39
|
-
computedPayload.exp = currentTime + options.expiresIn;
|
|
40
|
-
}
|
|
41
|
-
const protectedHeaderString = JSON.stringify(protectedHeader);
|
|
42
|
-
const protectedHeaderEncoded = base64UrlEncode(protectedHeaderString);
|
|
43
|
-
let payloadBytes;
|
|
44
|
-
if (payload instanceof Uint8Array) {
|
|
45
|
-
payloadBytes = payload;
|
|
46
|
-
} else if (typeof payload === "string") {
|
|
47
|
-
payloadBytes = textEncoder.encode(payload);
|
|
48
|
-
} else if (typeof payload === "object" && payload !== null) {
|
|
49
|
-
payloadBytes = textEncoder.encode(
|
|
50
|
-
JSON.stringify(computedPayload || payload)
|
|
51
|
-
);
|
|
52
|
-
} else {
|
|
53
|
-
throw new TypeError(
|
|
54
|
-
"Payload must be a string, Uint8Array, or a JSON-serializable object."
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
const useB64 = protectedHeader.b64 !== false;
|
|
58
|
-
const payloadEncoded = useB64 ? base64UrlEncode(payloadBytes) : textDecoder.decode(payloadBytes);
|
|
59
|
-
const signingInputString = `${protectedHeaderEncoded}.${payloadEncoded}`;
|
|
60
|
-
const signingInputBytes = textEncoder.encode(signingInputString);
|
|
61
|
-
const signatureBytes = await sign$1(alg, signingKey, signingInputBytes);
|
|
62
|
-
const signatureEncoded = base64UrlEncode(signatureBytes);
|
|
63
|
-
return `${signingInputString}.${signatureEncoded}`;
|
|
64
|
-
}
|
|
65
|
-
async function verify(jws, key, options = {}) {
|
|
66
|
-
const parts = jws.split(".");
|
|
67
|
-
if (parts.length !== 3) {
|
|
68
|
-
throw new Error("Invalid JWS: Must contain three parts separated by dots.");
|
|
69
|
-
}
|
|
70
|
-
const [protectedHeaderEncoded, payloadEncoded, signatureEncoded] = parts;
|
|
71
|
-
let protectedHeader;
|
|
72
|
-
try {
|
|
73
|
-
const protectedHeaderString = base64UrlDecode(protectedHeaderEncoded);
|
|
74
|
-
protectedHeader = JSON.parse(protectedHeaderString);
|
|
75
|
-
} catch (error_) {
|
|
76
|
-
throw new Error(
|
|
77
|
-
`Invalid JWS: Protected header is not valid Base64URL or JSON (${error_ instanceof Error ? error_.message : error_})`
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
if (!protectedHeader || typeof protectedHeader !== "object" || !protectedHeader.alg) {
|
|
81
|
-
throw new Error(
|
|
82
|
-
'Invalid JWS: Protected header must be an object with an "alg" property.'
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
const alg = protectedHeader.alg;
|
|
86
|
-
if (options.algorithms && !options.algorithms.includes(alg)) {
|
|
87
|
-
throw new Error(`Algorithm not allowed: ${alg}`);
|
|
88
|
-
}
|
|
89
|
-
if (options.typ && protectedHeader.typ !== options.typ) {
|
|
90
|
-
throw new Error(
|
|
91
|
-
`Invalid JWS: "typ" (Type) Header Parameter mismatch. Expected "${options.typ}", got "${protectedHeader.typ}".`
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
let signatureBytes;
|
|
95
|
-
try {
|
|
96
|
-
signatureBytes = base64UrlDecode(signatureEncoded, false);
|
|
97
|
-
} catch (error_) {
|
|
98
|
-
throw new Error(
|
|
99
|
-
`Invalid JWS: Signature is not valid Base64URL (${error_ instanceof Error ? error_.message : error_})`
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
const keyInput = typeof key === "function" ? await key(protectedHeader, jws) : key;
|
|
103
|
-
const resolvedKey = isJWKSet(keyInput) ? getJWKFromSet(keyInput, protectedHeader) : keyInput;
|
|
104
|
-
const verificationKey = await importKey(resolvedKey, alg);
|
|
105
|
-
const signingInputString = `${protectedHeaderEncoded}.${payloadEncoded}`;
|
|
106
|
-
const signingInputBytes = textEncoder.encode(signingInputString);
|
|
107
|
-
const isValid = await verify$1(
|
|
108
|
-
alg,
|
|
109
|
-
verificationKey,
|
|
110
|
-
signatureBytes,
|
|
111
|
-
signingInputBytes
|
|
112
|
-
);
|
|
113
|
-
if (!isValid) {
|
|
114
|
-
throw new Error("JWS signature verification failed.");
|
|
115
|
-
}
|
|
116
|
-
const useB64 = protectedHeader.b64 !== false;
|
|
117
|
-
let payload;
|
|
118
|
-
try {
|
|
119
|
-
if (useB64) {
|
|
120
|
-
if (options.forceUint8Array) {
|
|
121
|
-
payload = base64UrlDecode(payloadEncoded, false);
|
|
122
|
-
} else {
|
|
123
|
-
const cty = protectedHeader.cty?.toLowerCase();
|
|
124
|
-
const isJsonOutput = protectedHeader.typ === "JWT" || cty === "json" || cty === "application/json" || cty && cty.endsWith("+json");
|
|
125
|
-
const decodedString = base64UrlDecode(payloadEncoded);
|
|
126
|
-
if (isJsonOutput) {
|
|
127
|
-
if (decodedString.startsWith("{") && decodedString.endsWith("}") || decodedString.startsWith("[") && decodedString.endsWith("]")) {
|
|
128
|
-
try {
|
|
129
|
-
payload = JSON.parse(decodedString);
|
|
130
|
-
} catch {
|
|
131
|
-
payload = decodedString;
|
|
132
|
-
}
|
|
133
|
-
} else {
|
|
134
|
-
payload = decodedString;
|
|
135
|
-
}
|
|
136
|
-
} else {
|
|
137
|
-
payload = decodedString;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
} else {
|
|
141
|
-
payload = options.forceUint8Array ? textEncoder.encode(payloadEncoded) : payloadEncoded;
|
|
142
|
-
}
|
|
143
|
-
} catch (error_) {
|
|
144
|
-
throw new Error(
|
|
145
|
-
`Invalid JWS: Payload decoding failed (${error_ instanceof Error ? error_.message : error_})`
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
if (protectedHeader.crit) {
|
|
149
|
-
const missingHeaderParams = /* @__PURE__ */ new Set();
|
|
150
|
-
const recognizedParams = /* @__PURE__ */ new Set([
|
|
151
|
-
...options.critical || [],
|
|
152
|
-
// TODO: remove deprecated option
|
|
153
|
-
...options.requiredHeaders || [],
|
|
154
|
-
"alg",
|
|
155
|
-
"typ",
|
|
156
|
-
"cty",
|
|
157
|
-
"kid",
|
|
158
|
-
"jwk",
|
|
159
|
-
"jku",
|
|
160
|
-
"x5c",
|
|
161
|
-
"x5t",
|
|
162
|
-
"x5u",
|
|
163
|
-
"b64"
|
|
164
|
-
]);
|
|
165
|
-
for (const param of protectedHeader.crit) {
|
|
166
|
-
if (recognizedParams.has(param) && (param in protectedHeader || param === "b64")) {
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
missingHeaderParams.add(param);
|
|
170
|
-
}
|
|
171
|
-
if (missingHeaderParams.size > 0) {
|
|
172
|
-
throw new Error(
|
|
173
|
-
`Missing critical header parameters: ${[...missingHeaderParams].join(", ")}`
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
if (payload && typeof payload === "object" && protectedHeader.typ === "JWT" && !options.forceUint8Array) {
|
|
178
|
-
const jwtClaims = payload;
|
|
179
|
-
const clockTolerance = options.clockTolerance ?? 0;
|
|
180
|
-
const currentTime = Math.round(
|
|
181
|
-
(options.currentDate ?? /* @__PURE__ */ new Date()).getTime() / 1e3
|
|
182
|
-
);
|
|
183
|
-
const allRequiredClaims = new Set(options.requiredClaims || []);
|
|
184
|
-
const missingClaims = /* @__PURE__ */ new Set();
|
|
185
|
-
if (options.issuer) allRequiredClaims.add("iss");
|
|
186
|
-
if (options.audience) allRequiredClaims.add("aud");
|
|
187
|
-
if (options.subject) allRequiredClaims.add("sub");
|
|
188
|
-
if (options.maxTokenAge) allRequiredClaims.add("iat");
|
|
189
|
-
for (const claimName of allRequiredClaims) {
|
|
190
|
-
if (!(claimName in jwtClaims)) {
|
|
191
|
-
missingClaims.add(claimName);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
if (missingClaims.size > 0) {
|
|
195
|
-
throw new Error(
|
|
196
|
-
`Missing required JWT Claims: ${[...missingClaims].join(", ")}`
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
if (options.issuer) {
|
|
200
|
-
const expectedIssuers = maybeArray(options.issuer);
|
|
201
|
-
if (!jwtClaims.iss || !expectedIssuers.includes(jwtClaims.iss)) {
|
|
202
|
-
throw new Error(
|
|
203
|
-
`Invalid JWT "iss" (Issuer) Claim: Expected ${expectedIssuers.join(" or ")}, got ${jwtClaims.iss}`
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
if (options.subject && jwtClaims.sub !== options.subject) {
|
|
208
|
-
throw new Error(
|
|
209
|
-
`Invalid JWT "sub" (Subject) Claim: Expected ${options.subject}, got ${jwtClaims.sub}`
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
if (options.audience) {
|
|
213
|
-
const expectedAudiences = maybeArray(options.audience);
|
|
214
|
-
const claimAudience = maybeArray(jwtClaims.aud || []);
|
|
215
|
-
if (!claimAudience.some((aud) => expectedAudiences.includes(aud))) {
|
|
216
|
-
throw new Error(
|
|
217
|
-
`Invalid JWT "aud" (Audience) Claim: Expected ${expectedAudiences.join(" or ")}, got ${claimAudience.join(", ")}`
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
if (typeof jwtClaims.nbf === "number" && jwtClaims.nbf > currentTime + clockTolerance) {
|
|
222
|
-
throw new Error(
|
|
223
|
-
`JWT "nbf" (Not Before) Claim validation failed: Token is not yet valid (nbf: ${new Date(jwtClaims.nbf * 1e3).toISOString()})`
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
if (typeof jwtClaims.exp === "number" && jwtClaims.exp <= currentTime - clockTolerance) {
|
|
227
|
-
throw new Error(
|
|
228
|
-
`JWT "exp" (Expiration Time) Claim validation failed: Token has expired (exp: ${new Date(jwtClaims.exp * 1e3).toISOString()})`
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
if (options.maxTokenAge) {
|
|
232
|
-
if (typeof jwtClaims.iat !== "number") {
|
|
233
|
-
throw new TypeError(
|
|
234
|
-
'JWT "iat" (Issued At) Claim must be a number when maxTokenAge is set.'
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
if (jwtClaims.iat > currentTime + clockTolerance) {
|
|
238
|
-
throw new Error(
|
|
239
|
-
`JWT "iat" (Issued At) Claim validation failed: Token was issued in the future (iat: ${new Date(jwtClaims.iat * 1e3).toISOString()})`
|
|
240
|
-
);
|
|
241
|
-
}
|
|
242
|
-
if (jwtClaims.iat < currentTime - options.maxTokenAge - clockTolerance) {
|
|
243
|
-
throw new Error(
|
|
244
|
-
`JWT "iat" (Issued At) Claim validation failed: Token is too old (maxTokenAge: ${options.maxTokenAge}s, iat: ${new Date(jwtClaims.iat * 1e3).toISOString()})`
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return {
|
|
250
|
-
payload,
|
|
251
|
-
protectedHeader
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
function validateKeyLength(key, alg) {
|
|
255
|
-
if (!alg || isJWK(key)) return;
|
|
256
|
-
if (alg.startsWith("HS") && key instanceof Uint8Array) {
|
|
257
|
-
const algLength = Number.parseInt(alg.slice(2)) / 8;
|
|
258
|
-
if (key.length < algLength) {
|
|
259
|
-
throw new TypeError(
|
|
260
|
-
`${alg} requires key length to be ${algLength} bytes or larger`
|
|
261
|
-
);
|
|
262
|
-
}
|
|
263
|
-
} else if ((alg.startsWith("RS") || alg.startsWith("PS")) && key instanceof CryptoKey) {
|
|
264
|
-
const { modulusLength } = key.algorithm;
|
|
265
|
-
if (typeof modulusLength !== "number" || modulusLength < 2048) {
|
|
266
|
-
throw new TypeError(
|
|
267
|
-
`${alg} requires key modulusLength to be 2048 bits or larger`
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const jws = {
|
|
274
|
-
__proto__: null,
|
|
275
|
-
sign: sign,
|
|
276
|
-
verify: verify
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
export { jws as j, sign as s, verify as v };
|