unjwt 0.7.2 → 0.8.0

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.
Files changed (39) hide show
  1. package/README.md +4 -4
  2. package/dist/THIRD-PARTY-LICENSES.md.gz +0 -0
  3. package/dist/_chunks/_codec-jwe.d.mts +170 -0
  4. package/dist/_chunks/_codec-jws.mjs +878 -0
  5. package/dist/_chunks/_internal.d.mts +7 -0
  6. package/dist/_chunks/_jwt-internal.mjs +388 -0
  7. package/dist/_chunks/algorithms.mjs +186 -0
  8. package/dist/_chunks/index.d.mts +512 -818
  9. package/dist/_chunks/index2.d.mts +11 -0
  10. package/dist/_chunks/index3.d.mts +108 -0
  11. package/dist/_chunks/jwe.d.mts +43 -66
  12. package/dist/_chunks/jwe.mjs +384 -252
  13. package/dist/_chunks/jwk.mjs +1390 -622
  14. package/dist/_chunks/jws.d.mts +48 -103
  15. package/dist/_chunks/jws.mjs +372 -184
  16. package/dist/_chunks/jwt.d.mts +56 -0
  17. package/dist/_chunks/libs/unsecure.d.mts +164 -85
  18. package/dist/_chunks/libs/unsecure.mjs +390 -123
  19. package/dist/adapters/elysia/index.d.mts +33 -171
  20. package/dist/adapters/elysia/index.mjs +106 -575
  21. package/dist/adapters/h3v1/index.d.mts +59 -344
  22. package/dist/adapters/h3v1/index.mjs +114 -619
  23. package/dist/adapters/h3v2/index.d.mts +58 -326
  24. package/dist/adapters/h3v2/index.mjs +108 -611
  25. package/dist/core/internal.d.mts +2 -0
  26. package/dist/core/internal.mjs +1 -0
  27. package/dist/core/jwe.d.mts +4 -2
  28. package/dist/core/jwe.mjs +4 -2
  29. package/dist/core/jwk.d.mts +183 -371
  30. package/dist/core/jwk.mjs +4 -3
  31. package/dist/core/jws.d.mts +4 -2
  32. package/dist/core/jws.mjs +4 -2
  33. package/dist/core/utils/index.d.mts +5 -155
  34. package/dist/core/utils/index.mjs +12 -3
  35. package/dist/index.d.mts +8 -4
  36. package/dist/index.mjs +6 -3
  37. package/package.json +39 -36
  38. package/dist/_chunks/_internal.mjs +0 -88
  39. package/dist/_chunks/utils.mjs +0 -390
@@ -1,5 +1,16 @@
1
- import { JWTError, assertCryptoKey, concatUint8Arrays, isAsymmetricJWK, isCryptoKey, isCryptoKeyPair, isJWK, isJWKSet } from "./utils.mjs";
2
- import { base64Decode, base64Encode, base64UrlDecode, base64UrlEncode, sanitizeObjectCopy, secureRandomBytes, textEncoder } from "./libs/unsecure.mjs";
1
+ import { safeJsonParse, sanitizeObjectCopy, secureRandomBytes, textEncoder } from "./libs/unsecure.mjs";
2
+ import { JWTError, assertClaimValidationOptions, assertCritShape, assertCryptoKey, assertPlainObject, assertStringList, base64Parse, base64Stringify, base64UrlParse, base64UrlStringify, concatUint8Arrays, isCryptoKey, isCryptoKeyPair, isJWK, isJWKSet, isPlainObject, parsePayloadBytes, parsePayloadSegment, uint32be, validateJwtClaims } from "./_jwt-internal.mjs";
3
+ import { ECDSA_CURVES, PBES2_ALGORITHMS, aesBitsOf, checkKeyUsage, cryptoKeyCurve, hashBitsOf, inferJWEAllowedAlgorithms, inferJWSAllowedAlgorithms, innerKeyWrapAlg, isAlgorithm, isContentEncryptionAlgorithm, isEd25519Signature, jwsHashOf, lengthOf, modulusLengthOf, namedCurveOf, rsaOaepHashOf, unusableKey } from "./algorithms.mjs";
4
+ const MAX_QUOTED_VALUE = 64;
5
+ function quoteTokenValue(value) {
6
+ const text = String(value);
7
+ return JSON.stringify(text.length > MAX_QUOTED_VALUE ? `${text.slice(0, MAX_QUOTED_VALUE)}…` : text);
8
+ }
9
+ const HASHED_SIGNATURE_ALGORITHMS = {
10
+ HS: "HMAC",
11
+ RS: "RSASSA-PKCS1-v1_5",
12
+ PS: "RSA-PSS"
13
+ };
3
14
  async function sign(alg, key, data) {
4
15
  checkSigCryptoKey(key, alg, "sign");
5
16
  const signature = await crypto.subtle.sign(subtleAlgorithm(alg, key.algorithm), key, data);
@@ -17,46 +28,37 @@ function checkSigCryptoKey(key, alg, usage) {
17
28
  switch (alg) {
18
29
  case "HS256":
19
30
  case "HS384":
20
- case "HS512": {
21
- if (!isAlgorithm$3(key.algorithm, "HMAC")) throw unusable$4("HMAC");
22
- const expected = Number.parseInt(alg.slice(2), 10);
23
- if (getHashLength$1(key.algorithm.hash) !== expected) throw unusable$4(`SHA-${expected}`, "algorithm.hash");
24
- break;
25
- }
31
+ case "HS512":
26
32
  case "RS256":
27
33
  case "RS384":
28
- case "RS512": {
29
- if (!isAlgorithm$3(key.algorithm, "RSASSA-PKCS1-v1_5")) throw unusable$4("RSASSA-PKCS1-v1_5");
30
- const expected = Number.parseInt(alg.slice(2), 10);
31
- if (getHashLength$1(key.algorithm.hash) !== expected) throw unusable$4(`SHA-${expected}`, "algorithm.hash");
32
- break;
33
- }
34
+ case "RS512":
34
35
  case "PS256":
35
36
  case "PS384":
36
37
  case "PS512": {
37
- if (!isAlgorithm$3(key.algorithm, "RSA-PSS")) throw unusable$4("RSA-PSS");
38
+ const name = HASHED_SIGNATURE_ALGORITHMS[alg.slice(0, 2)];
39
+ if (!isAlgorithm(key.algorithm, name)) throw unusableKey(name);
38
40
  const expected = Number.parseInt(alg.slice(2), 10);
39
- if (getHashLength$1(key.algorithm.hash) !== expected) throw unusable$4(`SHA-${expected}`, "algorithm.hash");
41
+ if (hashBitsOf(key.algorithm.hash) !== expected) throw unusableKey(`SHA-${expected}`, "algorithm.hash");
40
42
  break;
41
43
  }
42
44
  case "Ed25519":
43
45
  case "EdDSA":
44
- if (!isAlgorithm$3(key.algorithm, "Ed25519")) throw unusable$4("Ed25519");
46
+ if (!isAlgorithm(key.algorithm, "Ed25519")) throw unusableKey("Ed25519");
45
47
  break;
46
48
  case "ES256":
47
49
  case "ES384":
48
50
  case "ES512": {
49
- if (!isAlgorithm$3(key.algorithm, "ECDSA")) throw unusable$4("ECDSA");
50
- const expected = getNamedCurve$1(alg);
51
- if (key.algorithm.namedCurve !== expected) throw unusable$4(expected, "algorithm.namedCurve");
51
+ if (!isAlgorithm(key.algorithm, "ECDSA")) throw unusableKey("ECDSA");
52
+ const expected = ECDSA_CURVES[alg];
53
+ if (key.algorithm.namedCurve !== expected) throw unusableKey(expected, "algorithm.namedCurve");
52
54
  break;
53
55
  }
54
- default: throw new TypeError("CryptoKey does not support this operation");
56
+ default: throw new JWTError("CryptoKey does not support this operation", "ERR_JWK_INVALID");
55
57
  }
56
- checkUsage$4(key, usage);
58
+ checkKeyUsage(key, usage);
57
59
  }
58
60
  function subtleAlgorithm(alg, algorithm) {
59
- const hash = `SHA-${alg.slice(-3)}`;
61
+ const hash = jwsHashOf(alg);
60
62
  switch (alg) {
61
63
  case "HS256":
62
64
  case "HS384":
@@ -82,66 +84,65 @@ function subtleAlgorithm(alg, algorithm) {
82
84
  case "ES512": return {
83
85
  hash,
84
86
  name: "ECDSA",
85
- namedCurve: algorithm.namedCurve
87
+ namedCurve: namedCurveOf(algorithm)
86
88
  };
87
89
  case "Ed25519":
88
90
  case "EdDSA": return { name: "Ed25519" };
89
- default: throw new Error(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
90
- }
91
- }
92
- function unusable$4(name, prop = "algorithm.name") {
93
- return /* @__PURE__ */ new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
94
- }
95
- function isAlgorithm$3(algorithm, name) {
96
- return algorithm.name === name;
97
- }
98
- function getHashLength$1(hash) {
99
- return Number.parseInt(hash.name.slice(4), 10);
100
- }
101
- function getNamedCurve$1(alg) {
102
- switch (alg) {
103
- case "ES256": return "P-256";
104
- case "ES384": return "P-384";
105
- case "ES512": return "P-521";
106
- default: throw new Error("unreachable");
91
+ default: throw new JWTError(`alg ${alg} is not supported either by JOSE or your javascript runtime`, "ERR_JWS_ALG_NOT_ALLOWED");
107
92
  }
108
93
  }
109
- function checkUsage$4(key, usage) {
110
- if (usage && !key.usages.includes(usage)) throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
111
- }
112
94
  const IV_BIT_LENGTHS = {
113
- A128GCM: 96,
114
- A128GCMKW: 96,
115
- A192GCM: 96,
116
- A192GCMKW: 96,
117
- A256GCM: 96,
118
- A256GCMKW: 96,
95
+ "A128GCM": 96,
96
+ "A128GCMKW": 96,
97
+ "A192GCM": 96,
98
+ "A192GCMKW": 96,
99
+ "A256GCM": 96,
100
+ "A256GCMKW": 96,
119
101
  "A128CBC-HS256": 128,
120
102
  "A192CBC-HS384": 128,
121
103
  "A256CBC-HS512": 128
122
104
  };
123
105
  const CEK_BIT_LENGTHS = {
124
- A128GCM: 128,
125
- A192GCM: 192,
126
- A256GCM: 256,
106
+ "A128GCM": 128,
107
+ "A192GCM": 192,
108
+ "A256GCM": 256,
127
109
  "A128CBC-HS256": 256,
128
110
  "A192CBC-HS384": 384,
129
111
  "A256CBC-HS512": 512
130
112
  };
131
113
  function bitLengthIV(alg) {
132
114
  const length = IV_BIT_LENGTHS[alg];
133
- if (length === void 0) throw new Error(`Unsupported JWE Algorithm: ${alg}`);
115
+ if (length === void 0) throw new JWTError(`Unsupported JWE Algorithm: ${quoteTokenValue(alg)}`, "ERR_JWE_INVALID");
134
116
  return length;
135
117
  }
136
118
  function generateIV(alg) {
137
119
  return crypto.getRandomValues(new Uint8Array(bitLengthIV(alg) >> 3));
138
120
  }
139
121
  function checkIvLength(enc, iv) {
140
- if (iv.length << 3 !== bitLengthIV(enc)) throw new Error("Invalid Initialization Vector length");
122
+ if (iv.length << 3 !== bitLengthIV(enc)) throw new JWTError("Invalid Initialization Vector length", "ERR_JWE_INVALID");
123
+ }
124
+ const TAG_BIT_LENGTHS = {
125
+ "A128GCM": 128,
126
+ "A128GCMKW": 128,
127
+ "A192GCM": 128,
128
+ "A192GCMKW": 128,
129
+ "A256GCM": 128,
130
+ "A256GCMKW": 128,
131
+ "A128CBC-HS256": 128,
132
+ "A192CBC-HS384": 192,
133
+ "A256CBC-HS512": 256
134
+ };
135
+ function bitLengthTag(alg) {
136
+ const length = TAG_BIT_LENGTHS[alg];
137
+ if (length === void 0) throw new JWTError(`Unsupported JWE Algorithm: ${quoteTokenValue(alg)}`, "ERR_JWE_INVALID");
138
+ return length;
139
+ }
140
+ function checkTagLength(enc, tag) {
141
+ if (tag.length << 3 !== bitLengthTag(enc)) throw new JWTError("Invalid Authentication Tag length", "ERR_JWE_INVALID");
141
142
  }
142
143
  function bitLengthCEK(alg) {
143
144
  const length = CEK_BIT_LENGTHS[alg];
144
- if (length === void 0) throw new Error(`Unsupported JWE Algorithm: ${alg}`);
145
+ if (length === void 0) throw new JWTError(`Unsupported JWE Algorithm: ${quoteTokenValue(alg)}`, "ERR_JWE_INVALID");
145
146
  return length;
146
147
  }
147
148
  function generateCEK(alg) {
@@ -149,7 +150,7 @@ function generateCEK(alg) {
149
150
  }
150
151
  function checkCEKLength(cek, expected) {
151
152
  const actual = cek.byteLength << 3;
152
- if (actual !== expected) throw new Error(`Invalid Content Encryption Key length. Expected ${expected} bits, got ${actual} bits`);
153
+ if (actual !== expected) throw new JWTError(`Invalid Content Encryption Key length. Expected ${expected} bits, got ${actual} bits`, "ERR_INVALID_OPTION");
153
154
  }
154
155
  function assertOctKeyLength(bytes, alg) {
155
156
  if (!alg) return;
@@ -158,30 +159,26 @@ function assertOctKeyLength(bytes, alg) {
158
159
  if (bytes.length < minBytes) throw new JWTError(`${alg} requires a key of at least ${minBytes} bytes (got ${bytes.length})`, "ERR_JWK_INVALID");
159
160
  return;
160
161
  }
161
- const exactBits = /^A(128|192|256)(GCM)?KW$/.test(alg) ? Number.parseInt(alg.slice(1, 4), 10) : CEK_BIT_LENGTHS[alg];
162
+ const exactBits = /^A(128|192|256)(GCM)?KW$/.test(alg) ? aesBitsOf(alg) : CEK_BIT_LENGTHS[alg];
162
163
  if (exactBits !== void 0 && bytes.length << 3 !== exactBits) throw new JWTError(`${alg} requires a key of exactly ${exactBits >> 3} bytes (got ${bytes.length})`, "ERR_JWK_INVALID");
163
164
  }
164
165
  function checkAESCryptoKey(key, alg, usage) {
165
166
  switch (alg) {
166
167
  case "A128GCM":
167
168
  case "A192GCM":
168
- case "A256GCM": {
169
- if (!isAlgorithm$2(key.algorithm, "AES-GCM")) throw unusable$3("AES-GCM");
170
- const expected = Number.parseInt(alg.slice(1, 4), 10);
171
- if (key.algorithm.length !== expected) throw unusable$3(expected, "algorithm.length");
172
- break;
173
- }
169
+ case "A256GCM":
174
170
  case "A128KW":
175
171
  case "A192KW":
176
172
  case "A256KW": {
177
- if (!isAlgorithm$2(key.algorithm, "AES-KW")) throw unusable$3("AES-KW");
178
- const expected = Number.parseInt(alg.slice(1, 4), 10);
179
- if (key.algorithm.length !== expected) throw unusable$3(expected, "algorithm.length");
173
+ const name = alg.endsWith("KW") ? "AES-KW" : "AES-GCM";
174
+ if (!isAlgorithm(key.algorithm, name)) throw unusableKey(name);
175
+ const expected = aesBitsOf(alg);
176
+ if (key.algorithm.length !== expected) throw unusableKey(expected, "algorithm.length");
180
177
  break;
181
178
  }
182
- default: throw new TypeError("CryptoKey does not support this operation");
179
+ default: throw new JWTError("CryptoKey does not support this operation", "ERR_JWK_INVALID");
183
180
  }
184
- checkUsage$3(key, usage);
181
+ checkKeyUsage(key, usage);
185
182
  }
186
183
  async function aesKwWrap(alg, key, cek) {
187
184
  const cryptoKey = await getAESKWCryptoKey(key, alg, { usage: "wrapKey" });
@@ -202,18 +199,18 @@ async function aesKwUnwrap(alg, key, encryptedKey) {
202
199
  return new Uint8Array(await crypto.subtle.exportKey("raw", cryptoKeyCek));
203
200
  }
204
201
  async function gcmkwEncrypt(alg, key, plaintext, iv) {
205
- const wrapped = await encrypt(alg.slice(0, 7), plaintext, key, iv, new Uint8Array(0));
202
+ const wrapped = await encrypt(alg.slice(0, 7), plaintext, key, iv, /* @__PURE__ */ new Uint8Array(0));
206
203
  return {
207
204
  encryptedKey: wrapped.ciphertext,
208
- iv: base64UrlEncode(wrapped.iv),
209
- tag: base64UrlEncode(wrapped.tag)
205
+ iv: base64UrlStringify(wrapped.iv),
206
+ tag: base64UrlStringify(wrapped.tag)
210
207
  };
211
208
  }
212
209
  async function gcmkwDecrypt(alg, key, ciphertext, iv, tag) {
213
- return decrypt(alg.slice(0, 7), key, ciphertext, iv, tag, new Uint8Array(0));
210
+ return decrypt(alg.slice(0, 7), key, ciphertext, iv, tag, /* @__PURE__ */ new Uint8Array(0));
214
211
  }
215
212
  async function encrypt(enc, plaintext, cek, iv, aad) {
216
- if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) throw new TypeError("Key must be one of type: CryptoKey or Uint8Array");
213
+ if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) throw new JWTError("Key must be one of type: CryptoKey or Uint8Array", "ERR_JWK_INVALID");
217
214
  if (iv) checkIvLength(enc, iv);
218
215
  else iv = generateIV(enc);
219
216
  switch (enc) {
@@ -225,16 +222,17 @@ async function encrypt(enc, plaintext, cek, iv, aad) {
225
222
  case "A128GCM":
226
223
  case "A192GCM":
227
224
  case "A256GCM":
228
- if (cek instanceof Uint8Array) checkCEKLength(cek, Number.parseInt(enc.slice(1, 4), 10));
225
+ if (cek instanceof Uint8Array) checkCEKLength(cek, aesBitsOf(enc));
229
226
  return gcmEncrypt(enc, plaintext, cek, iv, aad);
230
- default: throw new Error("Unsupported JWE Content Encryption Algorithm");
227
+ default: throw new JWTError("Unsupported JWE Content Encryption Algorithm", "ERR_JWE_INVALID");
231
228
  }
232
229
  }
233
230
  async function decrypt(enc, cek, ciphertext, iv, tag, aad) {
234
- if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) throw new TypeError("Key must be one of type: CryptoKey or Uint8Array");
235
- if (!iv) throw new Error("JWE Initialization Vector missing");
236
- if (!tag) throw new Error("JWE Authentication Tag missing");
231
+ if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) throw new JWTError("Key must be one of type: CryptoKey or Uint8Array", "ERR_JWK_INVALID");
232
+ if (!iv) throw new JWTError("JWE Initialization Vector missing", "ERR_JWE_INVALID");
233
+ if (!tag) throw new JWTError("JWE Authentication Tag missing", "ERR_JWE_INVALID");
237
234
  checkIvLength(enc, iv);
235
+ checkTagLength(enc, tag);
238
236
  switch (enc) {
239
237
  case "A128CBC-HS256":
240
238
  case "A192CBC-HS384":
@@ -244,20 +242,11 @@ async function decrypt(enc, cek, ciphertext, iv, tag, aad) {
244
242
  case "A128GCM":
245
243
  case "A192GCM":
246
244
  case "A256GCM":
247
- if (cek instanceof Uint8Array) checkCEKLength(cek, Number.parseInt(enc.slice(1, 4), 10));
245
+ if (cek instanceof Uint8Array) checkCEKLength(cek, aesBitsOf(enc));
248
246
  return gcmDecrypt(enc, cek, ciphertext, iv, tag, aad);
249
- default: throw new Error("Unsupported JWE Content Encryption Algorithm");
247
+ default: throw new JWTError("Unsupported JWE Content Encryption Algorithm", "ERR_JWE_INVALID");
250
248
  }
251
249
  }
252
- function unusable$3(name, prop = "algorithm.name") {
253
- return /* @__PURE__ */ new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
254
- }
255
- function isAlgorithm$2(algorithm, name) {
256
- return algorithm.name === name;
257
- }
258
- function checkUsage$3(key, usage) {
259
- if (usage && !key.usages.includes(usage)) throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
260
- }
261
250
  async function getAESKWCryptoKey(key, alg, options = {}) {
262
251
  const { extractable = true, usage } = options;
263
252
  if (key instanceof Uint8Array) return crypto.subtle.importKey("raw", key, "AES-KW", extractable, [usage ?? "wrapKey"]);
@@ -265,10 +254,10 @@ async function getAESKWCryptoKey(key, alg, options = {}) {
265
254
  return key;
266
255
  }
267
256
  function checkAESKWKeySize(key, alg) {
268
- if (key.algorithm.length !== Number.parseInt(alg.slice(1, 4), 10)) throw new TypeError(`Invalid key size for alg: ${alg}`);
257
+ if (lengthOf(key.algorithm) !== aesBitsOf(alg)) throw new JWTError(`Invalid key size for alg: ${alg}`, "ERR_JWK_INVALID");
269
258
  }
270
259
  async function importCBCKeys(enc, cek, usage) {
271
- const keySize = Number.parseInt(enc.slice(1, 4), 10);
260
+ const keySize = aesBitsOf(enc);
272
261
  const [encKey, macKey] = await Promise.all([crypto.subtle.importKey("raw", cek.subarray(keySize >> 3), "AES-CBC", false, [usage]), crypto.subtle.importKey("raw", cek.subarray(0, keySize >> 3), {
273
262
  hash: `SHA-${keySize << 1}`,
274
263
  name: "HMAC"
@@ -283,7 +272,7 @@ function cbcMacData(aad, iv, ciphertext) {
283
272
  return concatUint8Arrays(aad, iv, ciphertext, uint64be(aad.length << 3));
284
273
  }
285
274
  async function cbcEncrypt(enc, plaintext, cek, iv, aad) {
286
- if (!(cek instanceof Uint8Array)) throw new TypeError("CBC key must be of type Uint8Array");
275
+ if (!(cek instanceof Uint8Array)) throw new JWTError("CBC key must be of type Uint8Array", "ERR_JWK_INVALID");
287
276
  const { encKey, macKey, keySize } = await importCBCKeys(enc, cek, "encrypt");
288
277
  const ciphertext = new Uint8Array(await crypto.subtle.encrypt({
289
278
  iv,
@@ -317,7 +306,7 @@ async function gcmEncrypt(enc, plaintext, cek, iv, aad) {
317
306
  };
318
307
  }
319
308
  async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
320
- if (!(cek instanceof Uint8Array)) throw new TypeError("CBC key must be of type Uint8Array");
309
+ if (!(cek instanceof Uint8Array)) throw new JWTError("CBC key must be of type Uint8Array", "ERR_JWK_INVALID");
321
310
  const { encKey, macKey, keySize } = await importCBCKeys(enc, cek, "decrypt");
322
311
  const macData = cbcMacData(aad, iv, ciphertext);
323
312
  const expectedTag = new Uint8Array((await crypto.subtle.sign("HMAC", macKey, macData)).slice(0, keySize >> 3));
@@ -325,7 +314,7 @@ async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
325
314
  try {
326
315
  macCheckPassed = await timingSafeEqual(tag, expectedTag);
327
316
  } catch {}
328
- if (!macCheckPassed) throw new Error("JWE Decryption Failed");
317
+ if (!macCheckPassed) throw new JWTError("JWE Decryption Failed", "ERR_JWE_DECRYPTION_FAILED");
329
318
  let plaintext;
330
319
  try {
331
320
  plaintext = new Uint8Array(await crypto.subtle.decrypt({
@@ -333,7 +322,7 @@ async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
333
322
  name: "AES-CBC"
334
323
  }, encKey, ciphertext));
335
324
  } catch {}
336
- if (!plaintext) throw new Error("JWE Decryption Failed");
325
+ if (!plaintext) throw new JWTError("JWE Decryption Failed", "ERR_JWE_DECRYPTION_FAILED");
337
326
  return plaintext;
338
327
  }
339
328
  async function gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) {
@@ -351,7 +340,7 @@ async function gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) {
351
340
  tagLength: 128
352
341
  }, encKey, concatUint8Arrays(ciphertext, tag)));
353
342
  } catch {
354
- throw new Error("JWE Decryption Failed");
343
+ throw new JWTError("JWE Decryption Failed", "ERR_JWE_DECRYPTION_FAILED");
355
344
  }
356
345
  }
357
346
  let _timingSafeKey;
@@ -363,8 +352,8 @@ function getTimingSafeKey() {
363
352
  return _timingSafeKey;
364
353
  }
365
354
  async function timingSafeEqual(a, b) {
366
- if (!(a instanceof Uint8Array)) throw new TypeError("First argument must be a buffer");
367
- if (!(b instanceof Uint8Array)) throw new TypeError("Second argument must be a buffer");
355
+ if (!(a instanceof Uint8Array)) throw new JWTError("First argument must be a buffer", "ERR_INVALID_OPTION");
356
+ if (!(b instanceof Uint8Array)) throw new JWTError("Second argument must be a buffer", "ERR_INVALID_OPTION");
368
357
  const algorithm = {
369
358
  name: "HMAC",
370
359
  hash: "SHA-256"
@@ -377,36 +366,40 @@ async function timingSafeEqual(a, b) {
377
366
  while (++i < 32) out |= aHmac[i] ^ bHmac[i];
378
367
  return out === 0;
379
368
  }
380
- function writeUInt32BE$1(buf, value, offset) {
381
- if (value < 0 || value >= 2 ** 32) throw new RangeError(`value must be >= 0 and <= ${2 ** 32 - 1}. Received ${value}`);
382
- buf.set([
383
- value >>> 24,
384
- value >>> 16,
385
- value >>> 8,
386
- value & 255
387
- ], offset);
388
- }
389
369
  function uint64be(value) {
390
- const high = Math.floor(value / 2 ** 32);
391
- const low = value % 2 ** 32;
392
- const buf = new Uint8Array(8);
393
- writeUInt32BE$1(buf, high, 0);
394
- writeUInt32BE$1(buf, low, 4);
395
- return buf;
396
- }
397
- async function jwkTokey(jwk) {
398
- if (!jwk.alg) throw new TypeError("\"alg\" argument is required when \"jwk.alg\" is not present");
370
+ return concatUint8Arrays(uint32be(Math.floor(value / 2 ** 32)), uint32be(value % 2 ** 32));
371
+ }
372
+ async function jwkTokey(jwk, options = {}) {
373
+ if (!jwk.alg) throw new JWTError("\"alg\" argument is required when \"jwk.alg\" is not present", "ERR_JWK_INVALID");
399
374
  const { algorithm, keyUsages } = subtleMapping(jwk);
400
- return crypto.subtle.importKey("jwk", jwk, algorithm, jwk.ext ?? (jwk.d ? false : true), jwk.key_ops ?? keyUsages);
375
+ const isPrivate = "d" in jwk && jwk.d !== void 0;
376
+ const extractable = jwk.ext === false ? false : options.extractable ?? !isPrivate;
377
+ try {
378
+ return await crypto.subtle.importKey("jwk", jwk, algorithm, extractable, permittedUsages(jwk, keyUsages));
379
+ } catch (error) {
380
+ if (error instanceof JWTError) throw error;
381
+ throw new JWTError(`Key is not usable for ${quoteTokenValue(jwk.alg)}.`, "ERR_JWK_INVALID", error);
382
+ }
401
383
  }
402
384
  async function keyToJWK(key) {
403
- if (key instanceof Uint8Array) return {
385
+ let jwk;
386
+ if (key instanceof Uint8Array) jwk = {
404
387
  kty: "oct",
405
- k: base64UrlEncode(key)
388
+ k: base64UrlStringify(key)
406
389
  };
407
- if (!isCryptoKey(key)) throw new TypeError("Key must be one of type: CryptoKey or Uint8Array");
408
- if (!key.extractable) throw new TypeError("non-extractable CryptoKey cannot be exported as a JWK");
409
- return await crypto.subtle.exportKey("jwk", key);
390
+ else {
391
+ if (!isCryptoKey(key)) throw new JWTError("Key must be one of type: CryptoKey or Uint8Array", "ERR_JWK_INVALID");
392
+ if (!key.extractable) throw new JWTError("non-extractable CryptoKey cannot be exported as a JWK", "ERR_JWK_INVALID");
393
+ jwk = await crypto.subtle.exportKey("jwk", key);
394
+ }
395
+ return jwk;
396
+ }
397
+ function permittedUsages(jwk, keyUsages) {
398
+ const keyOps = jwk.key_ops;
399
+ if (!keyOps || keyUsages.length === 0) return keyUsages;
400
+ const permitted = keyUsages.filter((usage) => keyOps.includes(usage));
401
+ if (permitted.length === 0) throw new JWTError(`JWK "key_ops" does not permit ${keyUsages.join(", ")}.`, "ERR_JWK_INVALID");
402
+ return permitted;
410
403
  }
411
404
  function subtleMapping(jwk) {
412
405
  let algorithm;
@@ -419,18 +412,18 @@ function subtleMapping(jwk) {
419
412
  case "PS512":
420
413
  algorithm = {
421
414
  name: "RSA-PSS",
422
- hash: `SHA-${jwk.alg.slice(-3)}`
415
+ hash: jwsHashOf(jwk.alg)
423
416
  };
424
- keyUsages = jwk.d ? ["sign"] : ["verify"];
417
+ keyUsages = hasPrivateMember(jwk) ? ["sign"] : ["verify"];
425
418
  break;
426
419
  case "RS256":
427
420
  case "RS384":
428
421
  case "RS512":
429
422
  algorithm = {
430
423
  name: "RSASSA-PKCS1-v1_5",
431
- hash: `SHA-${jwk.alg.slice(-3)}`
424
+ hash: jwsHashOf(jwk.alg)
432
425
  };
433
- keyUsages = jwk.d ? ["sign"] : ["verify"];
426
+ keyUsages = hasPrivateMember(jwk) ? ["sign"] : ["verify"];
434
427
  break;
435
428
  case "RSA-OAEP":
436
429
  case "RSA-OAEP-256":
@@ -438,35 +431,23 @@ function subtleMapping(jwk) {
438
431
  case "RSA-OAEP-512":
439
432
  algorithm = {
440
433
  name: "RSA-OAEP",
441
- hash: `SHA-${Number.parseInt(jwk.alg.slice(-3), 10) || 1}`
434
+ hash: rsaOaepHashOf(jwk.alg)
442
435
  };
443
- keyUsages = jwk.d ? ["decrypt", "unwrapKey"] : ["encrypt", "wrapKey"];
436
+ keyUsages = hasPrivateMember(jwk) ? ["decrypt", "unwrapKey"] : ["encrypt", "wrapKey"];
444
437
  break;
445
- default: throw new Error("Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value");
438
+ default: throw new JWTError(`Invalid or unsupported JWK "alg" (Algorithm) Parameter value: ${quoteTokenValue(jwk.alg)}.`, "ERR_JWK_INVALID");
446
439
  }
447
440
  break;
448
441
  case "EC":
449
442
  switch (jwk.alg) {
450
443
  case "ES256":
451
- algorithm = {
452
- name: "ECDSA",
453
- namedCurve: "P-256"
454
- };
455
- keyUsages = jwk.d ? ["sign"] : ["verify"];
456
- break;
457
444
  case "ES384":
458
- algorithm = {
459
- name: "ECDSA",
460
- namedCurve: "P-384"
461
- };
462
- keyUsages = jwk.d ? ["sign"] : ["verify"];
463
- break;
464
445
  case "ES512":
465
446
  algorithm = {
466
447
  name: "ECDSA",
467
- namedCurve: "P-521"
448
+ namedCurve: ECDSA_CURVES[jwk.alg]
468
449
  };
469
- keyUsages = jwk.d ? ["sign"] : ["verify"];
450
+ keyUsages = hasPrivateMember(jwk) ? ["sign"] : ["verify"];
470
451
  break;
471
452
  case "ECDH-ES":
472
453
  case "ECDH-ES+A128KW":
@@ -474,37 +455,49 @@ function subtleMapping(jwk) {
474
455
  case "ECDH-ES+A256KW":
475
456
  algorithm = {
476
457
  name: "ECDH",
477
- namedCurve: jwk.crv
458
+ namedCurve: requireCurve(jwk, [
459
+ "P-256",
460
+ "P-384",
461
+ "P-521"
462
+ ])
478
463
  };
479
- keyUsages = jwk.d ? ["deriveBits"] : [];
464
+ keyUsages = hasPrivateMember(jwk) ? ["deriveBits"] : [];
480
465
  break;
481
- default: throw new Error("Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value");
466
+ default: throw new JWTError(`Invalid or unsupported JWK "alg" (Algorithm) Parameter value: ${quoteTokenValue(jwk.alg)}.`, "ERR_JWK_INVALID");
482
467
  }
483
468
  break;
484
469
  case "OKP":
485
470
  switch (jwk.alg) {
486
471
  case "Ed25519":
487
472
  case "EdDSA":
488
- algorithm = { name: "Ed25519" };
489
- keyUsages = jwk.d ? ["sign"] : ["verify"];
473
+ algorithm = { name: requireCurve(jwk, ["Ed25519"]) };
474
+ keyUsages = hasPrivateMember(jwk) ? ["sign"] : ["verify"];
490
475
  break;
491
476
  case "ECDH-ES":
492
477
  case "ECDH-ES+A128KW":
493
478
  case "ECDH-ES+A192KW":
494
479
  case "ECDH-ES+A256KW":
495
- algorithm = { name: jwk.crv };
496
- keyUsages = jwk.d ? ["deriveBits"] : [];
480
+ algorithm = { name: requireCurve(jwk, ["X25519"]) };
481
+ keyUsages = hasPrivateMember(jwk) ? ["deriveBits"] : [];
497
482
  break;
498
- default: throw new Error("Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value");
483
+ default: throw new JWTError(`Invalid or unsupported JWK "alg" (Algorithm) Parameter value: ${quoteTokenValue(jwk.alg)}.`, "ERR_JWK_INVALID");
499
484
  }
500
485
  break;
501
- default: throw new Error("Invalid or unsupported JWK \"kty\" (Key Type) Parameter value");
486
+ default: throw new JWTError(`Invalid or unsupported JWK "kty" (Key Type) Parameter value: ${quoteTokenValue(jwk.kty)}.`, "ERR_JWK_INVALID");
502
487
  }
503
488
  return {
504
489
  algorithm,
505
490
  keyUsages
506
491
  };
507
492
  }
493
+ function requireCurve(jwk, allowed) {
494
+ const crv = "crv" in jwk ? jwk.crv : void 0;
495
+ if (typeof crv !== "string" || !allowed.includes(crv)) throw new JWTError(`Invalid or unsupported JWK "crv" (Curve) Parameter value: ${quoteTokenValue(crv)}. Expected one of: ${allowed.join(", ")}.`, "ERR_JWK_INVALID");
496
+ return crv;
497
+ }
498
+ function hasPrivateMember(jwk) {
499
+ return "d" in jwk && Boolean(jwk.d);
500
+ }
508
501
  async function encryptRSAES(alg, key, cek) {
509
502
  checkRSACryptoKey(key, alg, "encrypt");
510
503
  checkRSAModulusLength(alg, key);
@@ -516,60 +509,49 @@ async function decryptRSAES(alg, key, encryptedKey) {
516
509
  return new Uint8Array(await crypto.subtle.decrypt("RSA-OAEP", key, encryptedKey));
517
510
  }
518
511
  function checkRSACryptoKey(key, alg, usage) {
519
- if (!isAlgorithm$1(key.algorithm, "RSA-OAEP")) throw unusable$2("RSA-OAEP");
512
+ if (!isAlgorithm(key.algorithm, "RSA-OAEP")) throw unusableKey("RSA-OAEP");
520
513
  const expected = Number.parseInt(alg.slice(9), 10) || 1;
521
- if (getHashLength(key.algorithm.hash) !== expected) throw unusable$2(`SHA-${expected}`, "algorithm.hash");
522
- checkUsage$2(key, usage);
514
+ if (hashBitsOf(key.algorithm.hash) !== expected) throw unusableKey(`SHA-${expected}`, "algorithm.hash");
515
+ checkKeyUsage(key, usage);
523
516
  }
524
517
  function checkRSAModulusLength(alg, key) {
525
518
  if (alg.startsWith("RS") || alg.startsWith("PS") || alg.startsWith("RSA")) {
526
- const { modulusLength } = key.algorithm;
527
- if (typeof modulusLength !== "number" || modulusLength < 2048) throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
519
+ const modulusLength = modulusLengthOf(key.algorithm);
520
+ if (typeof modulusLength !== "number" || modulusLength < 2048) throw new JWTError(`${alg} requires key modulusLength to be 2048 bits or larger`, "ERR_JWK_INVALID");
528
521
  }
529
522
  }
530
- function unusable$2(name, prop = "algorithm.name") {
531
- return /* @__PURE__ */ new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
532
- }
533
- function isAlgorithm$1(algorithm, name) {
534
- return algorithm.name === name;
535
- }
536
- function getHashLength(hash) {
537
- return Number.parseInt(hash.name.slice(4), 10);
538
- }
539
- function checkUsage$2(key, usage) {
540
- if (usage && !key.usages.includes(usage)) throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
541
- }
542
- async function deriveECDHESKey(publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(0), apv = new Uint8Array(0)) {
523
+ async function deriveECDHESKey(publicKey, privateKey, algorithm, keyLength, apu = /* @__PURE__ */ new Uint8Array(0), apv = /* @__PURE__ */ new Uint8Array(0)) {
543
524
  checkECDHCryptoKey(publicKey, "ECDH");
544
525
  checkECDHCryptoKey(privateKey, "ECDH", "deriveBits");
545
526
  const value = concatUint8Arrays(lengthAndInput(textEncoder.encode(algorithm)), lengthAndInput(apu), lengthAndInput(apv), uint32be(keyLength));
546
- const length = publicKey.algorithm.name === "X25519" ? 256 : Math.ceil(Number.parseInt(publicKey.algorithm.namedCurve.slice(-3), 10) / 8) << 3;
527
+ const length = publicKey.algorithm.name === "X25519" ? 256 : Math.ceil(Number.parseInt((namedCurveOf(publicKey.algorithm) ?? "").slice(-3), 10) / 8) << 3;
547
528
  return concatKdf(new Uint8Array(await crypto.subtle.deriveBits({
548
529
  name: publicKey.algorithm.name,
549
530
  public: publicKey
550
531
  }, privateKey, length)), keyLength, value);
551
532
  }
552
- function isECDHKeyAllowed(key) {
553
- switch (key.algorithm.namedCurve) {
533
+ function ecdhDerivedBits(alg, enc) {
534
+ return alg === "ECDH-ES" ? bitLengthCEK(enc) : Number.parseInt(alg.slice(-5, -2), 10);
535
+ }
536
+ function generateEphemeralKeyPair(recipientKey) {
537
+ return crypto.subtle.generateKey(recipientKey.algorithm, true, ["deriveBits"]);
538
+ }
539
+ function assertECDHKeyAllowed(key) {
540
+ switch (namedCurveOf(key.algorithm) ?? key.algorithm.name) {
554
541
  case "P-256":
555
542
  case "P-384":
556
- case "P-521": return true;
557
- default: return key.algorithm.name === "X25519";
543
+ case "P-521":
544
+ case "X25519": return;
545
+ default: throw new JWTError("ECDH with the provided key is not allowed or not supported", "ERR_JWK_INVALID");
558
546
  }
559
547
  }
560
548
  function checkECDHCryptoKey(key, alg, usage) {
561
549
  switch (key.algorithm.name) {
562
550
  case "ECDH":
563
551
  case "X25519": break;
564
- default: throw unusable$1("ECDH or X25519");
552
+ default: throw unusableKey("ECDH or X25519");
565
553
  }
566
- checkUsage$1(key, usage);
567
- }
568
- function unusable$1(name, prop = "algorithm.name") {
569
- return /* @__PURE__ */ new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
570
- }
571
- function checkUsage$1(key, usage) {
572
- if (usage && !key.usages.includes(usage)) throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
554
+ checkKeyUsage(key, usage);
573
555
  }
574
556
  async function concatKdf(secret, bits, value) {
575
557
  const iterations = Math.ceil((bits >> 3) / 32);
@@ -589,39 +571,48 @@ function lengthAndInput(input) {
589
571
  async function digest(algorithm, data) {
590
572
  return new Uint8Array(await crypto.subtle.digest(`SHA-${algorithm.slice(-3)}`, data));
591
573
  }
592
- function writeUInt32BE(buf, value, offset) {
593
- if (value < 0 || value >= 2 ** 32) throw new RangeError(`value must be >= 0 and <= ${2 ** 32 - 1}. Received ${value}`);
594
- buf.set([
595
- value >>> 24,
596
- value >>> 16,
597
- value >>> 8,
598
- value & 255
599
- ], offset);
600
- }
601
- function uint32be(value) {
602
- const buf = new Uint8Array(4);
603
- writeUInt32BE(buf, value, 0);
604
- return buf;
605
- }
606
574
  const DEFAULT_PBES2_MIN_ITERATIONS = 1e3;
607
- const DEFAULT_PBES2_MAX_ITERATIONS = 1e6;
575
+ const DEFAULT_PBES2_ITERATIONS = 6e5;
576
+ const DEFAULT_PBES2_MAX_ITERATIONS = DEFAULT_PBES2_ITERATIONS;
577
+ function assertPBES2Params(params) {
578
+ const { p2s, p2c } = params;
579
+ if (p2s !== void 0) assertPBES2Salt(p2s, "\"p2s\"");
580
+ if (p2c === void 0) return;
581
+ assertPBES2Count(p2c, "\"p2c\"");
582
+ if (p2c > 6e5) throw new JWTError(`"p2c" must be between ${DEFAULT_PBES2_MIN_ITERATIONS} and ${DEFAULT_PBES2_MAX_ITERATIONS} iterations (got ${p2c}).`, "ERR_INVALID_OPTION");
583
+ }
584
+ function assertPBES2Salt(salt, name) {
585
+ if (salt instanceof Uint8Array && salt.length >= 8) return;
586
+ throw new JWTError(`${name} must be 8 or more octets (RFC 7518 §4.8.1.1).`, "ERR_INVALID_OPTION");
587
+ }
588
+ function assertPBES2Count(count, name) {
589
+ if (typeof count !== "number" || !Number.isInteger(count) || count < 1) throw new JWTError(`${name} must be a positive integer.`, "ERR_INVALID_OPTION");
590
+ if (count < 1e3) throw new JWTError(`${name} must be at least ${DEFAULT_PBES2_MIN_ITERATIONS} iterations (got ${count}).`, "ERR_INVALID_OPTION");
591
+ }
608
592
  async function pbes2Wrap(alg, key, cek, p2c, p2s) {
609
593
  const derived = await deriveKey(p2s, alg, p2c, key);
610
594
  return {
611
- encryptedKey: await aesKwWrap(alg.slice(-6), derived, cek),
595
+ encryptedKey: await aesKwWrap(innerKeyWrapAlg(alg), derived, cek),
612
596
  p2c,
613
- p2s: base64UrlEncode(p2s)
597
+ p2s: base64UrlStringify(p2s)
614
598
  };
615
599
  }
616
- async function pbes2Unwrap(alg, key, encryptedKey, p2c, p2s, minIterations = DEFAULT_PBES2_MIN_ITERATIONS, maxIterations = DEFAULT_PBES2_MAX_ITERATIONS) {
600
+ function assertPBES2Iterations(p2c, bounds) {
601
+ const { minIterations = DEFAULT_PBES2_MIN_ITERATIONS, maxIterations = DEFAULT_PBES2_MAX_ITERATIONS } = bounds;
617
602
  if (p2c < minIterations) throw new JWTError(`PBES2 "p2c" below the minimum of ${minIterations} iterations (got ${p2c}).`, "ERR_JWE_INVALID");
618
603
  if (p2c > maxIterations) throw new JWTError(`PBES2 "p2c" above the maximum of ${maxIterations} iterations (got ${p2c}).`, "ERR_JWE_INVALID");
604
+ }
605
+ async function pbes2Unwrap(alg, key, encryptedKey, p2c, p2s, minIterations, maxIterations) {
606
+ assertPBES2Iterations(p2c, {
607
+ minIterations,
608
+ maxIterations
609
+ });
619
610
  const derived = await deriveKey(p2s, alg, p2c, key);
620
- return aesKwUnwrap(alg.slice(-6), derived, encryptedKey);
611
+ return aesKwUnwrap(innerKeyWrapAlg(alg), derived, encryptedKey);
621
612
  }
622
613
  async function deriveKey(p2s, alg, p2c, key) {
623
- if (!(p2s instanceof Uint8Array) || p2s.length < 8) throw new Error("PBES2 Salt Input must be 8 or more octets");
624
- if (p2c === void 0 || p2c < 1) throw new Error("PBES2 Iteration Count Parameter must be a positive integer");
614
+ assertPBES2Salt(p2s, "\"p2s\"");
615
+ if (p2c === void 0 || p2c < 1) throw new JWTError("PBES2 Iteration Count Parameter must be a positive integer", "ERR_INVALID_OPTION");
625
616
  const salt = concatUint8Arrays(textEncoder.encode(alg), new Uint8Array([0]), p2s);
626
617
  const keylen = Number.parseInt(alg.slice(13, 16), 10);
627
618
  const subtleAlg = {
@@ -634,17 +625,8 @@ async function deriveKey(p2s, alg, p2c, key) {
634
625
  return new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen));
635
626
  }
636
627
  function checkPBES2CryptoKey(key, alg, usage) {
637
- if (!isAlgorithm(key.algorithm, "PBKDF2")) throw unusable("PBKDF2");
638
- checkUsage(key, usage);
639
- }
640
- function unusable(name, prop = "algorithm.name") {
641
- return /* @__PURE__ */ new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
642
- }
643
- function isAlgorithm(algorithm, name) {
644
- return algorithm.name === name;
645
- }
646
- function checkUsage(key, usage) {
647
- if (usage && !key.usages.includes(usage)) throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
628
+ if (!isAlgorithm(key.algorithm, "PBKDF2")) throw unusableKey("PBKDF2");
629
+ checkKeyUsage(key, usage);
648
630
  }
649
631
  async function getPBKDF2CryptoKey(key, alg, options = {}) {
650
632
  const { extractable = false, usage = "deriveBits" } = options;
@@ -652,20 +634,6 @@ async function getPBKDF2CryptoKey(key, alg, options = {}) {
652
634
  checkPBES2CryptoKey(key, alg, usage);
653
635
  return key;
654
636
  }
655
- const PUBLIC_EPK_FIELDS = new Set([
656
- "kty",
657
- "crv",
658
- "x",
659
- "y",
660
- "kid",
661
- "use",
662
- "key_ops",
663
- "alg",
664
- "x5c",
665
- "x5t",
666
- "x5t#S256",
667
- "x5u"
668
- ]);
669
637
  async function encryptKey(alg, enc, key, providedCek, providedParameters = {}) {
670
638
  let encryptedKey;
671
639
  let parameters = {};
@@ -677,34 +645,15 @@ async function encryptKey(alg, enc, key, providedCek, providedParameters = {}) {
677
645
  case "ECDH-ES":
678
646
  case "ECDH-ES+A128KW":
679
647
  case "ECDH-ES+A192KW":
680
- case "ECDH-ES+A256KW": {
648
+ case "ECDH-ES+A256KW":
681
649
  assertCryptoKey(key);
682
- if (!isECDHKeyAllowed(key)) throw new Error("ECDH with the provided key is not allowed or not supported by your javascript runtime");
683
- const { apu, apv, epk: providedEpk, epkPrivateKey } = providedParameters;
684
- if (providedEpk && !epkPrivateKey) throw new TypeError("ECDH-ES custom ephemeral key material must include the matching private key.");
685
- let ephemeralPrivateKey;
686
- let epkHeader;
687
- if (epkPrivateKey) {
688
- ephemeralPrivateKey = await ensurePrivateKey(alg, epkPrivateKey);
689
- epkHeader = await exportPublicJwkFrom(alg, providedEpk ?? epkPrivateKey);
690
- } else {
691
- if (providedEpk) throw new TypeError("ECDH-ES custom ephemeral public key requires a matching private key.");
692
- const generated = await crypto.subtle.generateKey(key.algorithm, true, ["deriveBits"]);
693
- ephemeralPrivateKey = generated.privateKey;
694
- epkHeader = await exportPublicJwkFrom(alg, generated.publicKey);
695
- }
696
- const sharedSecret = await deriveECDHESKey(key, ephemeralPrivateKey, alg === "ECDH-ES" ? enc : alg, alg === "ECDH-ES" ? bitLengthCEK(enc) : Number.parseInt(alg.slice(-5, -2), 10), apu, apv);
697
- parameters = { epk: epkHeader };
698
- if (apu) parameters.apu = base64UrlEncode(apu);
699
- if (apv) parameters.apv = base64UrlEncode(apv);
700
- if (alg === "ECDH-ES") {
701
- cek = sharedSecret;
702
- break;
703
- }
704
- cek = providedCek || generateCEK(enc);
705
- encryptedKey = await aesKwWrap(alg.slice(-6), sharedSecret, cek);
650
+ ({cek, encryptedKey, parameters} = await ecdhesWrap(alg, {
651
+ enc,
652
+ recipientKey: key,
653
+ cek: providedCek,
654
+ parameters: providedParameters
655
+ }));
706
656
  break;
707
- }
708
657
  case "RSA-OAEP":
709
658
  case "RSA-OAEP-256":
710
659
  case "RSA-OAEP-384":
@@ -718,6 +667,7 @@ async function encryptKey(alg, enc, key, providedCek, providedParameters = {}) {
718
667
  case "PBES2-HS512+A256KW": {
719
668
  cek = providedCek || generateCEK(enc);
720
669
  const { p2c, p2s } = providedParameters;
670
+ if (p2c === void 0 || p2s === void 0) throw new JWTError(`${alg} requires "p2c" and "p2s"`, "ERR_JWE_INVALID");
721
671
  ({encryptedKey, ...parameters} = await pbes2Wrap(alg, key, cek, p2c, p2s));
722
672
  break;
723
673
  }
@@ -735,7 +685,7 @@ async function encryptKey(alg, enc, key, providedCek, providedParameters = {}) {
735
685
  ({encryptedKey, ...parameters} = await gcmkwEncrypt(alg, key, cek, iv));
736
686
  break;
737
687
  }
738
- default: throw new Error("Invalid or unsupported \"alg\" (JWE Algorithm) header value");
688
+ default: throw new JWTError(`Invalid or unsupported "alg" (JWE Algorithm) header value: ${quoteTokenValue(alg)}`, "ERR_JWE_ALG_NOT_ALLOWED");
739
689
  }
740
690
  return {
741
691
  cek,
@@ -743,52 +693,127 @@ async function encryptKey(alg, enc, key, providedCek, providedParameters = {}) {
743
693
  parameters
744
694
  };
745
695
  }
746
- async function normalizeKey(key, alg) {
747
- if (key instanceof Uint8Array) return key;
748
- if (isCryptoKey(key)) return key;
749
- if (isJWK(key)) {
750
- if ("k" in key && key.k) return base64UrlDecode(key.k, { returnAs: "uint8array" });
751
- return jwkTokey(key.alg ? key : {
752
- ...key,
753
- alg
754
- });
696
+ async function ecdhesWrap(alg, options) {
697
+ const { enc, recipientKey } = options;
698
+ const { apu, apv, epk: providedEpk, epkPrivateKey } = options.parameters;
699
+ assertECDHKeyAllowed(recipientKey);
700
+ if (providedEpk && !epkPrivateKey) throw new JWTError("ECDH-ES custom ephemeral key material must include the matching private key.", "ERR_JWK_INVALID");
701
+ let ephemeralPrivateKey;
702
+ let epk;
703
+ if (epkPrivateKey) {
704
+ ephemeralPrivateKey = await ensurePrivateKey(alg, epkPrivateKey);
705
+ assertEphemeralCurve(ephemeralPrivateKey, recipientKey);
706
+ epk = await exportPublicJwkFrom(providedEpk ?? epkPrivateKey);
707
+ } else {
708
+ const generated = await generateEphemeralKeyPair(recipientKey);
709
+ ephemeralPrivateKey = generated.privateKey;
710
+ epk = await exportPublicJwkFrom(generated.publicKey);
711
+ }
712
+ const kdfAlg = alg === "ECDH-ES" ? contentAlgorithm(enc) : alg;
713
+ const sharedSecret = await deriveECDHESKey(recipientKey, ephemeralPrivateKey, kdfAlg, ecdhDerivedBits(alg, kdfAlg), apu, apv);
714
+ const parameters = { epk };
715
+ if (apu) parameters.apu = base64UrlStringify(apu);
716
+ if (apv) parameters.apv = base64UrlStringify(apv);
717
+ if (alg === "ECDH-ES") return {
718
+ cek: sharedSecret,
719
+ parameters
720
+ };
721
+ const cek = options.cek ?? generateCEK(contentAlgorithm(enc));
722
+ return {
723
+ cek,
724
+ encryptedKey: await aesKwWrap(innerKeyWrapAlg(alg), sharedSecret, cek),
725
+ parameters
726
+ };
727
+ }
728
+ async function normalizeEpk(epk, options) {
729
+ const recipientCurve = cryptoKeyCurve(options.recipientKey);
730
+ if (isCryptoKey(epk)) {
731
+ if (epk.type !== "public") throw invalidEpk("must not contain private key material.");
732
+ assertEpkCurve(cryptoKeyCurve(epk), recipientCurve);
733
+ return epk;
755
734
  }
756
- throw new Error("unreachable");
735
+ if (!isJWK(epk) || epk.kty !== "EC" && epk.kty !== "OKP") throw invalidEpk("must be an EC or OKP public key.");
736
+ if ("d" in epk && epk.d !== void 0) throw invalidEpk("must not contain private key material.");
737
+ const crv = epk.crv;
738
+ const allowed = epk.kty === "EC" ? EC_ECDH_CURVES : OKP_ECDH_CURVES;
739
+ if (typeof crv !== "string" || !allowed.has(crv)) throw invalidEpk(`curve ${quoteTokenValue(crv)} is not supported for ${options.alg}.`);
740
+ assertEpkCurve(crv, recipientCurve);
741
+ const x = epk.x;
742
+ const y = epk.kty === "EC" ? epk.y : void 0;
743
+ if (typeof x !== "string" || epk.kty === "EC" && typeof y !== "string") throw invalidEpk("is missing its public coordinates.");
744
+ return jwkTokey(epk.kty === "EC" && typeof y === "string" ? {
745
+ kty: "EC",
746
+ crv,
747
+ x,
748
+ y,
749
+ alg: options.alg
750
+ } : {
751
+ kty: "OKP",
752
+ crv,
753
+ x,
754
+ alg: options.alg
755
+ });
756
+ }
757
+ const EC_ECDH_CURVES = /* @__PURE__ */ new Set([
758
+ "P-256",
759
+ "P-384",
760
+ "P-521"
761
+ ]);
762
+ const OKP_ECDH_CURVES = /* @__PURE__ */ new Set(["X25519"]);
763
+ function contentAlgorithm(enc) {
764
+ if (enc) return enc;
765
+ throw new JWTError("ECDH-ES requires \"enc\", the content encryption algorithm the key is agreed for.", "ERR_JWE_INVALID");
766
+ }
767
+ function assertEphemeralCurve(ephemeralKey, recipientKey) {
768
+ assertECDHKeyAllowed(ephemeralKey);
769
+ const ephemeralCurve = cryptoKeyCurve(ephemeralKey);
770
+ const recipientCurve = cryptoKeyCurve(recipientKey);
771
+ if (ephemeralCurve === recipientCurve) return;
772
+ throw new JWTError(`ECDH-ES ephemeral key curve ${quoteTokenValue(ephemeralCurve)} does not match the recipient key curve ${quoteTokenValue(recipientCurve)}.`, "ERR_JWK_INVALID");
773
+ }
774
+ function invalidEpk(detail) {
775
+ return new JWTError(`Invalid JWE: "epk" ${detail}`, "ERR_JWE_INVALID");
776
+ }
777
+ function assertEpkCurve(epkCurve, recipientCurve) {
778
+ if (!recipientCurve || !epkCurve || epkCurve === recipientCurve) return;
779
+ throw invalidEpk(`curve "${epkCurve}" does not match the recipient key curve "${recipientCurve}".`);
757
780
  }
758
781
  function toPublicEpkJwk(jwk) {
759
- const filtered = {};
760
- for (const [key, value] of Object.entries(jwk)) if (value !== void 0 && PUBLIC_EPK_FIELDS.has(key)) filtered[key] = value;
761
- const { kty, crv, x, y } = filtered;
762
- if (typeof kty !== "string") throw new TypeError("ECDH-ES ephemeral key JWK must include the \"kty\" parameter.");
763
- if (typeof crv !== "string") throw new TypeError("ECDH-ES ephemeral key JWK must include the \"crv\" parameter.");
764
- if (typeof x !== "string") throw new TypeError("ECDH-ES ephemeral key JWK must include the \"x\" coordinate.");
765
- if (kty === "EC" && typeof y !== "string") throw new TypeError("ECDH-ES EC ephemeral key JWK must include both \"x\" and \"y\" coordinates.");
766
- const publicJwk = {
767
- ...filtered,
782
+ const { kty } = jwk;
783
+ const crv = "crv" in jwk ? jwk.crv : void 0;
784
+ const x = "x" in jwk ? jwk.x : void 0;
785
+ if (kty !== "EC" && kty !== "OKP") throw new JWTError("ECDH-ES ephemeral key JWK \"kty\" must be \"EC\" or \"OKP\".", "ERR_JWK_INVALID");
786
+ if (typeof crv !== "string") throw new JWTError("ECDH-ES ephemeral key JWK must include the \"crv\" parameter.", "ERR_JWK_INVALID");
787
+ if (typeof x !== "string") throw new JWTError("ECDH-ES ephemeral key JWK must include the \"x\" coordinate.", "ERR_JWK_INVALID");
788
+ if (kty === "OKP") return {
768
789
  kty,
769
790
  crv,
770
791
  x
771
792
  };
772
- if (typeof y === "string") publicJwk.y = y;
773
- else delete publicJwk.y;
774
- return sanitizeObjectCopy(publicJwk);
793
+ const y = "y" in jwk ? jwk.y : void 0;
794
+ if (typeof y !== "string") throw new JWTError("ECDH-ES EC ephemeral key JWK must include both \"x\" and \"y\" coordinates.", "ERR_JWK_INVALID");
795
+ return {
796
+ kty,
797
+ crv,
798
+ x,
799
+ y
800
+ };
775
801
  }
776
802
  async function ensurePrivateKey(alg, value) {
777
- const normalized = await normalizeKey(value, alg);
778
- if (!(normalized instanceof CryptoKey)) throw new TypeError("ECDH-ES ephemeral private key must be a CryptoKey or convertible JWK.");
779
- if (normalized.type !== "private") throw new TypeError("ECDH-ES ephemeral private key must have type \"private\".");
803
+ const normalized = isCryptoKey(value) ? value : await jwkTokey(value.alg ? value : {
804
+ ...value,
805
+ alg
806
+ });
807
+ if (normalized.type !== "private") throw new JWTError("ECDH-ES ephemeral private key must have type \"private\".", "ERR_JWK_INVALID");
780
808
  return normalized;
781
809
  }
782
- async function exportPublicJwkFrom(alg, value) {
783
- if (isCryptoKey(value)) try {
810
+ async function exportPublicJwkFrom(value) {
811
+ if (!isCryptoKey(value)) return toPublicEpkJwk(value);
812
+ try {
784
813
  return toPublicEpkJwk(await keyToJWK(value));
785
814
  } catch (error_) {
786
- throw new TypeError("ECDH-ES ephemeral CryptoKey must be extractable to export as JWK.", { cause: error_ instanceof Error ? error_ : void 0 });
815
+ throw new JWTError("ECDH-ES ephemeral CryptoKey must be extractable to export as JWK.", "ERR_JWK_INVALID", error_);
787
816
  }
788
- if (isJWK(value) && isAsymmetricJWK(value) && value.kty === "EC") return toPublicEpkJwk(value);
789
- const normalized = await normalizeKey(value, alg);
790
- if (!(normalized instanceof CryptoKey)) throw new TypeError("ECDH-ES ephemeral public key must be a CryptoKey or convertible JWK.");
791
- return exportPublicJwkFrom(alg, normalized);
792
817
  }
793
818
  const toSPKI = (key) => {
794
819
  return genericExport("public", "spki", key);
@@ -797,42 +822,53 @@ const toPKCS8 = (key) => {
797
822
  return genericExport("private", "pkcs8", key);
798
823
  };
799
824
  const fromPKCS8 = (pem, alg, options) => {
800
- return genericImport(/(?:-----(?:BEGIN|END) PRIVATE KEY-----|\s)/g, "PRIVATE KEY", "pkcs8", pem, alg, options);
825
+ return genericImport("PRIVATE KEY", "pkcs8", pem, alg, options);
801
826
  };
802
827
  const fromSPKI = (pem, alg, options) => {
803
- return genericImport(/(?:-----(?:BEGIN|END) PUBLIC KEY-----|\s)/g, "PUBLIC KEY", "spki", pem, alg, options);
828
+ return genericImport("PUBLIC KEY", "spki", pem, alg, options);
804
829
  };
805
830
  const fromX509 = (pem, alg, options) => {
806
831
  let spki;
807
832
  try {
808
833
  spki = getSPKI(pem);
809
834
  } catch (error_) {
810
- throw new TypeError("Failed to parse the X.509 certificate", { cause: error_ });
835
+ throw new JWTError("Failed to parse the X.509 certificate.", "ERR_JWK_INVALID", error_);
811
836
  }
812
837
  return fromSPKI(spki, alg, options);
813
838
  };
814
839
  const formatPEM = (b64, descriptor) => {
815
840
  return `-----BEGIN ${descriptor}-----\n${(b64.match(/.{1,64}/g) || []).join("\n")}\n-----END ${descriptor}-----`;
816
841
  };
817
- const assertPEMLabel = (pem, descriptor) => {
842
+ const pemBody = (pem, descriptor) => {
818
843
  const begin = `-----BEGIN ${descriptor}-----`;
819
844
  const end = `-----END ${descriptor}-----`;
820
- if (!pem.includes(begin) || !pem.includes(end)) {
845
+ const start = pem.indexOf(begin);
846
+ if (start === -1) {
821
847
  const found = pem.match(/-----BEGIN [^-]+-----/)?.[0];
822
848
  throw new JWTError(found ? `PEM label mismatch: expected "${begin}", got "${found}".` : `PEM label missing: expected "${begin}".`, "ERR_JWK_INVALID");
823
849
  }
850
+ const bodyStart = start + begin.length;
851
+ const bodyEnd = pem.indexOf(end, bodyStart);
852
+ if (bodyEnd === -1) throw new JWTError(`PEM label missing: expected "${end}".`, "ERR_JWK_INVALID");
853
+ if (pem.includes("-----BEGIN", bodyStart) || pem.slice(bodyEnd + end.length).trim() !== "") throw new JWTError(`PEM must contain exactly one ${descriptor} block, with nothing after it.`, "ERR_JWK_INVALID");
854
+ return pem.slice(bodyStart, bodyEnd).replaceAll(/\s/g, "");
824
855
  };
825
856
  const genericExport = async (keyType, keyFormat, key) => {
826
- if (!isCryptoKey(key)) throw new TypeError(`Key must be ${key} of type CryptoKey`);
827
- if (!key.extractable) throw new TypeError("CryptoKey is not extractable");
828
- if (key.type !== keyType) throw new TypeError(`key is not a ${keyType} key`);
829
- return formatPEM(base64Encode(new Uint8Array(await crypto.subtle.exportKey(keyFormat, key))), `${keyType.toUpperCase()} KEY`);
857
+ if (!isCryptoKey(key)) throw new JWTError(`Key must be of type CryptoKey, got ${typeof key}`, "ERR_INVALID_OPTION");
858
+ if (!key.extractable) throw new JWTError("CryptoKey is not extractable", "ERR_JWK_INVALID");
859
+ if (key.type !== keyType) throw new JWTError(`key is not a ${keyType} key`, "ERR_JWK_INVALID");
860
+ return formatPEM(base64Stringify(new Uint8Array(await crypto.subtle.exportKey(keyFormat, key))), `${keyType.toUpperCase()} KEY`);
830
861
  };
831
- const genericImport = async (replace, descriptor, keyFormat, pem, alg, options) => {
862
+ const genericImport = async (descriptor, keyFormat, pem, alg, options) => {
832
863
  let algorithm;
833
864
  let keyUsages;
834
- assertPEMLabel(pem, descriptor);
835
- const keyData = base64Decode(pem.replace(replace, ""), { returnAs: "uint8array" });
865
+ const body = pemBody(pem, descriptor);
866
+ let keyData;
867
+ try {
868
+ keyData = base64Parse(body, { returnAs: "uint8array" });
869
+ } catch (error) {
870
+ throw new JWTError("Invalid PEM: body could not be decoded.", "ERR_JWK_INVALID", error);
871
+ }
836
872
  const isPublic = keyFormat === "spki";
837
873
  switch (alg) {
838
874
  case "PS256":
@@ -840,7 +876,7 @@ const genericImport = async (replace, descriptor, keyFormat, pem, alg, options)
840
876
  case "PS512":
841
877
  algorithm = {
842
878
  name: "RSA-PSS",
843
- hash: `SHA-${alg.slice(-3)}`
879
+ hash: jwsHashOf(alg)
844
880
  };
845
881
  keyUsages = isPublic ? ["verify"] : ["sign"];
846
882
  break;
@@ -849,7 +885,7 @@ const genericImport = async (replace, descriptor, keyFormat, pem, alg, options)
849
885
  case "RS512":
850
886
  algorithm = {
851
887
  name: "RSASSA-PKCS1-v1_5",
852
- hash: `SHA-${alg.slice(-3)}`
888
+ hash: jwsHashOf(alg)
853
889
  };
854
890
  keyUsages = isPublic ? ["verify"] : ["sign"];
855
891
  break;
@@ -859,28 +895,16 @@ const genericImport = async (replace, descriptor, keyFormat, pem, alg, options)
859
895
  case "RSA-OAEP-512":
860
896
  algorithm = {
861
897
  name: "RSA-OAEP",
862
- hash: `SHA-${Number.parseInt(alg.slice(-3), 10) || 1}`
898
+ hash: rsaOaepHashOf(alg)
863
899
  };
864
900
  keyUsages = isPublic ? ["encrypt", "wrapKey"] : ["decrypt", "unwrapKey"];
865
901
  break;
866
902
  case "ES256":
867
- algorithm = {
868
- name: "ECDSA",
869
- namedCurve: "P-256"
870
- };
871
- keyUsages = isPublic ? ["verify"] : ["sign"];
872
- break;
873
903
  case "ES384":
874
- algorithm = {
875
- name: "ECDSA",
876
- namedCurve: "P-384"
877
- };
878
- keyUsages = isPublic ? ["verify"] : ["sign"];
879
- break;
880
904
  case "ES512":
881
905
  algorithm = {
882
906
  name: "ECDSA",
883
- namedCurve: "P-521"
907
+ namedCurve: ECDSA_CURVES[alg]
884
908
  };
885
909
  keyUsages = isPublic ? ["verify"] : ["sign"];
886
910
  break;
@@ -889,32 +913,52 @@ const genericImport = async (replace, descriptor, keyFormat, pem, alg, options)
889
913
  case "ECDH-ES+A192KW":
890
914
  case "ECDH-ES+A256KW": {
891
915
  const namedCurve = getNamedCurve(keyData);
892
- algorithm = namedCurve?.startsWith("P-") ? {
916
+ if (namedCurve) algorithm = {
893
917
  name: "ECDH",
894
918
  namedCurve
895
- } : { name: "X25519" };
919
+ };
920
+ else algorithm = { name: requireOKPCurve(keyData, "X25519") };
896
921
  keyUsages = isPublic ? [] : ["deriveBits"];
897
922
  break;
898
923
  }
899
924
  case "Ed25519":
900
925
  case "EdDSA":
901
- algorithm = { name: "Ed25519" };
926
+ algorithm = { name: requireOKPCurve(keyData, "Ed25519") };
902
927
  keyUsages = isPublic ? ["verify"] : ["sign"];
903
928
  break;
904
- default: throw new Error("Invalid or unsupported \"alg\" (Algorithm) value");
929
+ default: throw new JWTError("Invalid or unsupported \"alg\" (Algorithm) value", "ERR_JWK_UNSUPPORTED");
930
+ }
931
+ try {
932
+ return await crypto.subtle.importKey(keyFormat, keyData, algorithm, options?.extractable ?? isPublic, keyUsages);
933
+ } catch (error) {
934
+ throw new JWTError(`Invalid PEM: the body could not be imported as "${alg}".`, "ERR_JWK_INVALID", error);
905
935
  }
906
- return crypto.subtle.importKey(keyFormat, keyData, algorithm, options?.extractable ?? (isPublic ? true : false), keyUsages);
907
936
  };
908
- const findOid = (keyData, oid, from = 0) => {
909
- if (from === 0) {
910
- oid.unshift(oid.length);
911
- oid.unshift(6);
912
- }
913
- const i = keyData.indexOf(oid[0], from);
914
- if (i === -1) return false;
915
- const sub = keyData.subarray(i, i + oid.length);
916
- if (sub.length !== oid.length) return false;
917
- return sub.every((value, index) => value === oid[index]) || findOid(keyData, oid, i + 1);
937
+ const findOid = (keyData, oid) => {
938
+ const needle = [
939
+ 6,
940
+ oid.length,
941
+ ...oid
942
+ ];
943
+ const last = keyData.length - needle.length;
944
+ for (let i = keyData.indexOf(needle[0]); i !== -1 && i <= last; i = keyData.indexOf(needle[0], i + 1)) if (needle.every((byte, index) => keyData[i + index] === byte)) return true;
945
+ return false;
946
+ };
947
+ const OKP_CURVE_OIDS = {
948
+ X25519: [
949
+ 43,
950
+ 101,
951
+ 110
952
+ ],
953
+ Ed25519: [
954
+ 43,
955
+ 101,
956
+ 112
957
+ ]
958
+ };
959
+ const requireOKPCurve = (keyData, crv) => {
960
+ if (findOid(keyData, OKP_CURVE_OIDS[crv])) return crv;
961
+ throw new JWTError(`Invalid PEM: unsupported curve, expected the ${crv} OID.`, "ERR_JWK_INVALID");
918
962
  };
919
963
  const getNamedCurve = (keyData) => {
920
964
  switch (true) {
@@ -950,6 +994,7 @@ const getElement = (seq) => {
950
994
  let next = 0;
951
995
  while (next < seq.length) {
952
996
  const nextPart = parseElement(seq.subarray(next));
997
+ if (nextPart.byteLength <= 0) throw new JWTError("Invalid DER: zero-length element", "ERR_JWK_INVALID");
953
998
  result.push(nextPart);
954
999
  next += nextPart.byteLength;
955
1000
  }
@@ -957,27 +1002,33 @@ const getElement = (seq) => {
957
1002
  };
958
1003
  const parseElement = (bytes) => {
959
1004
  let position = 0;
960
- let tag = bytes[0] & 31;
1005
+ const at = (index) => {
1006
+ const byte = bytes[index];
1007
+ if (byte === void 0) throw new JWTError("Invalid DER: element is truncated", "ERR_JWK_INVALID");
1008
+ return byte;
1009
+ };
1010
+ let tag = at(0) & 31;
961
1011
  position++;
962
1012
  if (tag === 31) {
963
1013
  tag = 0;
964
- while (bytes[position] >= 128) {
965
- tag = tag * 128 + bytes[position] - 128;
1014
+ while (at(position) >= 128) {
1015
+ tag = tag * 128 + at(position) - 128;
966
1016
  position++;
967
1017
  }
968
- tag = tag * 128 + bytes[position] - 128;
1018
+ tag = tag * 128 + at(position) - 128;
969
1019
  position++;
970
1020
  }
971
1021
  let length = 0;
972
- if (bytes[position] < 128) {
973
- length = bytes[position];
1022
+ if (at(position) < 128) {
1023
+ length = at(position);
974
1024
  position++;
975
- } else if (length === 128) {
1025
+ } else if (at(position) === 128) {
976
1026
  length = 0;
977
- while (bytes[position + length] !== 0 || bytes[position + length + 1] !== 0) {
978
- if (length > bytes.byteLength) throw new TypeError("invalid indefinite form length");
1027
+ while (position + length + 1 < bytes.byteLength) {
1028
+ if (at(position + length) === 0 && at(position + length + 1) === 0) break;
979
1029
  length++;
980
1030
  }
1031
+ if (position + length + 1 >= bytes.byteLength) throw new JWTError("Invalid DER: invalid indefinite form length", "ERR_JWK_INVALID");
981
1032
  const byteLength = position + length + 2;
982
1033
  return {
983
1034
  byteLength,
@@ -985,15 +1036,16 @@ const parseElement = (bytes) => {
985
1036
  raw: bytes.subarray(0, byteLength)
986
1037
  };
987
1038
  } else {
988
- const numberOfDigits = bytes[position] & 127;
1039
+ const numberOfDigits = at(position) & 127;
989
1040
  position++;
990
1041
  length = 0;
991
1042
  for (let i = 0; i < numberOfDigits; i++) {
992
- length = length * 256 + bytes[position];
1043
+ length = length * 256 + at(position);
993
1044
  position++;
994
1045
  }
995
1046
  }
996
1047
  const byteLength = position + length;
1048
+ if (byteLength > bytes.byteLength) throw new JWTError("Invalid DER: element length exceeds the available bytes", "ERR_JWK_INVALID");
997
1049
  return {
998
1050
  byteLength,
999
1051
  contents: bytes.subarray(position, byteLength),
@@ -1001,8 +1053,14 @@ const parseElement = (bytes) => {
1001
1053
  };
1002
1054
  };
1003
1055
  const spkiFromX509 = (buf) => {
1004
- const tbsCertificate = getElement(getElement(parseElement(buf).contents)[0].contents);
1005
- return base64Encode(tbsCertificate[tbsCertificate[0].raw[0] === 160 ? 6 : 5].raw);
1056
+ const tbs = getElement(parseElement(buf).contents)[0];
1057
+ if (!tbs) throw new JWTError("Invalid X.509 certificate: missing tbsCertificate", "ERR_JWK_INVALID");
1058
+ const tbsCertificate = getElement(tbs.contents);
1059
+ const first = tbsCertificate[0];
1060
+ if (!first) throw new JWTError("Invalid X.509 certificate: empty tbsCertificate", "ERR_JWK_INVALID");
1061
+ const spki = tbsCertificate[first.raw[0] === 160 ? 6 : 5];
1062
+ if (!spki) throw new JWTError("Invalid X.509 certificate: missing subjectPublicKeyInfo", "ERR_JWK_INVALID");
1063
+ return base64Stringify(spki.raw);
1006
1064
  };
1007
1065
  let createPublicKey;
1008
1066
  const getSPKI = (x509) => {
@@ -1011,82 +1069,680 @@ const getSPKI = (x509) => {
1011
1069
  } catch {
1012
1070
  createPublicKey = 0;
1013
1071
  }
1072
+ const body = pemBody(x509, "CERTIFICATE");
1014
1073
  if (createPublicKey) try {
1015
1074
  return new createPublicKey(x509).export({
1016
1075
  format: "pem",
1017
1076
  type: "spki"
1018
1077
  });
1019
1078
  } catch {}
1020
- return formatPEM(spkiFromX509(base64Decode(x509.replace(/(?:-----(?:BEGIN|END) CERTIFICATE-----|\s)/g, ""), { returnAs: "uint8array" })), "PUBLIC KEY");
1079
+ let raw;
1080
+ try {
1081
+ raw = base64Parse(body, { returnAs: "uint8array" });
1082
+ } catch (error) {
1083
+ throw new JWTError("Invalid X.509 certificate: body could not be decoded.", "ERR_JWK_INVALID", error);
1084
+ }
1085
+ return formatPEM(spkiFromX509(raw), "PUBLIC KEY");
1086
+ };
1087
+ const THUMBPRINT_MEMBERS = /* @__PURE__ */ Object.freeze({
1088
+ EC: [
1089
+ "crv",
1090
+ "kty",
1091
+ "x",
1092
+ "y"
1093
+ ],
1094
+ RSA: [
1095
+ "e",
1096
+ "kty",
1097
+ "n"
1098
+ ],
1099
+ OKP: [
1100
+ "crv",
1101
+ "kty",
1102
+ "x"
1103
+ ],
1104
+ oct: ["k", "kty"]
1105
+ });
1106
+ const THUMBPRINT_HASHES = /* @__PURE__ */ new Set([
1107
+ "SHA-256",
1108
+ "SHA-384",
1109
+ "SHA-512"
1110
+ ]);
1111
+ async function thumbprint(jwk, options = {}) {
1112
+ assertPlainObject(jwk, "jwk");
1113
+ assertPlainObject(options, "options");
1114
+ const hash = options.hash ?? "SHA-256";
1115
+ if (!THUMBPRINT_HASHES.has(hash)) throw new JWTError("\"hash\" must be \"SHA-256\", \"SHA-384\" or \"SHA-512\".", "ERR_INVALID_OPTION");
1116
+ const kty = jwk.kty;
1117
+ const members = typeof kty === "string" && Object.hasOwn(THUMBPRINT_MEMBERS, kty) ? THUMBPRINT_MEMBERS[kty] : void 0;
1118
+ if (!members) throw new JWTError(`JWK thumbprint is not defined for kty "${String(kty)}".`, "ERR_JWK_INVALID");
1119
+ const canonical = members.map((name) => {
1120
+ const value = Reflect.get(jwk, name);
1121
+ if (typeof value !== "string" || value.length === 0) throw new JWTError(`JWK thumbprint requires the member "${name}" on an ${jwk.kty} key.`, "ERR_JWK_INVALID");
1122
+ return `${JSON.stringify(name)}:${JSON.stringify(value)}`;
1123
+ });
1124
+ const digest = await crypto.subtle.digest(hash, textEncoder.encode(`{${canonical.join(",")}}`));
1125
+ return base64UrlStringify(new Uint8Array(digest));
1126
+ }
1127
+ const MAX_PARTY_INFO_BYTES = 1024;
1128
+ const DEFAULT_JOSE_LIMITS = /* @__PURE__ */ Object.freeze({
1129
+ signatures: 16,
1130
+ recipients: 16,
1131
+ keyCandidates: 8,
1132
+ pbes2Iterations: 4 * DEFAULT_PBES2_ITERATIONS
1133
+ });
1134
+ function resolveLimit(limits, name) {
1135
+ const value = limits?.[name];
1136
+ if (value === void 0) return DEFAULT_JOSE_LIMITS[name];
1137
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1) throw new JWTError(`"limits.${name}" must be a positive integer.`, "ERR_INVALID_OPTION");
1138
+ return value;
1139
+ }
1140
+ function assertEntryLimit(count, limit, options) {
1141
+ if (count <= limit) return;
1142
+ throw new JWTError(`Invalid ${options.family}: ${count} ${options.what} exceed the limit of ${limit}.`, `ERR_${options.family}_INVALID`);
1143
+ }
1144
+ function assertCandidateLimit(count, limit) {
1145
+ if (count <= limit) return;
1146
+ throw new JWTError(`${count} candidate keys exceed the limit of ${limit}; narrow the JWK Set with a "kid".`, "ERR_JWK_KEY_NOT_FOUND");
1147
+ }
1148
+ function assertJWKSetCandidates(candidates, options) {
1149
+ if (candidates.length === 0) {
1150
+ const { kid } = options;
1151
+ throw new JWTError(`No key found in JWK Set${kid ? ` with kid ${quoteTokenValue(kid)}` : ""}.`, "ERR_JWK_KEY_NOT_FOUND");
1152
+ }
1153
+ assertCandidateLimit(candidates.length, options.limit);
1154
+ }
1155
+ function createPBES2Budget(limit) {
1156
+ let remaining = limit;
1157
+ return { spend(attempt) {
1158
+ const { alg, p2c } = attempt;
1159
+ if (!alg.startsWith("PBES2")) return;
1160
+ if (typeof p2c !== "number" || !(p2c > 0)) return;
1161
+ assertPBES2Iterations(p2c, attempt);
1162
+ if (p2c > remaining) throw new JWTError(`PBES2 iteration budget of ${limit} exhausted.`, "ERR_JWE_INVALID");
1163
+ remaining -= p2c;
1164
+ } };
1165
+ }
1166
+ function serializeProtectedHeader(header) {
1167
+ try {
1168
+ return JSON.stringify(header);
1169
+ } catch (error) {
1170
+ throw new JWTError("The protected header is not JSON-serializable.", "ERR_INVALID_OPTION", error);
1171
+ }
1172
+ }
1173
+ function assertProducerCrit(header, family) {
1174
+ const crit = header.crit;
1175
+ if (crit === void 0) return;
1176
+ assertCritShape(crit, {
1177
+ family,
1178
+ code: "ERR_INVALID_OPTION"
1179
+ });
1180
+ for (const param of crit) {
1181
+ if (Object.hasOwn(header, param)) continue;
1182
+ throw new JWTError(`"crit" lists "${param}", which the protected header does not carry.`, "ERR_INVALID_OPTION");
1183
+ }
1184
+ }
1185
+ const PROTECTED_ONLY_PARAMS = {
1186
+ JWS: ["crit", "b64"],
1187
+ JWE: ["crit"]
1021
1188
  };
1189
+ function assertProtectedOnlyOption(header, options) {
1190
+ if (!header) return;
1191
+ const { tier, family } = options;
1192
+ for (const param of PROTECTED_ONLY_PARAMS[family]) {
1193
+ if (!Object.hasOwn(header, param)) continue;
1194
+ throw new JWTError(`${family} "${param}" must be integrity protected; move it from the ${tier} header to the protected header.`, "ERR_INVALID_OPTION");
1195
+ }
1196
+ }
1197
+ function assertOptionEntry(entry, options) {
1198
+ const { label, objects } = options;
1199
+ assertPlainObject(entry, label);
1200
+ for (const member of objects) if (entry[member] !== void 0) assertPlainObject(entry[member], `${label}.${member}`);
1201
+ }
1202
+ function assertProducerPartyInfo(name, value) {
1203
+ if (!(value instanceof Uint8Array)) throw new JWTError(`"${name === "apu" ? "partyUInfo" : "partyVInfo"}" (${name}) must be a Uint8Array.`, "ERR_INVALID_OPTION");
1204
+ if (value.length > 1024) throw new JWTError(`"${name === "apu" ? "partyUInfo" : "partyVInfo"}" (${name}) must not exceed ${MAX_PARTY_INFO_BYTES} bytes (got ${value.length}).`, "ERR_INVALID_OPTION");
1205
+ }
1206
+ function assertProducerCEK(cek, enc) {
1207
+ if (cek === void 0) return;
1208
+ const expected = bitLengthCEK(enc) >> 3;
1209
+ if (!(cek instanceof Uint8Array) || cek.length !== expected) throw new JWTError(`"cek" must be ${expected} bytes for ${enc} (got ${cek instanceof Uint8Array ? cek.length : typeof cek}).`, "ERR_INVALID_OPTION");
1210
+ }
1211
+ function assertProducerIV(iv, enc) {
1212
+ if (iv === void 0) return;
1213
+ const expected = bitLengthIV(enc) >> 3;
1214
+ if (!(iv instanceof Uint8Array) || iv.length !== expected) throw new JWTError(`"contentEncryptionIV" must be ${expected} bytes for ${enc} (got ${iv instanceof Uint8Array ? iv.length : typeof iv}).`, "ERR_INVALID_OPTION");
1215
+ }
1216
+ function assertConsumerOptions(options) {
1217
+ assertOptionEntry(options, {
1218
+ label: "options",
1219
+ objects: ["limits"]
1220
+ });
1221
+ const typ = options.typ;
1222
+ if (typ !== void 0 && (typeof typ !== "string" || typ === "")) throw new JWTError("\"typ\" must be a non-empty string.", "ERR_INVALID_OPTION");
1223
+ assertStringList(options.algorithms, "algorithms");
1224
+ assertStringList(options.encryptionAlgorithms, "encryptionAlgorithms");
1225
+ assertStringList(options.recognizedHeaders, "recognizedHeaders");
1226
+ assertClaimValidationOptions(options);
1227
+ }
1228
+ const JWK_SET_KEY_OPS = /* @__PURE__ */ Object.freeze({
1229
+ sig: ["verify"],
1230
+ enc: [
1231
+ "unwrapKey",
1232
+ "decrypt",
1233
+ "deriveBits",
1234
+ "deriveKey"
1235
+ ]
1236
+ });
1237
+ function buildJWKSetFilter(header, options) {
1238
+ const kid = header?.kid;
1239
+ const alg = header?.alg;
1240
+ const { op, allowSymmetric } = options;
1241
+ const use = op;
1242
+ const keyOps = JWK_SET_KEY_OPS[op];
1243
+ return (k) => {
1244
+ if (!isJWK(k)) return false;
1245
+ if (k.kty === "oct" && !allowSymmetric) return false;
1246
+ if (kid && k.kid !== kid) return false;
1247
+ if (k.alg && k.alg !== alg) return false;
1248
+ if (k.use !== void 0 && k.use !== use) return false;
1249
+ const ops = k.key_ops;
1250
+ if (ops !== void 0 && !(Array.isArray(ops) && ops.some((o) => keyOps.includes(o)))) return false;
1251
+ return true;
1252
+ };
1253
+ }
1254
+ function parseEphemeralKey(ephemeralKey) {
1255
+ if (isCryptoKeyPair(ephemeralKey)) return {
1256
+ epk: ephemeralKey.publicKey,
1257
+ epkPrivateKey: ephemeralKey.privateKey
1258
+ };
1259
+ if (typeof ephemeralKey === "object" && ephemeralKey !== null && "publicKey" in ephemeralKey && "privateKey" in ephemeralKey) {
1260
+ if (!ephemeralKey.publicKey || !ephemeralKey.privateKey) throw new JWTError("ECDH-ES custom ephemeral key must include both publicKey and privateKey.", "ERR_JWK_INVALID");
1261
+ return {
1262
+ epk: ephemeralKey.publicKey,
1263
+ epkPrivateKey: ephemeralKey.privateKey
1264
+ };
1265
+ }
1266
+ if (isCryptoKey(ephemeralKey)) {
1267
+ if (ephemeralKey.type !== "private") throw new JWTError("ECDH-ES custom ephemeral CryptoKey must include private key material.", "ERR_JWK_INVALID");
1268
+ return {
1269
+ epk: ephemeralKey,
1270
+ epkPrivateKey: ephemeralKey
1271
+ };
1272
+ }
1273
+ if (isJWK(ephemeralKey)) {
1274
+ if (!("d" in ephemeralKey) || typeof ephemeralKey.d !== "string") throw new JWTError("ECDH-ES custom ephemeral JWK must include private parameter \"d\".", "ERR_JWK_INVALID");
1275
+ return {
1276
+ epk: ephemeralKey,
1277
+ epkPrivateKey: ephemeralKey
1278
+ };
1279
+ }
1280
+ throw new JWTError("Unsupported ECDH-ES ephemeral key material provided.", "ERR_JWK_INVALID");
1281
+ }
1282
+ function buildECDHAgreementParams(ecdh) {
1283
+ const params = {};
1284
+ if (!ecdh) return params;
1285
+ const { partyUInfo, partyVInfo, ephemeralKey } = ecdh;
1286
+ if (partyUInfo !== void 0) {
1287
+ assertProducerPartyInfo("apu", partyUInfo);
1288
+ if (partyUInfo.length > 0) params.apu = partyUInfo;
1289
+ }
1290
+ if (partyVInfo !== void 0) {
1291
+ assertProducerPartyInfo("apv", partyVInfo);
1292
+ if (partyVInfo.length > 0) params.apv = partyVInfo;
1293
+ }
1294
+ if (ephemeralKey) {
1295
+ const { epk, epkPrivateKey } = parseEphemeralKey(ephemeralKey);
1296
+ params.epk = epk;
1297
+ params.epkPrivateKey = epkPrivateKey;
1298
+ }
1299
+ return params;
1300
+ }
1301
+ async function resolveSigningKey(alg, key, usage) {
1302
+ if (key instanceof Uint8Array) {
1303
+ if (!alg.startsWith("HS")) throw new JWTError(`Raw key bytes are HMAC secrets; ${alg} needs an asymmetric key. Pass a JWK or a CryptoKey.`, "ERR_JWK_INVALID");
1304
+ assertOctKeyLength(key, alg);
1305
+ return crypto.subtle.importKey("raw", key, {
1306
+ name: "HMAC",
1307
+ hash: jwsHashOf(alg)
1308
+ }, false, [usage]);
1309
+ }
1310
+ if (alg.startsWith("RS") || alg.startsWith("PS")) {
1311
+ const modulusLength = modulusLengthOf(key.algorithm);
1312
+ if (typeof modulusLength !== "number" || modulusLength < 2048) throw new JWTError(`${alg} requires a key modulusLength of at least 2048 bits`, "ERR_JWK_INVALID");
1313
+ }
1314
+ return key;
1315
+ }
1316
+ function validateClaimsIfJson(payload, mode, options) {
1317
+ if (mode !== "json" || options.validateClaims === false) return;
1318
+ validateJwtClaims(payload, options);
1319
+ }
1320
+ const PAYLOAD_MODES = /* @__PURE__ */ new Set([
1321
+ "json",
1322
+ "string",
1323
+ "bytes"
1324
+ ]);
1325
+ function resolvePayloadMode(options) {
1326
+ const { payload, forceUint8Array, validateClaims } = options;
1327
+ if (payload !== void 0 && !PAYLOAD_MODES.has(payload)) throw new JWTError("\"payload\" must be \"json\", \"string\" or \"bytes\".", "ERR_INVALID_OPTION");
1328
+ let mode = payload ?? "json";
1329
+ if (forceUint8Array !== void 0) {
1330
+ if (payload === void 0) mode = forceUint8Array ? "bytes" : "json";
1331
+ else if (forceUint8Array !== (payload === "bytes")) throw new JWTError("\"forceUint8Array\" contradicts \"payload\"; pass \"payload\" alone.", "ERR_INVALID_OPTION");
1332
+ }
1333
+ if (validateClaims === true && mode !== "json") throw new JWTError("\"validateClaims\" requires payload: \"json\".", "ERR_INVALID_OPTION");
1334
+ return mode;
1335
+ }
1336
+ function stringKeyError() {
1337
+ return new JWTError("String keys are not accepted: pass an oct JWK or a Uint8Array secret, or import PEM text with importPEM().", "ERR_JWK_INVALID");
1338
+ }
1339
+ function assertNotStringKey(key) {
1340
+ if (typeof key === "string") throw stringKeyError();
1341
+ }
1342
+ function resolvePasswordKey(alg, key) {
1343
+ if (typeof key !== "string") return key;
1344
+ if (!alg.startsWith("PBES2")) throw stringKeyError();
1345
+ return textEncoder.encode(key);
1346
+ }
1347
+ const JWS_ALG_CTX = /* @__PURE__ */ Object.freeze({
1348
+ infer: inferJWSAllowedAlgorithms,
1349
+ octRoles: false,
1350
+ errorCode: "ERR_JWS_ALG_NOT_ALLOWED",
1351
+ label: "Algorithm",
1352
+ op: "sig"
1353
+ });
1354
+ const JWE_ALG_CTX = /* @__PURE__ */ Object.freeze({
1355
+ infer: inferJWEAllowedAlgorithms,
1356
+ octRoles: true,
1357
+ errorCode: "ERR_JWE_ALG_NOT_ALLOWED",
1358
+ label: "Key management algorithm",
1359
+ op: "enc"
1360
+ });
1361
+ function checkAlgAllowed(alg, key, options) {
1362
+ const { ctx, algorithms, allowSymmetric } = options;
1363
+ if (algorithms !== void 0) return algorithms.includes(alg) ? void 0 : notAllowed(alg, ctx);
1364
+ if (isJWK(key) && typeof key.alg === "string" && (!ctx.octRoles || key.kty !== "oct")) return key.alg === alg || isEd25519Signature(key.alg) && isEd25519Signature(alg) ? void 0 : notAllowed(alg, ctx);
1365
+ const inferred = ctx.infer(key, { allowSymmetric });
1366
+ if (!inferred) return new JWTError(`Cannot infer allowed ${ctx.label.toLowerCase()}s from this key; pass "options.algorithms" explicitly.`, ctx.errorCode);
1367
+ return inferred.includes(alg) ? void 0 : notAllowed(alg, ctx);
1368
+ }
1369
+ function notAllowed(alg, ctx) {
1370
+ return new JWTError(`${ctx.label} not allowed: ${alg}`, ctx.errorCode);
1371
+ }
1372
+ function keyMatchesHeader(header, keyMaterial, options) {
1373
+ const { ctx, allowSymmetric } = options;
1374
+ if (isJWKSet(keyMaterial)) {
1375
+ const candidates = keyMaterial.keys.filter(buildJWKSetFilter(header, {
1376
+ op: ctx.op,
1377
+ allowSymmetric
1378
+ }));
1379
+ return candidates.length === 0 || candidates.some((k) => keyServesHeaderAlg(header, k, ctx));
1380
+ }
1381
+ if (isJWK(keyMaterial)) {
1382
+ if (header.kid && keyMaterial.kid && header.kid !== keyMaterial.kid) return false;
1383
+ return keyServesHeaderAlg(header, keyMaterial, ctx);
1384
+ }
1385
+ if (isCryptoKey(keyMaterial)) return keyServesHeaderAlg(header, keyMaterial, ctx);
1386
+ return true;
1387
+ }
1388
+ const JWS_ALGORITHM_SET = /* @__PURE__ */ new Set(Object.keys({
1389
+ HS256: true,
1390
+ HS384: true,
1391
+ HS512: true,
1392
+ RS256: true,
1393
+ RS384: true,
1394
+ RS512: true,
1395
+ PS256: true,
1396
+ PS384: true,
1397
+ PS512: true,
1398
+ ES256: true,
1399
+ ES384: true,
1400
+ ES512: true,
1401
+ Ed25519: true,
1402
+ EdDSA: true
1403
+ }));
1404
+ function checkJWSAlgSupported(alg) {
1405
+ return checkAlgSupported(alg, {
1406
+ supported: JWS_ALGORITHM_SET,
1407
+ code: "ERR_JWS_ALG_NOT_ALLOWED",
1408
+ label: "Algorithm",
1409
+ role: "signing algorithm"
1410
+ });
1411
+ }
1412
+ function checkJWSB64(header) {
1413
+ if (Object.hasOwn(header, "b64") && typeof header.b64 !== "boolean") return new JWTError("Invalid JWS: \"b64\" must be a boolean (RFC 7797 §3).", "ERR_JWS_INVALID");
1414
+ if (header.b64 !== false) return void 0;
1415
+ if (Array.isArray(header.crit) && header.crit.includes("b64")) return void 0;
1416
+ return new JWTError("Invalid JWS: \"b64\" must be listed in \"crit\" (RFC 7797 §6).", "ERR_JWS_INVALID");
1417
+ }
1418
+ function assertB64Option(header) {
1419
+ if (!header || !Object.hasOwn(header, "b64") || typeof header.b64 === "boolean") return;
1420
+ throw new JWTError("\"b64\" must be a boolean (RFC 7797 §3).", "ERR_INVALID_OPTION");
1421
+ }
1422
+ function applyB64Header(header) {
1423
+ assertB64Option(header);
1424
+ if (header.b64 === true) {
1425
+ if (!(Array.isArray(header.crit) && header.crit.includes("b64"))) delete header.b64;
1426
+ return;
1427
+ }
1428
+ if (header.b64 !== false) return;
1429
+ const crit = header.crit;
1430
+ if (crit === void 0) header.crit = ["b64"];
1431
+ else if (Array.isArray(crit) && !crit.includes("b64")) header.crit = [...crit, "b64"];
1432
+ }
1433
+ function assertCompactToken(token, family) {
1434
+ if (typeof token !== "string") throw new JWTError(`Invalid ${family}: token must be a string.`, `ERR_${family}_INVALID`);
1435
+ }
1436
+ function assertSerializationObject(value, family) {
1437
+ if (!isPlainObject(value)) throw new JWTError(`Invalid ${family} JSON Serialization: expected an object.`, `ERR_${family}_INVALID_SERIALIZATION`);
1438
+ }
1439
+ function checkSerializationEntry(entry, options) {
1440
+ const { family, label, objects, strings } = options;
1441
+ const code = `ERR_${family}_INVALID`;
1442
+ if (!isPlainObject(entry)) return new JWTError(`Invalid ${family}: ${label} must be a JSON object.`, code);
1443
+ for (const member of objects) if (entry[member] !== void 0 && !isPlainObject(entry[member])) return new JWTError(`Invalid ${family}: ${label} "${member}" must be a JSON object.`, code);
1444
+ for (const member of strings) if (entry[member] !== void 0 && typeof entry[member] !== "string") return new JWTError(`Invalid ${family}: ${label} "${member}" must be a string.`, code);
1445
+ }
1446
+ function asKeyLookupError(error, what) {
1447
+ return asJWTError(error, {
1448
+ code: "ERR_JWK_KEY_NOT_FOUND",
1449
+ message: `Key lookup failed for ${what}.`
1450
+ });
1451
+ }
1452
+ function asJWTError(error, options) {
1453
+ if (error instanceof JWTError) return error;
1454
+ return new JWTError(options.message, options.code, error);
1455
+ }
1456
+ function asDecryptionError(error) {
1457
+ return asJWTError(error, {
1458
+ code: "ERR_JWE_DECRYPTION_FAILED",
1459
+ message: "JWE decryption failed."
1460
+ });
1461
+ }
1462
+ async function resolveKeyInput(key, options) {
1463
+ if (typeof key !== "function") return key;
1464
+ const { header, token, what } = options;
1465
+ let resolved;
1466
+ try {
1467
+ resolved = await key(header, token);
1468
+ } catch (error) {
1469
+ throw asKeyLookupError(error, what);
1470
+ }
1471
+ if (resolved === void 0 || resolved === null) throw new JWTError(`Key lookup returned no key for ${what}.`, "ERR_JWK_KEY_NOT_FOUND");
1472
+ return resolved;
1473
+ }
1474
+ function asKeyUsageError(error, alg) {
1475
+ return asJWTError(error, {
1476
+ code: "ERR_JWK_INVALID",
1477
+ message: `Key is not usable for ${alg}.`
1478
+ });
1479
+ }
1480
+ const JWE_ALGORITHM_SET = /* @__PURE__ */ new Set(Object.keys({
1481
+ "dir": true,
1482
+ "A128KW": true,
1483
+ "A192KW": true,
1484
+ "A256KW": true,
1485
+ "A128GCMKW": true,
1486
+ "A192GCMKW": true,
1487
+ "A256GCMKW": true,
1488
+ "PBES2-HS256+A128KW": true,
1489
+ "PBES2-HS384+A192KW": true,
1490
+ "PBES2-HS512+A256KW": true,
1491
+ "RSA-OAEP": true,
1492
+ "RSA-OAEP-256": true,
1493
+ "RSA-OAEP-384": true,
1494
+ "RSA-OAEP-512": true,
1495
+ "ECDH-ES": true,
1496
+ "ECDH-ES+A128KW": true,
1497
+ "ECDH-ES+A192KW": true,
1498
+ "ECDH-ES+A256KW": true
1499
+ }));
1500
+ const JWE_ENC_CEK_FORMAT = /* @__PURE__ */ Object.freeze({
1501
+ "A128GCM": "cryptokey",
1502
+ "A192GCM": "cryptokey",
1503
+ "A256GCM": "cryptokey",
1504
+ "A128CBC-HS256": "raw",
1505
+ "A192CBC-HS384": "raw",
1506
+ "A256CBC-HS512": "raw"
1507
+ });
1508
+ function assertDirectKeyRole(key, enc) {
1509
+ if (!isJWK(key) || typeof key.alg !== "string" || key.alg === "dir") return;
1510
+ if (enc !== void 0 && key.alg === enc) return;
1511
+ throw new JWTError(`JWK "alg" is "${key.alg}" but "dir" requires a key declared as "dir" or as the token's "enc" (${enc ?? "unknown"}).`, "ERR_JWK_INVALID");
1512
+ }
1513
+ const JWE_DIRECT_ALGS = /* @__PURE__ */ new Set(["dir", "ECDH-ES"]);
1514
+ function checkJWEAlgSupported(alg) {
1515
+ return checkAlgSupported(alg, {
1516
+ supported: JWE_ALGORITHM_SET,
1517
+ code: "ERR_JWE_ALG_NOT_ALLOWED",
1518
+ label: "Key management algorithm",
1519
+ role: "key management algorithm"
1520
+ });
1521
+ }
1522
+ function checkJWEEncSupported(enc) {
1523
+ if (typeof enc === "string" && isContentEncryptionAlgorithm(enc)) return void 0;
1524
+ return new JWTError(`Invalid JWE: unsupported "enc" ${quoteTokenValue(enc)}`, "ERR_JWE_INVALID");
1525
+ }
1526
+ function isJWEAlgSupported(alg) {
1527
+ return JWE_ALGORITHM_SET.has(alg);
1528
+ }
1529
+ function assertJWEAlgSupported(alg) {
1530
+ const error = checkJWEAlgSupported(alg);
1531
+ if (error) throw error;
1532
+ }
1533
+ function assertJWEEncSupported(enc) {
1534
+ const error = checkJWEEncSupported(enc);
1535
+ if (error) throw error;
1536
+ }
1537
+ function checkJWEEncAllowed(enc, encryptionAlgorithms) {
1538
+ if (encryptionAlgorithms === void 0 || encryptionAlgorithms.includes(enc)) return void 0;
1539
+ return new JWTError(`Content encryption algorithm not allowed: ${enc}`, "ERR_JWE_ALG_NOT_ALLOWED");
1540
+ }
1541
+ async function exportReturnedCek(cek) {
1542
+ if (!isCryptoKey(cek)) return cek;
1543
+ if (!cek.extractable) throw new JWTError("\"returnCek\" requires an extractable content encryption key.", "ERR_INVALID_OPTION");
1544
+ return new Uint8Array(await crypto.subtle.exportKey("raw", cek));
1545
+ }
1546
+ function cekFormatForEnc(enc) {
1547
+ return JWE_ENC_CEK_FORMAT[enc];
1548
+ }
1549
+ function buildUnwrapKeyOptions(header, algorithms, options) {
1550
+ const { alg, enc } = algorithms;
1551
+ const opts = {
1552
+ alg,
1553
+ enc,
1554
+ format: cekFormatForEnc(enc),
1555
+ keyUsage: options?.keyUsage || ["decrypt"]
1556
+ };
1557
+ if (header.iv) opts.iv = header.iv;
1558
+ if (header.tag) opts.tag = header.tag;
1559
+ if (header.p2s) opts.p2s = header.p2s;
1560
+ if (header.p2c) opts.p2c = header.p2c;
1561
+ if (header.epk) opts.epk = header.epk;
1562
+ if (header.apu) opts.apu = header.apu;
1563
+ if (header.apv) opts.apv = header.apv;
1564
+ if (options?.unwrappedKeyAlgorithm) opts.unwrappedKeyAlgorithm = options.unwrappedKeyAlgorithm;
1565
+ if (options?.extractable !== void 0) opts.extractable = options.extractable;
1566
+ if (options?.minIterations !== void 0) opts.minIterations = options.minIterations;
1567
+ if (options?.maxIterations !== void 0) opts.maxIterations = options.maxIterations;
1568
+ return opts;
1569
+ }
1570
+ function checkJWEDirectEncryptedKey(alg, encryptedKey) {
1571
+ if (!JWE_DIRECT_ALGS.has(alg) || !encryptedKey) return void 0;
1572
+ return new JWTError(`Invalid JWE: Encrypted key must be empty for ${alg}.`, "ERR_JWE_INVALID");
1573
+ }
1574
+ function checkJWEContentSegments(enc, iv, tag) {
1575
+ const ivBytes = bitLengthIV(enc) >> 3;
1576
+ if (iv.length !== ivBytes) return new JWTError(`Invalid JWE: Initialization vector must be ${ivBytes} bytes for ${enc} (got ${iv.length}).`, "ERR_JWE_INVALID");
1577
+ const tagBytes = bitLengthTag(enc) >> 3;
1578
+ if (tag.length !== tagBytes) return new JWTError(`Invalid JWE: Authentication tag must be ${tagBytes} bytes for ${enc} (got ${tag.length}).`, "ERR_JWE_INVALID");
1579
+ }
1580
+ function checkJWEZip(header) {
1581
+ if (!header || !Object.hasOwn(header, "zip")) return void 0;
1582
+ return new JWTError("Invalid JWE: compression is not supported.", "ERR_JWE_INVALID");
1583
+ }
1584
+ function assertNoZipOption(header, tier) {
1585
+ if (!header || !Object.hasOwn(header, "zip")) return;
1586
+ throw new JWTError(`JWE compression ("zip") is not supported; remove it from the ${tier} header.`, "ERR_INVALID_OPTION");
1587
+ }
1588
+ function checkJWEUnprotectedCrit(header) {
1589
+ if (!header || !Object.hasOwn(header, "crit")) return void 0;
1590
+ return new JWTError("Invalid JWE: \"crit\" must be integrity protected (RFC 7516 §4.1.13).", "ERR_JWE_INVALID");
1591
+ }
1592
+ function typMatches(expected, actual) {
1593
+ if (typeof actual !== "string") return false;
1594
+ return normalizeTyp(expected) === normalizeTyp(actual);
1595
+ }
1596
+ function checkProtectedTyp(expected, protectedHeader, options) {
1597
+ if (expected === void 0) return void 0;
1598
+ const actual = protectedHeader.typ;
1599
+ if (typMatches(expected, actual)) return void 0;
1600
+ const { family, label } = options;
1601
+ const where = label ? ` on ${label}` : "";
1602
+ const message = actual === void 0 ? `Invalid ${family}: the protected header${where} carries no "typ"; expected "${expected}".` : `Invalid ${family}: "typ" (Type) Header Parameter mismatch${where}. Expected "${expected}", got ${JSON.stringify(actual)}.`;
1603
+ return new JWTError(message, `ERR_${family}_INVALID`);
1604
+ }
1605
+ function normalizeTyp(typ) {
1606
+ const lowered = typ.toLowerCase();
1607
+ return lowered.includes("/") ? lowered : `application/${lowered}`;
1608
+ }
1609
+ function decodeProtectedHeader(encoded, family) {
1610
+ let parsed = {};
1611
+ if (encoded) {
1612
+ try {
1613
+ parsed = safeJsonParse(base64UrlParse(encoded));
1614
+ } catch (error) {
1615
+ throw new JWTError(`Invalid ${family}: Protected header could not be decoded.`, `ERR_${family}_INVALID`, error);
1616
+ }
1617
+ if (!isPlainObject(parsed)) throw new JWTError(`Invalid ${family}: Protected header must be a JSON object.`, `ERR_${family}_INVALID`);
1618
+ }
1619
+ return parsed;
1620
+ }
1621
+ function decodeSegment(encoded, options) {
1622
+ try {
1623
+ return base64UrlParse(encoded, { returnAs: "uint8array" });
1624
+ } catch (error) {
1625
+ throw new JWTError(`Invalid ${options.family}: ${options.what} could not be decoded.`, `ERR_${options.family}_INVALID`, error);
1626
+ }
1627
+ }
1628
+ function decodeJWSPayload(payloadSegment, useB64, mode) {
1629
+ if (!useB64) return mode === "string" ? payloadSegment : parsePayloadBytes(textEncoder.encode(payloadSegment), {
1630
+ payload: mode,
1631
+ family: "JWS"
1632
+ });
1633
+ try {
1634
+ return parsePayloadSegment(payloadSegment, {
1635
+ payload: mode,
1636
+ family: "JWS"
1637
+ });
1638
+ } catch (error) {
1639
+ if (error instanceof JWTError) throw error;
1640
+ throw new JWTError("Invalid JWS: Payload could not be decoded.", "ERR_JWS_INVALID", error);
1641
+ }
1642
+ }
1643
+ function decodeJWEPayload(plaintext, mode) {
1644
+ return parsePayloadBytes(plaintext, {
1645
+ payload: mode,
1646
+ family: "JWE"
1647
+ });
1648
+ }
1649
+ function checkAlgSupported(alg, options) {
1650
+ const { supported, code, label, role } = options;
1651
+ if (alg === "none") return new JWTError(`"none" is not a valid ${role}`, code);
1652
+ if (!supported.has(alg)) return new JWTError(`${label} not supported: ${quoteTokenValue(alg)}`, code);
1653
+ }
1654
+ function keyServesHeaderAlg(header, key, ctx) {
1655
+ const { alg } = header;
1656
+ if (!alg) return false;
1657
+ const inferred = ctx.infer(key);
1658
+ if (inferred && !inferred.includes(alg)) return false;
1659
+ if (!alg.startsWith("ECDH-ES")) return true;
1660
+ const epkCurve = header.epk?.crv;
1661
+ const keyCurve = isCryptoKey(key) ? cryptoKeyCurve(key) : "crv" in key ? key.crv : void 0;
1662
+ return !epkCurve || !keyCurve || epkCurve === keyCurve;
1663
+ }
1022
1664
  async function generateKey(alg, options = {}) {
1023
- const exportToJWK = options.toJWK !== void 0 && options.toJWK !== false;
1665
+ const exportToJWK = options.toJWK !== void 0 && options.toJWK;
1024
1666
  const defaultExtractable = exportToJWK || options.extractable !== false;
1667
+ const kid = exportToJWK ? assertKidOption(options.kid) : void 0;
1025
1668
  if (alg === "A128CBC-HS256" || alg === "A192CBC-HS384" || alg === "A256CBC-HS512") {
1026
- const keyBytes = secureRandomBytes(bitLengthCEK(alg) >> 3);
1027
- if (exportToJWK) return keyToJWK(keyBytes);
1669
+ const keyLength = bitLengthCEK(alg);
1670
+ const keyBytes = secureRandomBytes(keyLength >> 3);
1671
+ if (exportToJWK) return withGeneratedKid(kid, {
1672
+ ...await keyToJWK(keyBytes),
1673
+ alg,
1674
+ ext: true,
1675
+ key_ops: resolveKeyUsage(options.keyUsage, {
1676
+ allowed: CONTENT_ENCRYPTION_USAGES,
1677
+ fallback: ["encrypt", "decrypt"],
1678
+ alg
1679
+ })
1680
+ });
1028
1681
  return keyBytes;
1029
1682
  }
1030
1683
  const { algorithm, keyUsages } = getGenerateKeyParams(alg, options);
1031
1684
  const key = await crypto.subtle.generateKey(algorithm, defaultExtractable, keyUsages);
1032
- if (exportToJWK) if (key instanceof CryptoKey) return {
1033
- ...await exportKey(key),
1034
- alg
1035
- };
1036
- else {
1037
- const [pub, priv] = await Promise.all([exportKey(key.publicKey), exportKey(key.privateKey)]);
1038
- return {
1039
- privateKey: {
1040
- ...priv,
1041
- alg
1042
- },
1043
- publicKey: {
1685
+ if (exportToJWK) {
1686
+ if (key instanceof CryptoKey) return withGeneratedKid(kid, {
1687
+ ...await exportKey(key),
1688
+ alg
1689
+ });
1690
+ else {
1691
+ const [pub, priv] = await Promise.all([exportKey(key.publicKey), exportKey(key.privateKey)]);
1692
+ const publicKey = await withGeneratedKid(kid, {
1044
1693
  ...pub,
1045
1694
  alg
1046
- }
1047
- };
1695
+ });
1696
+ const named = publicKey.kid === void 0 ? void 0 : { kid: publicKey.kid };
1697
+ return {
1698
+ privateKey: {
1699
+ ...priv,
1700
+ alg,
1701
+ ...named
1702
+ },
1703
+ publicKey
1704
+ };
1705
+ }
1048
1706
  }
1049
1707
  return key;
1050
1708
  }
1051
1709
  async function generateJWK(alg, options) {
1052
- const { keyUsage, modulusLength, publicExponent, namedCurve, ...jwkParams } = options ?? {};
1053
- const kid = typeof jwkParams.kid === "string" ? jwkParams.kid : crypto.randomUUID();
1054
- const extraParams = {
1055
- ...jwkParams,
1056
- kid
1057
- };
1710
+ const { keyUsage, modulusLength, publicExponent, namedCurve, kid, extractable: _extractable, toJWK: _toJWK, ...jwkParams } = options ?? {};
1711
+ assertNoReservedJWKParams(jwkParams);
1058
1712
  const result = await generateKey(alg, {
1059
1713
  keyUsage,
1060
1714
  modulusLength,
1061
1715
  publicExponent,
1062
1716
  namedCurve,
1717
+ kid,
1063
1718
  toJWK: true
1064
1719
  });
1065
- if (result && typeof result === "object" && "privateKey" in result && "publicKey" in result) {
1066
- const pair = result;
1067
- return {
1068
- privateKey: {
1069
- ...extraParams,
1070
- ...pair.privateKey
1071
- },
1072
- publicKey: {
1073
- ...extraParams,
1074
- ...pair.publicKey
1075
- }
1076
- };
1077
- }
1720
+ if (result && typeof result === "object" && "privateKey" in result && "publicKey" in result) return {
1721
+ privateKey: {
1722
+ ...jwkParams,
1723
+ ...result.privateKey
1724
+ },
1725
+ publicKey: {
1726
+ ...jwkParams,
1727
+ ...result.publicKey
1728
+ }
1729
+ };
1078
1730
  return {
1079
- ...extraParams,
1731
+ ...jwkParams,
1080
1732
  ...result
1081
1733
  };
1082
1734
  }
1083
- async function deriveKeyFromPassword(password, alg, options) {
1084
- const { salt, iterations, extractable, keyUsage } = options;
1085
- const exportToJWK = options.toJWK !== void 0 && options.toJWK !== false;
1086
- if (!(salt instanceof Uint8Array) || salt.length < 8) throw new JWTError("PBES2 Salt Input (salt) must be 8 or more octets", "ERR_JWE_INVALID");
1087
- if (typeof iterations !== "number" || iterations < 1) throw new JWTError("PBES2 Iteration Count (iterations) must be a positive integer", "ERR_JWE_INVALID");
1088
- const derivedBytes = await deriveKey(salt, alg, iterations, typeof password === "string" ? textEncoder.encode(password) : password);
1089
- const wrappingAlg = alg.slice(-6);
1735
+ async function deriveKeyFromPassword(password, options) {
1736
+ assertPlainObject(options, "options");
1737
+ if (typeof password !== "string" && !(password instanceof Uint8Array)) throw new JWTError("\"password\" must be a string or a Uint8Array.", "ERR_INVALID_OPTION");
1738
+ const { alg, salt, iterations, extractable, keyUsage } = options;
1739
+ assertPBES2Algorithm(alg);
1740
+ const exportToJWK = options.toJWK !== void 0 && options.toJWK;
1741
+ const saltBytes = typeof salt === "string" ? textEncoder.encode(salt) : salt;
1742
+ assertPBES2Salt(saltBytes, "\"salt\"");
1743
+ assertPBES2Count(iterations, "\"iterations\"");
1744
+ const derivedBytes = await deriveKey(saltBytes, alg, iterations, typeof password === "string" ? textEncoder.encode(password) : password);
1745
+ const wrappingAlg = innerKeyWrapAlg(alg);
1090
1746
  const finalUsages = keyUsage ?? ["wrapKey", "unwrapKey"];
1091
1747
  const finalExtractable = exportToJWK ? true : extractable === true;
1092
1748
  const derivedKey = await crypto.subtle.importKey("raw", derivedBytes, { name: "AES-KW" }, finalExtractable, finalUsages);
@@ -1097,18 +1753,22 @@ async function deriveKeyFromPassword(password, alg, options) {
1097
1753
  };
1098
1754
  return derivedKey;
1099
1755
  }
1100
- async function deriveJWKFromPassword(password, alg, options) {
1101
- const { salt, iterations, keyUsage, ...jwkParams } = options;
1102
- const result = await deriveKeyFromPassword(password, alg, {
1756
+ async function deriveJWKFromPassword(password, options) {
1757
+ assertPlainObject(options, "options");
1758
+ const { alg, salt, iterations, keyUsage, kid: kidOption, extractable: _extractable, toJWK: _toJWK, ...jwkParams } = options;
1759
+ assertNoReservedJWKParams(jwkParams);
1760
+ const kid = assertKidOption(kidOption);
1761
+ const result = await deriveKeyFromPassword(password, {
1762
+ alg,
1103
1763
  salt,
1104
1764
  iterations,
1105
1765
  keyUsage,
1106
1766
  toJWK: true
1107
1767
  });
1108
- return Object.keys(jwkParams).length > 0 ? {
1768
+ return {
1109
1769
  ...jwkParams,
1110
- ...result
1111
- } : result;
1770
+ ...await withGeneratedKid(kid, result)
1771
+ };
1112
1772
  }
1113
1773
  var WeakMapJWKCache = class {
1114
1774
  _map = /* @__PURE__ */ new WeakMap();
@@ -1131,44 +1791,58 @@ function clearJWKCache() {
1131
1791
  async function importKey(key, algOrOptions) {
1132
1792
  const alg = typeof algOrOptions === "string" ? algOrOptions : algOrOptions?.alg ?? void 0;
1133
1793
  const expect = typeof algOrOptions === "object" ? algOrOptions.expect ?? void 0 : void 0;
1134
- if (typeof key === "string") key = textEncoder.encode(key);
1794
+ const extractable = typeof algOrOptions === "object" && !algOrOptions.asCryptoKey ? algOrOptions.extractable : void 0;
1795
+ if (typeof key === "string") throw stringKeyError();
1135
1796
  if (key instanceof Uint8Array) return key;
1136
1797
  if (isCryptoKey(key)) {
1137
1798
  assertIntentOnCryptoKey(key, expect);
1138
1799
  return key;
1139
1800
  }
1140
- if (isJWK(key)) if ("k" in key && typeof key.k === "string") {
1141
- const rawBytes = base64UrlDecode(key.k, { returnAs: "uint8array" });
1142
- assertOctKeyLength(rawBytes, key.alg || alg);
1143
- if (typeof algOrOptions === "object" && algOrOptions.asCryptoKey) {
1144
- const { algorithm, usage, extractable = false } = algOrOptions;
1145
- if (!algorithm || !usage) throw new JWTError("asCryptoKey option requires `algorithm` and `usage` to be provided.", "ERR_JWK_INVALID");
1146
- if (typeof algorithm === "object" && algorithm.name === "HMAC") {
1147
- const hash = algorithm.hash;
1148
- const hashName = typeof hash === "string" ? hash : hash?.name;
1149
- const minBytes = Number.parseInt(hashName?.slice(-3) ?? "", 10) / 8;
1150
- if (minBytes && rawBytes.length < minBytes) throw new JWTError(`HMAC with ${hashName} requires a key of at least ${minBytes} bytes (got ${rawBytes.length})`, "ERR_JWK_INVALID");
1801
+ if (isJWK(key)) {
1802
+ assertJWKAlgAuthority(key, alg);
1803
+ if ("k" in key && typeof key.k === "string") {
1804
+ const rawBytes = decodeSegment(key.k, {
1805
+ family: "JWK",
1806
+ what: "\"k\""
1807
+ });
1808
+ assertOctKeyLength(rawBytes, alg ?? key.alg);
1809
+ if (typeof algOrOptions === "object" && algOrOptions.asCryptoKey) {
1810
+ const { algorithm, usage, extractable: rawExtractable = false } = algOrOptions;
1811
+ if (!algorithm || !usage) throw new JWTError("asCryptoKey option requires `algorithm` and `usage` to be provided.", "ERR_JWK_INVALID");
1812
+ if (typeof algorithm === "object" && algorithm.name === "HMAC") {
1813
+ const hash = "hash" in algorithm ? algorithm.hash : void 0;
1814
+ const hashName = typeof hash === "string" ? hash : typeof hash === "object" && hash !== null && "name" in hash && typeof hash.name === "string" ? hash.name : void 0;
1815
+ const minBytes = Number.parseInt(hashName?.slice(-3) ?? "", 10) / 8;
1816
+ if (minBytes && rawBytes.length < minBytes) throw new JWTError(`HMAC with ${hashName} requires a key of at least ${minBytes} bytes (got ${rawBytes.length})`, "ERR_JWK_INVALID");
1817
+ }
1818
+ return crypto.subtle.importKey("raw", rawBytes, algorithm, rawExtractable, usage);
1151
1819
  }
1152
- return crypto.subtle.importKey("raw", rawBytes, algorithm, extractable, usage);
1153
- }
1154
- return rawBytes;
1155
- } else {
1156
- if (!key.alg && !alg) throw new JWTError("Algorithm must be provided when importing non-oct JWK", "ERR_JWK_INVALID");
1157
- assertIntentOnJWK(key, expect);
1158
- const effectiveAlg = key.alg || alg;
1159
- if (_activeCache) {
1160
- const cached = _activeCache.get(key, effectiveAlg);
1161
- if (cached) return cached;
1820
+ return rawBytes;
1821
+ } else {
1822
+ const effectiveAlg = key.alg || alg;
1823
+ if (!effectiveAlg) throw new JWTError("Algorithm must be provided when importing non-oct JWK", "ERR_JWK_INVALID");
1824
+ assertIntentOnJWK(key, expect);
1825
+ const cache = extractable === void 0 ? _activeCache : false;
1826
+ if (cache) {
1827
+ const cached = await cache.get(key, effectiveAlg);
1828
+ if (cached) return cached;
1829
+ }
1830
+ const cryptoKey = await jwkTokey(key.alg ? key : {
1831
+ ...key,
1832
+ alg
1833
+ }, { extractable });
1834
+ if (cache) await cache.set(key, effectiveAlg, cryptoKey);
1835
+ return cryptoKey;
1162
1836
  }
1163
- const cryptoKey = await jwkTokey(key.alg ? key : {
1164
- ...key,
1165
- alg
1166
- });
1167
- if (_activeCache) _activeCache.set(key, effectiveAlg, cryptoKey);
1168
- return cryptoKey;
1169
1837
  }
1170
1838
  throw new JWTError("Invalid key type provided to importKey", "ERR_JWK_INVALID");
1171
1839
  }
1840
+ function assertJWKAlgAuthority(jwk, alg) {
1841
+ if (!alg || !jwk.alg || jwk.alg === alg) return;
1842
+ if (jwk.kty === "oct" && alg === "dir" && isContentEncryptionAlgorithm(jwk.alg)) return;
1843
+ if (isEd25519Signature(jwk.alg) && isEd25519Signature(alg)) return;
1844
+ throw new JWTError(`JWK "alg" is "${jwk.alg}" but the operation requires "${alg}".`, "ERR_JWK_INVALID");
1845
+ }
1172
1846
  function assertIntentOnJWK(jwk, expect) {
1173
1847
  if (expect === void 0 || jwk.kty === "oct") return;
1174
1848
  const hasPrivateScalar = "d" in jwk && typeof jwk.d === "string";
@@ -1181,27 +1855,35 @@ function assertIntentOnCryptoKey(key, expect) {
1181
1855
  if (expect === "private" && key.type === "public") throw new JWTError("Public CryptoKey passed where a private key is expected.", "ERR_JWK_INVALID");
1182
1856
  }
1183
1857
  async function exportKey(key, jwkParams) {
1858
+ if (!isCryptoKey(key)) throw new JWTError(`exportKey expects a CryptoKey, got ${key === null ? "null" : typeof key}.`, "ERR_INVALID_OPTION");
1859
+ if (!key.extractable) throw new JWTError("A non-extractable CryptoKey cannot be exported as a JWK.", "ERR_JWK_INVALID");
1184
1860
  const exportedJwk = await keyToJWK(key);
1185
- if (jwkParams) return {
1186
- ...exportedJwk,
1187
- ...sanitizeObjectCopy(jwkParams)
1188
- };
1861
+ if (jwkParams) {
1862
+ const extraParams = sanitizeObjectCopy(jwkParams);
1863
+ assertNoReservedJWKParams(extraParams);
1864
+ return {
1865
+ ...exportedJwk,
1866
+ ...extraParams
1867
+ };
1868
+ }
1189
1869
  return exportedJwk;
1190
1870
  }
1191
- async function resolveWrappingKey(alg, key, expect) {
1192
- if (alg.startsWith("PBES2") && (typeof key === "string" || key instanceof Uint8Array)) return typeof key === "string" ? textEncoder.encode(key) : key;
1193
- if (typeof key === "string") throw new TypeError(`Key must be CryptoKey, JWK, or Uint8Array for ${alg}`);
1194
- if (expect !== void 0) return importKey(key, {
1871
+ async function wrapKey(keyToWrap, wrappingKey, options) {
1872
+ assertPlainObject(options, "options");
1873
+ assertKeyBytesArg(keyToWrap, "keyToWrap");
1874
+ const { alg } = options;
1875
+ const cekBytes = keyToWrap instanceof Uint8Array ? keyToWrap : new Uint8Array(await crypto.subtle.exportKey("raw", keyToWrap));
1876
+ if (alg.endsWith("KW")) assertWrappableCEK(cekBytes, alg);
1877
+ if (alg.startsWith("PBES2")) assertPBES2Params({
1878
+ p2s: options.p2s,
1879
+ p2c: options.p2c
1880
+ });
1881
+ const importedWrappingKey = await importKey(resolvePasswordKey(alg, wrappingKey), {
1195
1882
  alg,
1196
- expect
1883
+ expect: "public"
1197
1884
  });
1198
- return importKey(key, alg);
1199
- }
1200
- async function wrapKey(alg, keyToWrap, wrappingKey, options = {}) {
1201
- const cekBytes = keyToWrap instanceof Uint8Array ? keyToWrap : new Uint8Array(await crypto.subtle.exportKey("raw", keyToWrap));
1202
- const importedWrappingKey = await resolveWrappingKey(alg, wrappingKey, "public");
1203
1885
  switch (alg) {
1204
- case "dir": return { encryptedKey: new Uint8Array(0) };
1886
+ case "dir": return { encryptedKey: /* @__PURE__ */ new Uint8Array(0) };
1205
1887
  case "A128KW":
1206
1888
  case "A192KW":
1207
1889
  case "A256KW": return { encryptedKey: await aesKwWrap(alg, importedWrappingKey, cekBytes) };
@@ -1225,43 +1907,51 @@ async function wrapKey(alg, keyToWrap, wrappingKey, options = {}) {
1225
1907
  case "RSA-OAEP":
1226
1908
  case "RSA-OAEP-256":
1227
1909
  case "RSA-OAEP-384":
1228
- case "RSA-OAEP-512": return { encryptedKey: await encryptRSAES(alg, importedWrappingKey, cekBytes) };
1910
+ case "RSA-OAEP-512":
1911
+ assertCryptoKeyFor(alg, importedWrappingKey, "wrapping");
1912
+ return { encryptedKey: await encryptRSAES(alg, importedWrappingKey, cekBytes) };
1229
1913
  case "ECDH-ES":
1230
1914
  case "ECDH-ES+A128KW":
1231
1915
  case "ECDH-ES+A192KW":
1232
1916
  case "ECDH-ES+A256KW": {
1233
- if (!(importedWrappingKey instanceof CryptoKey)) throw new TypeError("ECDH-ES requires the wrapping key to be a CryptoKey (recipient's public key)");
1234
- if (!isECDHKeyAllowed(importedWrappingKey)) throw new JWTError("ECDH with the provided key is not allowed or not supported", "ERR_JWK_INVALID");
1235
- const apu = options.ecdh?.partyUInfo ?? new Uint8Array(0);
1236
- const apv = options.ecdh?.partyVInfo ?? new Uint8Array(0);
1237
- const { ephemeralPrivateKey, epkJwk } = await resolveECDHEphemeralPair(importedWrappingKey, options.ecdh?.ephemeralKey);
1238
- const infoAlg = alg === "ECDH-ES" ? (() => {
1239
- if (!options.ecdh?.enc) throw new JWTError("ECDH-ES direct key agreement requires options.ecdh.enc (the target content encryption algorithm)", "ERR_JWK_INVALID");
1240
- return options.ecdh.enc;
1241
- })() : alg;
1242
- const sharedSecret = await deriveECDHESKey(importedWrappingKey, ephemeralPrivateKey, infoAlg, alg === "ECDH-ES" ? bitLengthCEK(infoAlg) : Number.parseInt(alg.slice(-5, -2), 10), apu, apv);
1917
+ assertCryptoKeyFor(alg, importedWrappingKey, "wrapping");
1918
+ const enc = options.ecdh?.enc;
1919
+ if (alg === "ECDH-ES" && !enc) throw new JWTError("ECDH-ES direct key agreement requires options.ecdh.enc (the target content encryption algorithm)", "ERR_JWK_INVALID");
1920
+ const { encryptedKey, parameters } = await ecdhesWrap(alg, {
1921
+ enc,
1922
+ recipientKey: importedWrappingKey,
1923
+ cek: cekBytes,
1924
+ parameters: buildECDHAgreementParams(options.ecdh)
1925
+ });
1243
1926
  const wrapResult = {
1244
- encryptedKey: new Uint8Array(0),
1245
- epk: epkJwk
1927
+ encryptedKey: encryptedKey ?? /* @__PURE__ */ new Uint8Array(0),
1928
+ epk: parameters.epk
1246
1929
  };
1247
- if (apu.length > 0) wrapResult.apu = base64UrlEncode(apu);
1248
- if (apv.length > 0) wrapResult.apv = base64UrlEncode(apv);
1249
- if (alg === "ECDH-ES") return wrapResult;
1250
- wrapResult.encryptedKey = await aesKwWrap(alg.slice(-6), sharedSecret, cekBytes);
1930
+ if (parameters.apu) wrapResult.apu = parameters.apu;
1931
+ if (parameters.apv) wrapResult.apv = parameters.apv;
1251
1932
  return wrapResult;
1252
1933
  }
1253
1934
  default: throw new JWTError(`Unsupported key wrapping algorithm: ${alg}`, "ERR_JWK_UNSUPPORTED");
1254
1935
  }
1255
1936
  }
1256
- async function unwrapKey(alg, wrappedKey, unwrappingKey, options = {}) {
1937
+ async function unwrapKey(wrappedKey, unwrappingKey, options) {
1938
+ assertPlainObject(options, "options");
1939
+ if (!(wrappedKey instanceof Uint8Array)) throw new JWTError("\"wrappedKey\" must be a Uint8Array.", "ERR_INVALID_OPTION");
1940
+ const { alg } = options;
1257
1941
  const returnRaw = options.format === "raw";
1258
1942
  const defaultExtractable = options.extractable !== false;
1259
- const importedUnwrappingKey = await resolveWrappingKey(alg, unwrappingKey, "private");
1943
+ const importedUnwrappingKey = await importKey(resolvePasswordKey(alg, unwrappingKey), {
1944
+ alg,
1945
+ expect: "private"
1946
+ });
1260
1947
  let unwrappedCekBytes;
1261
1948
  switch (alg) {
1262
1949
  case "dir":
1263
- if (importedUnwrappingKey instanceof Uint8Array) unwrappedCekBytes = importedUnwrappingKey;
1264
- else {
1950
+ assertDirectKeyRole(unwrappingKey, options.enc);
1951
+ if (importedUnwrappingKey instanceof Uint8Array) {
1952
+ assertOctKeyLength(importedUnwrappingKey, options.enc);
1953
+ unwrappedCekBytes = importedUnwrappingKey;
1954
+ } else {
1265
1955
  if (!returnRaw) return importedUnwrappingKey;
1266
1956
  unwrappedCekBytes = new Uint8Array(await crypto.subtle.exportKey("raw", importedUnwrappingKey));
1267
1957
  }
@@ -1269,28 +1959,33 @@ async function unwrapKey(alg, wrappedKey, unwrappingKey, options = {}) {
1269
1959
  case "A128KW":
1270
1960
  case "A192KW":
1271
1961
  case "A256KW":
1272
- unwrappedCekBytes = await aesKwUnwrap(alg, importedUnwrappingKey, wrappedKey);
1962
+ unwrappedCekBytes = await unwrapping(aesKwUnwrap(alg, importedUnwrappingKey, wrappedKey));
1273
1963
  break;
1274
1964
  case "PBES2-HS256+A128KW":
1275
1965
  case "PBES2-HS384+A192KW":
1276
1966
  case "PBES2-HS512+A256KW": {
1277
1967
  const { p2s, p2c, minIterations, maxIterations } = options;
1278
1968
  if (!p2s || typeof p2c !== "number") throw new JWTError("PBES2 requires 'p2s' (salt) and 'p2c' (count) options", "ERR_JWE_INVALID");
1279
- unwrappedCekBytes = await pbes2Unwrap(alg, importedUnwrappingKey, wrappedKey, p2c, typeof p2s === "string" ? base64UrlDecode(p2s, { returnAs: "uint8array" }) : p2s, minIterations, maxIterations);
1969
+ unwrappedCekBytes = await unwrapping(pbes2Unwrap(alg, importedUnwrappingKey, wrappedKey, p2c, segmentBytes(p2s, "p2s"), minIterations, maxIterations));
1280
1970
  break;
1281
1971
  }
1282
1972
  case "A128GCMKW":
1283
1973
  case "A192GCMKW":
1284
- case "A256GCMKW":
1974
+ case "A256GCMKW": {
1285
1975
  if (!options.iv || !options.tag) throw new JWTError("AES-GCMKW requires 'iv' and 'tag' options for unwrapping", "ERR_JWE_INVALID");
1286
- unwrappedCekBytes = await gcmkwDecrypt(alg, importedUnwrappingKey, wrappedKey, typeof options.iv === "string" ? base64UrlDecode(options.iv, { returnAs: "uint8array" }) : options.iv, typeof options.tag === "string" ? base64UrlDecode(options.tag, { returnAs: "uint8array" }) : options.tag);
1976
+ const ivBytes = segmentBytes(options.iv, "iv");
1977
+ const tagBytes = segmentBytes(options.tag, "tag");
1978
+ assertKeyWrapSegmentLength("iv", ivBytes, bitLengthIV(alg) >> 3, alg);
1979
+ assertKeyWrapSegmentLength("tag", tagBytes, bitLengthTag(alg) >> 3, alg);
1980
+ unwrappedCekBytes = await unwrapping(gcmkwDecrypt(alg, importedUnwrappingKey, wrappedKey, ivBytes, tagBytes));
1287
1981
  break;
1982
+ }
1288
1983
  case "RSA-OAEP":
1289
1984
  case "RSA-OAEP-256":
1290
1985
  case "RSA-OAEP-384":
1291
1986
  case "RSA-OAEP-512": {
1292
- if (!(importedUnwrappingKey instanceof CryptoKey)) throw new TypeError("RSA-OAEP requires the unwrapping key to be provided as a CryptoKey");
1293
- unwrappedCekBytes = await decryptRSAES(alg, importedUnwrappingKey, wrappedKey);
1987
+ assertCryptoKeyFor(alg, importedUnwrappingKey, "unwrapping");
1988
+ unwrappedCekBytes = await unwrapping(decryptRSAES(alg, importedUnwrappingKey, wrappedKey));
1294
1989
  if (returnRaw) break;
1295
1990
  const inferredAlgorithm = options.unwrappedKeyAlgorithm || inferAesImportAlgorithm(options.enc, unwrappedCekBytes.length);
1296
1991
  if (!inferredAlgorithm) throw new JWTError("Unable to infer algorithm for RSA-OAEP unwrapped key. Provide \"unwrappedKeyAlgorithm\" in options.", "ERR_JWE_INVALID");
@@ -1302,20 +1997,24 @@ async function unwrapKey(alg, wrappedKey, unwrappingKey, options = {}) {
1302
1997
  case "ECDH-ES+A192KW":
1303
1998
  case "ECDH-ES+A256KW": {
1304
1999
  if (!options.epk) throw new JWTError("ECDH-ES requires 'epk' (Ephemeral Public Key) option", "ERR_JWE_INVALID");
1305
- if (!(importedUnwrappingKey instanceof CryptoKey)) throw new TypeError("ECDH-ES requires the unwrapping key to be a CryptoKey");
1306
- if (!isECDHKeyAllowed(importedUnwrappingKey)) throw new JWTError("ECDH with the provided key is not allowed or not supported", "ERR_JWK_INVALID");
1307
- const epkCandidate = options.epk instanceof CryptoKey ? options.epk : await normalizeKey(options.epk, alg);
1308
- if (!(epkCandidate instanceof CryptoKey)) throw new JWTError("Failed to normalize ECDH ephemeral public key", "ERR_JWK_INVALID");
1309
- const apuBytes = typeof options.apu === "string" ? base64UrlDecode(options.apu, { returnAs: "uint8array" }) : options.apu ?? new Uint8Array(0);
1310
- const apvBytes = typeof options.apv === "string" ? base64UrlDecode(options.apv, { returnAs: "uint8array" }) : options.apv ?? new Uint8Array(0);
2000
+ assertCryptoKeyFor(alg, importedUnwrappingKey, "unwrapping");
2001
+ assertECDHKeyAllowed(importedUnwrappingKey);
2002
+ const epkCandidate = await normalizeEpk(options.epk, {
2003
+ alg,
2004
+ recipientKey: importedUnwrappingKey
2005
+ });
2006
+ const apuBytes = segmentBytes(options.apu ?? /* @__PURE__ */ new Uint8Array(0), "apu");
2007
+ const apvBytes = segmentBytes(options.apv ?? /* @__PURE__ */ new Uint8Array(0), "apv");
2008
+ assertPartyInfoLength("apu", apuBytes);
2009
+ assertPartyInfoLength("apv", apvBytes);
1311
2010
  const infoAlg = alg === "ECDH-ES" ? options.enc : alg;
1312
2011
  if (!infoAlg) throw new JWTError("ECDH-ES requires content encryption algorithm ('enc') to derive the shared secret", "ERR_JWE_INVALID");
1313
- const sharedSecret = await deriveECDHESKey(epkCandidate, importedUnwrappingKey, infoAlg, alg === "ECDH-ES" ? bitLengthCEK(infoAlg) : Number.parseInt(alg.slice(-5, -2), 10), apuBytes, apvBytes);
2012
+ const sharedSecret = await unwrapping(deriveECDHESKey(epkCandidate, importedUnwrappingKey, infoAlg, ecdhDerivedBits(alg, infoAlg), apuBytes, apvBytes));
1314
2013
  if (alg === "ECDH-ES") unwrappedCekBytes = sharedSecret;
1315
2014
  else {
1316
- const kwAlg = alg.slice(-6);
2015
+ const kwAlg = innerKeyWrapAlg(alg);
1317
2016
  if (!(wrappedKey instanceof Uint8Array) || wrappedKey.length === 0) throw new JWTError("ECDH-ES key agreement with key wrapping requires an encrypted key", "ERR_JWE_INVALID");
1318
- unwrappedCekBytes = await aesKwUnwrap(kwAlg, sharedSecret, wrappedKey);
2017
+ unwrappedCekBytes = await unwrapping(aesKwUnwrap(kwAlg, sharedSecret, wrappedKey));
1319
2018
  }
1320
2019
  break;
1321
2020
  }
@@ -1325,6 +2024,8 @@ async function unwrapKey(alg, wrappedKey, unwrappingKey, options = {}) {
1325
2024
  return await crypto.subtle.importKey("raw", unwrappedCekBytes, options.unwrappedKeyAlgorithm || { name: "AES-GCM" }, defaultExtractable, options.keyUsage || ["encrypt", "decrypt"]);
1326
2025
  }
1327
2026
  async function importPEM(pem, alg, options) {
2027
+ if (typeof pem !== "string") throw new JWTError(`"pem" must be a PEM-encoded string, got ${pem === null ? "null" : typeof pem}.`, "ERR_INVALID_OPTION");
2028
+ if (options !== void 0) assertPlainObject(options, "options");
1328
2029
  const extractable = true;
1329
2030
  const pemType = options?.pemType ?? inferPEMType(pem);
1330
2031
  if (!pemType) throw new JWTError("Cannot infer PEM type from the input; pass \"options.pemType\" explicitly.", "ERR_JWK_INVALID");
@@ -1339,30 +2040,28 @@ async function importPEM(pem, alg, options) {
1339
2040
  case "x509":
1340
2041
  cryptoKey = await fromX509(pem, alg, { extractable });
1341
2042
  break;
1342
- default: throw new JWTError(`Unsupported PEM type: ${pemType}`, "ERR_JWK_UNSUPPORTED");
2043
+ default: throw new JWTError(`Unsupported PEM type: ${String(pemType)}`, "ERR_JWK_UNSUPPORTED");
1343
2044
  }
1344
2045
  return {
1345
2046
  ...await exportKey(cryptoKey, options?.jwkParams),
1346
2047
  alg
1347
2048
  };
1348
2049
  }
1349
- async function importFromPEM(pem, pemType, alg, options) {
1350
- return importPEM(pem, alg, {
1351
- pemType,
1352
- ...options
1353
- });
1354
- }
1355
2050
  async function exportPEM(jwk, options) {
2051
+ assertPlainObject(jwk, "jwk");
2052
+ if (options !== void 0) assertPlainObject(options, "options");
1356
2053
  if (jwk.kty === "oct") throw new JWTError("Octet (symmetric) JWKs (kty: 'oct') cannot be exported to PKCS8 or SPKI PEM formats.", "ERR_JWK_UNSUPPORTED");
1357
2054
  const effectiveAlg = jwk.alg || options?.alg;
1358
2055
  if (!effectiveAlg && (jwk.kty === "RSA" || jwk.kty === "EC" || jwk.kty === "OKP")) throw new JWTError("Algorithm (alg) must be provided in the JWK or via options for converting this JWK type to a CryptoKey.", "ERR_JWK_INVALID");
2056
+ if (effectiveAlg !== void 0 && !PEM_ALGORITHMS.has(effectiveAlg)) throw new JWTError(`Unsupported PEM algorithm: ${effectiveAlg}`, "ERR_JWK_UNSUPPORTED");
1359
2057
  const pemFormat = options?.pemFormat ?? ("d" in jwk ? "pkcs8" : "spki");
1360
2058
  const cryptoKeyCandidate = await importKey({
1361
2059
  ...jwk,
1362
2060
  ext: true
1363
2061
  }, {
1364
2062
  alg: effectiveAlg,
1365
- expect: pemFormat === "pkcs8" ? "private" : "public"
2063
+ expect: pemFormat === "pkcs8" ? "private" : "public",
2064
+ extractable: true
1366
2065
  });
1367
2066
  if (!isCryptoKey(cryptoKeyCandidate)) throw new JWTError("Failed to convert JWK to a CryptoKey instance suitable for PEM export.", "ERR_JWK_INVALID");
1368
2067
  const cryptoKey = cryptoKeyCandidate;
@@ -1373,111 +2072,83 @@ async function exportPEM(jwk, options) {
1373
2072
  case "spki":
1374
2073
  if (cryptoKey.type !== "public") throw new JWTError(`Only 'public' type CryptoKeys can be exported to SPKI PEM format. Key type is '${cryptoKey.type}'.`, "ERR_JWK_INVALID");
1375
2074
  return toSPKI(cryptoKey);
1376
- default: throw new JWTError(`Unsupported PEM format: ${pemFormat}`, "ERR_JWK_UNSUPPORTED");
2075
+ default: throw new JWTError(`Unsupported PEM format: ${String(pemFormat)}`, "ERR_JWK_UNSUPPORTED");
1377
2076
  }
1378
2077
  }
1379
- async function exportToPEM(jwk, pemFormat, algForCryptoKeyImport) {
1380
- return exportPEM(jwk, {
1381
- pemFormat,
1382
- alg: algForCryptoKeyImport
1383
- });
1384
- }
1385
2078
  function inferPEMType(pem) {
1386
2079
  if (pem.includes("-----BEGIN PRIVATE KEY-----")) return "pkcs8";
1387
2080
  if (pem.includes("-----BEGIN PUBLIC KEY-----")) return "spki";
1388
2081
  if (pem.includes("-----BEGIN CERTIFICATE-----")) return "x509";
1389
2082
  }
1390
- async function deriveSharedSecret(publicKey, privateKey, alg, options) {
2083
+ async function deriveSharedSecret(publicKey, privateKey, options) {
2084
+ assertPlainObject(options, "options");
2085
+ const { enc: alg, keyLength: requestedKeyLength, partyUInfo, partyVInfo } = options;
2086
+ if (requestedKeyLength !== void 0) assertDerivedKeyLength(requestedKeyLength);
2087
+ const importAlg = alg.startsWith("ECDH-ES") ? alg : "ECDH-ES";
1391
2088
  const pubCryptoKey = isCryptoKey(publicKey) ? publicKey : await importKey(publicKey, {
1392
- alg: "ECDH-ES",
2089
+ alg: importAlg,
1393
2090
  expect: "public"
1394
2091
  });
1395
2092
  const privCryptoKey = isCryptoKey(privateKey) ? privateKey : await importKey(privateKey, {
1396
- alg: "ECDH-ES",
2093
+ alg: importAlg,
1397
2094
  expect: "private"
1398
2095
  });
1399
2096
  let keyLength;
1400
- if (options?.keyLength !== void 0) keyLength = options.keyLength;
1401
- else if (alg === "ECDH-ES") throw new JWTError("deriveSharedSecret with alg \"ECDH-ES\" requires an explicit keyLength in options", "ERR_JWK_INVALID");
2097
+ if (requestedKeyLength !== void 0) keyLength = requestedKeyLength;
2098
+ else if (alg === "ECDH-ES") throw new JWTError("deriveSharedSecret with enc \"ECDH-ES\" requires an explicit keyLength in options", "ERR_JWK_INVALID");
1402
2099
  else if (alg.startsWith("ECDH-ES+")) keyLength = Number.parseInt(alg.slice(-5, -2), 10);
1403
2100
  else keyLength = bitLengthCEK(alg);
1404
- return deriveECDHESKey(pubCryptoKey, privCryptoKey, alg, keyLength, options?.partyUInfo ?? new Uint8Array(0), options?.partyVInfo ?? new Uint8Array(0));
1405
- }
1406
- function getJWKFromSet(jwkSet, kidOrProtectedHeader) {
1407
- if (!jwkSet || !isJWKSet(jwkSet)) throw new JWTError("Invalid JWK Set provided", "ERR_JWK_INVALID");
1408
- if (typeof kidOrProtectedHeader === "string") {
1409
- const kid = kidOrProtectedHeader;
1410
- const selectedKey = jwkSet.keys.find((k) => k.kid === kid);
1411
- if (!selectedKey) throw new JWTError(`No key found in JWK Set with kid "${kid}".`, "ERR_JWK_KEY_NOT_FOUND");
1412
- return selectedKey;
1413
- } else if (typeof kidOrProtectedHeader === "object") {
1414
- const { kid, alg, kty } = kidOrProtectedHeader;
1415
- if (!kid) {
1416
- if (jwkSet.keys.length === 1) return jwkSet.keys[0];
1417
- throw new JWTError("JWS Protected Header is missing 'kid' (Key ID) and the JWK Set contains multiple keys. Add a 'kid' parameter to the token header and to the matching JWK to enable automatic selection.", "ERR_JWK_KEY_NOT_FOUND");
1418
- }
1419
- const selectedKey = jwkSet.keys.find((k) => {
1420
- return k.kid === kid && (!alg || k.alg === alg) && (!kty || k.kty === kty);
1421
- });
1422
- if (!selectedKey) {
1423
- let errorMessage = `No key found in JWK Set with kid "${kid}"`;
1424
- if (alg) errorMessage += ` and alg "${alg}"`;
1425
- if (kty) errorMessage += ` and kty "${kty}"`;
1426
- errorMessage += ".";
1427
- throw new JWTError(errorMessage, "ERR_JWK_KEY_NOT_FOUND");
1428
- }
1429
- return selectedKey;
1430
- }
1431
- throw new TypeError("`kidOrProtectedHeader` must be a string (kid) or an object (JOSE Protected Header).");
2101
+ return deriveECDHESKey(pubCryptoKey, privCryptoKey, alg, keyLength, partyUInfo ?? /* @__PURE__ */ new Uint8Array(0), partyVInfo ?? /* @__PURE__ */ new Uint8Array(0));
1432
2102
  }
1433
2103
  function getJWKsFromSet(jwkSet, filter) {
1434
2104
  if (!jwkSet || !isJWKSet(jwkSet)) throw new JWTError("Invalid JWK Set provided", "ERR_JWK_INVALID");
1435
- if (!filter) return [...jwkSet.keys];
1436
- return jwkSet.keys.filter(filter);
2105
+ const keys = jwkSet.keys.filter((key) => isJWK(key));
2106
+ return filter ? keys.filter(filter) : keys;
1437
2107
  }
1438
2108
  function getGenerateKeyParams(alg, options) {
1439
2109
  let algorithm;
1440
2110
  let keyUsages;
1441
- const defaultKeyUsage = options?.keyUsage;
2111
+ const requested = options?.keyUsage;
2112
+ const usage = (allowed, fallback) => resolveKeyUsage(requested, {
2113
+ allowed,
2114
+ fallback,
2115
+ alg
2116
+ });
2117
+ const pairUsage = (allowed, fallback) => assertPairUsages(usage(allowed, fallback), {
2118
+ fallback,
2119
+ alg
2120
+ });
1442
2121
  switch (alg) {
1443
2122
  case "HS256":
1444
2123
  case "HS384":
1445
2124
  case "HS512":
1446
2125
  algorithm = {
1447
2126
  name: "HMAC",
1448
- hash: `SHA-${alg.slice(2)}`
2127
+ hash: jwsHashOf(alg)
1449
2128
  };
1450
- keyUsages = defaultKeyUsage ?? ["sign", "verify"];
2129
+ keyUsages = usage(SIGNATURE_USAGES, ["sign", "verify"]);
1451
2130
  break;
1452
2131
  case "RS256":
1453
2132
  case "RS384":
1454
2133
  case "RS512":
1455
2134
  algorithm = {
1456
2135
  name: "RSASSA-PKCS1-v1_5",
1457
- modulusLength: options?.modulusLength ?? 2048,
1458
- publicExponent: options?.publicExponent ?? new Uint8Array([
1459
- 1,
1460
- 0,
1461
- 1
1462
- ]),
1463
- hash: `SHA-${alg.slice(2)}`
2136
+ modulusLength: assertModulusLength(options?.modulusLength),
2137
+ publicExponent: assertPublicExponent(options?.publicExponent),
2138
+ hash: jwsHashOf(alg)
1464
2139
  };
1465
- keyUsages = defaultKeyUsage ?? ["sign", "verify"];
2140
+ keyUsages = pairUsage(SIGNATURE_USAGES, ["sign", "verify"]);
1466
2141
  break;
1467
2142
  case "PS256":
1468
2143
  case "PS384":
1469
2144
  case "PS512":
1470
2145
  algorithm = {
1471
2146
  name: "RSA-PSS",
1472
- modulusLength: options?.modulusLength ?? 2048,
1473
- publicExponent: options?.publicExponent ?? new Uint8Array([
1474
- 1,
1475
- 0,
1476
- 1
1477
- ]),
1478
- hash: `SHA-${alg.slice(2)}`
2147
+ modulusLength: assertModulusLength(options?.modulusLength),
2148
+ publicExponent: assertPublicExponent(options?.publicExponent),
2149
+ hash: jwsHashOf(alg)
1479
2150
  };
1480
- keyUsages = defaultKeyUsage ?? ["sign", "verify"];
2151
+ keyUsages = pairUsage(SIGNATURE_USAGES, ["sign", "verify"]);
1481
2152
  break;
1482
2153
  case "RSA-OAEP":
1483
2154
  case "RSA-OAEP-256":
@@ -1485,74 +2156,67 @@ function getGenerateKeyParams(alg, options) {
1485
2156
  case "RSA-OAEP-512":
1486
2157
  algorithm = {
1487
2158
  name: "RSA-OAEP",
1488
- modulusLength: options?.modulusLength ?? 2048,
1489
- publicExponent: options?.publicExponent ?? new Uint8Array([
1490
- 1,
1491
- 0,
1492
- 1
1493
- ]),
1494
- hash: `SHA-${Number.parseInt(alg.slice(9), 10) || 1}`
2159
+ modulusLength: assertModulusLength(options?.modulusLength),
2160
+ publicExponent: assertPublicExponent(options?.publicExponent),
2161
+ hash: rsaOaepHashOf(alg)
1495
2162
  };
1496
- keyUsages = defaultKeyUsage ?? [
2163
+ keyUsages = pairUsage(KEY_ENCRYPTION_USAGES, [
1497
2164
  "encrypt",
1498
2165
  "decrypt",
1499
2166
  "wrapKey",
1500
2167
  "unwrapKey"
1501
- ];
2168
+ ]);
1502
2169
  break;
1503
2170
  case "A128KW":
1504
2171
  case "A192KW":
1505
2172
  case "A256KW":
1506
2173
  algorithm = {
1507
2174
  name: "AES-KW",
1508
- length: Number.parseInt(alg.slice(1, 4), 10)
2175
+ length: aesBitsOf(alg)
1509
2176
  };
1510
- keyUsages = defaultKeyUsage ?? ["wrapKey", "unwrapKey"];
2177
+ keyUsages = usage(KEY_WRAPPING_USAGES, ["wrapKey", "unwrapKey"]);
1511
2178
  break;
1512
2179
  case "A128GCM":
1513
2180
  case "A192GCM":
1514
2181
  case "A256GCM":
1515
2182
  case "A128GCMKW":
1516
2183
  case "A192GCMKW":
1517
- case "A256GCMKW": {
1518
- const baseAlg = alg.replace("KW", "");
2184
+ case "A256GCMKW":
1519
2185
  algorithm = {
1520
2186
  name: "AES-GCM",
1521
- length: Number.parseInt(baseAlg.slice(1, 4), 10)
2187
+ length: aesBitsOf(alg)
1522
2188
  };
1523
- keyUsages = defaultKeyUsage ?? (alg.endsWith("KW") ? ["wrapKey", "unwrapKey"] : ["encrypt", "decrypt"]);
2189
+ keyUsages = usage(KEY_ENCRYPTION_USAGES, ["encrypt", "decrypt"]);
1524
2190
  break;
1525
- }
1526
2191
  case "ES256":
1527
2192
  case "ES384":
1528
- case "ES512":
2193
+ case "ES512": {
2194
+ const namedCurve = ECDSA_CURVES[alg];
2195
+ assertNamedCurve(options?.namedCurve, namedCurve, alg);
1529
2196
  algorithm = {
1530
2197
  name: "ECDSA",
1531
- namedCurve: `P-${alg.slice(2)}`
2198
+ namedCurve
1532
2199
  };
1533
- keyUsages = defaultKeyUsage ?? ["sign", "verify"];
2200
+ keyUsages = pairUsage(SIGNATURE_USAGES, ["sign", "verify"]);
1534
2201
  break;
2202
+ }
1535
2203
  case "Ed25519":
1536
- keyUsages = defaultKeyUsage ?? ["sign", "verify"];
2204
+ assertNamedCurve(options?.namedCurve, "Ed25519", alg);
2205
+ keyUsages = pairUsage(SIGNATURE_USAGES, ["sign", "verify"]);
1537
2206
  algorithm = { name: "Ed25519" };
1538
2207
  break;
1539
2208
  case "EdDSA": {
1540
- keyUsages = defaultKeyUsage ?? ["sign", "verify"];
2209
+ keyUsages = pairUsage(SIGNATURE_USAGES, ["sign", "verify"]);
1541
2210
  const namedCurve = options?.namedCurve ?? "Ed25519";
1542
- switch (namedCurve) {
1543
- case "Ed25519":
1544
- case "Ed448":
1545
- algorithm = { name: namedCurve };
1546
- break;
1547
- default: throw new JWTError("Unsupported namedCurve provided. Supported values are: Ed25519 and Ed448", "ERR_JWK_UNSUPPORTED");
1548
- }
2211
+ if (namedCurve !== "Ed25519") throw new JWTError("Unsupported namedCurve provided. Supported values are: Ed25519", "ERR_JWK_UNSUPPORTED");
2212
+ algorithm = { name: namedCurve };
1549
2213
  break;
1550
2214
  }
1551
2215
  case "ECDH-ES":
1552
2216
  case "ECDH-ES+A128KW":
1553
2217
  case "ECDH-ES+A192KW":
1554
2218
  case "ECDH-ES+A256KW": {
1555
- keyUsages = ["deriveBits"];
2219
+ keyUsages = pairUsage(DERIVATION_USAGES, ["deriveBits"]);
1556
2220
  const namedCurve = options?.namedCurve ?? "P-256";
1557
2221
  switch (namedCurve) {
1558
2222
  case "P-256":
@@ -1577,58 +2241,12 @@ function getGenerateKeyParams(alg, options) {
1577
2241
  keyUsages
1578
2242
  };
1579
2243
  }
1580
- async function resolveECDHEphemeralPair(recipientPublicKey, ephemeralKeyInput) {
1581
- if (!ephemeralKeyInput) {
1582
- const generated = await crypto.subtle.generateKey(recipientPublicKey.algorithm, true, ["deriveBits"]);
1583
- const rawJwk = await keyToJWK(generated.publicKey);
1584
- return {
1585
- ephemeralPrivateKey: generated.privateKey,
1586
- epkJwk: stripPrivateJwkFields(rawJwk)
1587
- };
1588
- }
1589
- if (isCryptoKeyPair(ephemeralKeyInput)) {
1590
- const rawJwk = await keyToJWK(ephemeralKeyInput.publicKey);
1591
- return {
1592
- ephemeralPrivateKey: ephemeralKeyInput.privateKey,
1593
- epkJwk: stripPrivateJwkFields(rawJwk)
1594
- };
1595
- }
1596
- if (typeof ephemeralKeyInput === "object" && "publicKey" in ephemeralKeyInput && "privateKey" in ephemeralKeyInput) {
1597
- const { publicKey, privateKey } = ephemeralKeyInput;
1598
- return {
1599
- ephemeralPrivateKey: isCryptoKey(privateKey) ? privateKey : await importKey(privateKey, {
1600
- alg: "ECDH-ES",
1601
- expect: "private"
1602
- }),
1603
- epkJwk: isCryptoKey(publicKey) ? stripPrivateJwkFields(await keyToJWK(publicKey)) : stripPrivateJwkFields(publicKey)
1604
- };
1605
- }
1606
- if (isCryptoKey(ephemeralKeyInput)) {
1607
- if (ephemeralKeyInput.type !== "private") throw new JWTError("ECDH-ES ephemeral CryptoKey must be a private key", "ERR_JWK_INVALID");
1608
- return {
1609
- ephemeralPrivateKey: ephemeralKeyInput,
1610
- epkJwk: stripPrivateJwkFields(await keyToJWK(ephemeralKeyInput))
1611
- };
1612
- }
1613
- if (isJWK(ephemeralKeyInput) && "d" in ephemeralKeyInput) return {
1614
- ephemeralPrivateKey: await importKey(ephemeralKeyInput, {
1615
- alg: "ECDH-ES",
1616
- expect: "private"
1617
- }),
1618
- epkJwk: stripPrivateJwkFields(ephemeralKeyInput)
1619
- };
1620
- throw new JWTError("Unsupported ECDH-ES ephemeral key material", "ERR_JWK_INVALID");
1621
- }
1622
- function stripPrivateJwkFields(jwk) {
1623
- const { d: _d, ...pub } = jwk;
1624
- return pub;
1625
- }
1626
2244
  function inferAesImportAlgorithm(enc, cekLengthBytes) {
1627
2245
  const bitLength = cekLengthBytes << 3;
1628
2246
  if (enc) {
1629
2247
  if (enc.includes("GCM")) return {
1630
2248
  name: "AES-GCM",
1631
- length: Number.parseInt(enc.slice(1, 4), 10)
2249
+ length: aesBitsOf(enc)
1632
2250
  };
1633
2251
  if (enc.includes("CBC-HS")) return;
1634
2252
  }
@@ -1637,4 +2255,154 @@ function inferAesImportAlgorithm(enc, cekLengthBytes) {
1637
2255
  length: bitLength
1638
2256
  };
1639
2257
  }
1640
- export { WeakMapJWKCache, assertOctKeyLength, clearJWKCache, configureJWKCache, decrypt, deriveJWKFromPassword, deriveKeyFromPassword, deriveSharedSecret, encrypt, encryptKey, exportKey, exportPEM, exportToPEM, generateCEK, generateIV, generateJWK, generateKey, getJWKFromSet, getJWKsFromSet, importFromPEM, importKey, importPEM, sign, unwrapKey, verify, wrapKey };
2258
+ const RESERVED_JWK_PARAMS = /* @__PURE__ */ new Set([
2259
+ "kty",
2260
+ "alg",
2261
+ "key_ops",
2262
+ "ext",
2263
+ "k",
2264
+ "d",
2265
+ "n",
2266
+ "e",
2267
+ "p",
2268
+ "q",
2269
+ "dp",
2270
+ "dq",
2271
+ "qi",
2272
+ "oth",
2273
+ "x",
2274
+ "y",
2275
+ "crv"
2276
+ ]);
2277
+ function assertNoReservedJWKParams(jwkParams) {
2278
+ const reserved = Object.keys(jwkParams).filter((name) => RESERVED_JWK_PARAMS.has(name));
2279
+ if (reserved.length > 0) throw new JWTError(`jwkParams must not set reserved JWK members: ${reserved.join(", ")}`, "ERR_INVALID_OPTION");
2280
+ }
2281
+ function assertNamedCurve(requested, expected, alg) {
2282
+ if (requested === void 0 || requested === expected) return;
2283
+ throw new JWTError(`"namedCurve" ${requested} contradicts ${alg}, which is defined over ${expected}.`, "ERR_INVALID_OPTION");
2284
+ }
2285
+ function assertPublicExponent(publicExponent) {
2286
+ if (publicExponent === void 0) return new Uint8Array([
2287
+ 1,
2288
+ 0,
2289
+ 1
2290
+ ]);
2291
+ if (!(publicExponent instanceof Uint8Array) || publicExponent.length === 0) throw new JWTError("\"publicExponent\" must be the exponent's big-endian bytes as a Uint8Array.", "ERR_INVALID_OPTION");
2292
+ return publicExponent;
2293
+ }
2294
+ const SIGNATURE_USAGES = ["sign", "verify"];
2295
+ const KEY_WRAPPING_USAGES = ["wrapKey", "unwrapKey"];
2296
+ const KEY_ENCRYPTION_USAGES = [
2297
+ "encrypt",
2298
+ "decrypt",
2299
+ "wrapKey",
2300
+ "unwrapKey"
2301
+ ];
2302
+ const DERIVATION_USAGES = ["deriveBits", "deriveKey"];
2303
+ const CONTENT_ENCRYPTION_USAGES = ["encrypt", "decrypt"];
2304
+ function resolveKeyUsage(requested, options) {
2305
+ const { allowed, fallback, alg } = options;
2306
+ if (requested === void 0) return fallback;
2307
+ if (!Array.isArray(requested) || requested.length === 0) throw new JWTError("\"keyUsage\" must be a non-empty array.", "ERR_INVALID_OPTION");
2308
+ const rejected = requested.filter((entry) => !allowed.includes(entry));
2309
+ if (rejected.length > 0) throw new JWTError(`"keyUsage" ${rejected.join(", ")} cannot be served by ${alg}; it admits ${allowed.join(", ")}.`, "ERR_INVALID_OPTION");
2310
+ return requested;
2311
+ }
2312
+ const PRIVATE_KEY_USAGES = [
2313
+ "sign",
2314
+ "decrypt",
2315
+ "unwrapKey",
2316
+ "deriveBits",
2317
+ "deriveKey"
2318
+ ];
2319
+ const PUBLIC_KEY_USAGES = [
2320
+ "verify",
2321
+ "encrypt",
2322
+ "wrapKey"
2323
+ ];
2324
+ function assertPairUsages(usages, options) {
2325
+ const { fallback, alg } = options;
2326
+ for (const [half, side] of [[PRIVATE_KEY_USAGES, "private"], [PUBLIC_KEY_USAGES, "public"]]) {
2327
+ const wanted = fallback.filter((entry) => half.includes(entry));
2328
+ if (wanted.length === 0 || usages.some((entry) => half.includes(entry))) continue;
2329
+ throw new JWTError(`"keyUsage" leaves the ${side} half of a ${alg} key pair with no usage; include one of ${wanted.join(", ")}.`, "ERR_INVALID_OPTION");
2330
+ }
2331
+ return usages;
2332
+ }
2333
+ function assertKidOption(kid) {
2334
+ if (kid === void 0 || kid === false || typeof kid === "string") return kid;
2335
+ throw new JWTError("\"kid\" must be a string or false.", "ERR_INVALID_OPTION");
2336
+ }
2337
+ async function withGeneratedKid(kid, jwk) {
2338
+ if (kid === false) return jwk;
2339
+ return {
2340
+ ...jwk,
2341
+ kid: kid ?? await thumbprint(jwk)
2342
+ };
2343
+ }
2344
+ const PEM_ALGORITHMS = /* @__PURE__ */ new Set(Object.keys({
2345
+ "PS256": true,
2346
+ "PS384": true,
2347
+ "PS512": true,
2348
+ "RS256": true,
2349
+ "RS384": true,
2350
+ "RS512": true,
2351
+ "RSA-OAEP": true,
2352
+ "RSA-OAEP-256": true,
2353
+ "RSA-OAEP-384": true,
2354
+ "RSA-OAEP-512": true,
2355
+ "ES256": true,
2356
+ "ES384": true,
2357
+ "ES512": true,
2358
+ "ECDH-ES": true,
2359
+ "ECDH-ES+A128KW": true,
2360
+ "ECDH-ES+A192KW": true,
2361
+ "ECDH-ES+A256KW": true,
2362
+ "Ed25519": true,
2363
+ "EdDSA": true
2364
+ }));
2365
+ function assertWrappableCEK(cek, alg) {
2366
+ if (cek.length >= 16 && cek.length % 8 === 0) return;
2367
+ throw new JWTError(`${alg} wraps a key of 16 or more bytes in whole 8-byte blocks (got ${cek.length}).`, "ERR_INVALID_OPTION");
2368
+ }
2369
+ async function unwrapping(operation) {
2370
+ try {
2371
+ return await operation;
2372
+ } catch (error) {
2373
+ throw asDecryptionError(error);
2374
+ }
2375
+ }
2376
+ function assertPBES2Algorithm(alg) {
2377
+ if (typeof alg === "string" && PBES2_ALGORITHMS.includes(alg)) return;
2378
+ throw new JWTError(`Password derivation is defined for ${PBES2_ALGORITHMS.join(", ")}, not ${String(alg)}.`, "ERR_JWK_UNSUPPORTED");
2379
+ }
2380
+ function assertKeyBytesArg(value, name) {
2381
+ if (value instanceof Uint8Array || isCryptoKey(value)) return;
2382
+ throw new JWTError(`"${name}" must be a Uint8Array or a CryptoKey, got ${value === null ? "null" : typeof value}.`, "ERR_INVALID_OPTION");
2383
+ }
2384
+ function assertModulusLength(modulusLength) {
2385
+ const length = modulusLength ?? 2048;
2386
+ if (!Number.isInteger(length) || length < 2048) throw new JWTError("modulusLength must be at least 2048 bits (RFC 7518 §3.3)", "ERR_INVALID_OPTION");
2387
+ return length;
2388
+ }
2389
+ function assertPartyInfoLength(name, bytes) {
2390
+ if (bytes.length > 1024) throw new JWTError(`Invalid JWE: "${name}" must not exceed ${MAX_PARTY_INFO_BYTES} bytes (got ${bytes.length}).`, "ERR_JWE_INVALID");
2391
+ }
2392
+ function assertKeyWrapSegmentLength(name, bytes, expected, alg) {
2393
+ if (bytes.length !== expected) throw new JWTError(`Invalid JWE: "${name}" must be ${expected} bytes for ${alg} (got ${bytes.length}).`, "ERR_JWE_INVALID");
2394
+ }
2395
+ function assertDerivedKeyLength(keyLength) {
2396
+ if (!Number.isInteger(keyLength) || keyLength <= 0 || keyLength % 8 !== 0 || keyLength > 8192) throw new JWTError(`keyLength must be a positive multiple of 8 no greater than 8192 bits, got ${keyLength}`, "ERR_INVALID_OPTION");
2397
+ }
2398
+ function assertCryptoKeyFor(alg, key, role) {
2399
+ if (isCryptoKey(key)) return;
2400
+ throw new JWTError(`${alg.startsWith("RSA") ? "RSA-OAEP" : "ECDH-ES"} requires the ${role} key to be a CryptoKey`, "ERR_JWK_INVALID");
2401
+ }
2402
+ function segmentBytes(value, name) {
2403
+ return typeof value === "string" ? decodeSegment(value, {
2404
+ family: "JWE",
2405
+ what: `"${name}"`
2406
+ }) : value;
2407
+ }
2408
+ export { DEFAULT_JOSE_LIMITS, DEFAULT_PBES2_ITERATIONS, JWE_ALG_CTX, JWE_DIRECT_ALGS, JWS_ALG_CTX, WeakMapJWKCache, applyB64Header, asDecryptionError, asJWTError, asKeyLookupError, asKeyUsageError, assertB64Option, assertCompactToken, assertConsumerOptions, assertDirectKeyRole, assertEntryLimit, assertJWEAlgSupported, assertJWEEncSupported, assertJWKSetCandidates, assertNoZipOption, assertNotStringKey, assertOptionEntry, assertPBES2Params, assertProducerCEK, assertProducerCrit, assertProducerIV, assertProtectedOnlyOption, assertSerializationObject, buildECDHAgreementParams, buildJWKSetFilter, buildUnwrapKeyOptions, checkAlgAllowed, checkJWEAlgSupported, checkJWEContentSegments, checkJWEDirectEncryptedKey, checkJWEEncAllowed, checkJWEEncSupported, checkJWEUnprotectedCrit, checkJWEZip, checkJWSAlgSupported, checkJWSB64, checkProtectedTyp, checkSerializationEntry, clearJWKCache, configureJWKCache, createPBES2Budget, decodeJWEPayload, decodeJWSPayload, decodeProtectedHeader, decodeSegment, decrypt, deriveJWKFromPassword, deriveKeyFromPassword, deriveSharedSecret, encrypt, encryptKey, exportKey, exportPEM, exportReturnedCek, generateCEK, generateIV, generateJWK, generateKey, getJWKsFromSet, importKey, importPEM, isJWEAlgSupported, keyMatchesHeader, quoteTokenValue, resolveKeyInput, resolveLimit, resolvePasswordKey, resolvePayloadMode, resolveSigningKey, serializeProtectedHeader, sign, stringKeyError, thumbprint, unwrapKey, validateClaimsIfJson, verify, wrapKey };