unjwt 0.8.4 → 0.8.5

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 (53) hide show
  1. package/README.md +3 -9
  2. package/dist/_chunks/{_import-key.mjs → algorithms.mjs} +194 -399
  3. package/dist/_chunks/{_codec-jwe.d.mts → codec-jwe.d.mts} +40 -9
  4. package/dist/_chunks/{_codec-jws.mjs → codec-jws.mjs} +133 -80
  5. package/dist/_chunks/cookie.mjs +50 -0
  6. package/dist/_chunks/digest.mjs +10 -3
  7. package/dist/_chunks/error.d.mts +103 -0
  8. package/dist/_chunks/export.mjs +97 -0
  9. package/dist/_chunks/index.d.mts +5 -103
  10. package/dist/_chunks/index2.d.mts +206 -12
  11. package/dist/_chunks/index3.d.mts +12 -109
  12. package/dist/_chunks/{jwe.d.mts → index4.d.mts} +2 -1
  13. package/dist/_chunks/{jws.d.mts → index5.d.mts} +2 -1
  14. package/dist/_chunks/index6.d.mts +113 -0
  15. package/dist/_chunks/jwe.mjs +205 -72
  16. package/dist/{core → _chunks}/jwk.mjs +210 -495
  17. package/dist/_chunks/jws.mjs +280 -193
  18. package/dist/_chunks/jwt.d.mts +2 -1
  19. package/dist/_chunks/{_jwt-internal.mjs → jwt.mjs} +110 -54
  20. package/dist/_chunks/libs/unsecure.d.mts +35 -25
  21. package/dist/_chunks/libs/unsecure.mjs +101 -268
  22. package/dist/_chunks/{_internal.d.mts → limits.d.mts} +1 -1
  23. package/dist/_chunks/payload.mjs +23 -0
  24. package/dist/_chunks/wrap.mjs +209 -0
  25. package/dist/adapters/elysia/index.d.mts +4 -4
  26. package/dist/adapters/elysia/index.mjs +4 -3
  27. package/dist/adapters/h3/index.d.mts +13 -13
  28. package/dist/adapters/h3/index.mjs +8 -11
  29. package/dist/adapters/h3v1/index.d.mts +5 -5
  30. package/dist/adapters/h3v1/index.mjs +6 -9
  31. package/dist/core/internal.mjs +1 -1
  32. package/dist/core/{jwe.d.mts → jwe/index.d.mts} +5 -4
  33. package/dist/core/jwe/index.mjs +5 -0
  34. package/dist/core/{jwk.d.mts → jwk/index.d.mts} +5 -4
  35. package/dist/core/jwk/index.mjs +7 -0
  36. package/dist/core/{jws.d.mts → jws/index.d.mts} +5 -4
  37. package/dist/core/jws/index.mjs +5 -0
  38. package/dist/dpop/index.d.mts +73 -0
  39. package/dist/dpop/index.mjs +296 -0
  40. package/dist/error.d.mts +3 -0
  41. package/dist/error.mjs +20 -0
  42. package/dist/index.d.mts +10 -9
  43. package/dist/index.mjs +7 -4
  44. package/dist/session/index.d.mts +4 -4
  45. package/dist/session/index.mjs +6 -47
  46. package/dist/utils/index.d.mts +7 -0
  47. package/dist/{core/utils → utils}/index.mjs +4 -3
  48. package/package.json +21 -10
  49. package/dist/_chunks/jwk.d.mts +0 -205
  50. package/dist/core/jwe.mjs +0 -5
  51. package/dist/core/jws.mjs +0 -5
  52. package/dist/core/utils/index.d.mts +0 -6
  53. /package/dist/_chunks/{_cookie-attributes.d.mts → cookie-attributes.d.mts} +0 -0
@@ -1,10 +1,115 @@
1
- import { safeJsonParse, textEncoder } from "./libs/unsecure.mjs";
2
- import { JWTError, assertClaimValidationOptions, assertCritShape, assertCryptoKey, assertPlainObject, assertStringList, base64Parse, base64Stringify, base64UrlParse, base64UrlStringify, concatUint8Arrays, isCryptoKey, isCryptoKeyPair, isJWK, isJWKSet, isPlainObject, isPublicJWK, parsePayloadBytes, parsePayloadSegment, uint32be, validateJwtClaims } from "./_jwt-internal.mjs";
3
- import { ECDSA_CURVES, aesBitsOf, checkKeyUsage, cryptoKeyCurve, digestUrl, hashBitsOf, inferJWEAllowedAlgorithms, inferJWSAllowedAlgorithms, innerKeyWrapAlg, isAlgorithm, isContentEncryptionAlgorithm, isECDHESAlgorithm, isEd25519Signature, isJWSAlgorithm, isKeyManagementAlgorithm, isPBES2Algorithm, jwsHashOf, lengthOf, modulusLengthOf, namedCurveOf, pbes2HashOf, rsaOaepHashOf, shaBitsOf, unusableKey } from "./digest.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);
1
+ import { safeJsonParse, sanitizeObjectCopy, textEncoder } from "./libs/unsecure.mjs";
2
+ import { JWTError } from "../error.mjs";
3
+ import { assertClaimValidationOptions, assertCritShape, assertCryptoKey, assertPlainObject, assertStringList, base64Parse, base64Stringify, base64UrlParse, base64UrlStringify, concatUint8Arrays, hasSymmetricSecret, isCryptoKey, isCryptoKeyPair, isJWK, isJWKSet, isPlainObject, isPublicJWK, quoteTokenValue, uint32be } from "./jwt.mjs";
4
+ import { ECDSA_CURVES, aesBitsOf, checkKeyUsage, cryptoKeyCurve, digestUrl, hashBitsOf, inferJWSAllowedAlgorithms, innerKeyWrapAlg, isAlgorithm, isContentEncryptionAlgorithm, isECDHESAlgorithm, isPBES2Algorithm, isSameAlgorithm, jwkAlgServes, jwsHashOf, lengthOf, modulusLengthOf, namedCurveOf, pbes2HashOf, rsaOaepHashOf, shaBitsOf, unusableKey } from "./digest.mjs";
5
+ function serializeProtectedHeader(header) {
6
+ try {
7
+ return JSON.stringify(header);
8
+ } catch (error) {
9
+ throw new JWTError("The protected header is not JSON-serializable.", "ERR_INVALID_OPTION", error);
10
+ }
11
+ }
12
+ function assertProducerCrit(header, family) {
13
+ const crit = header.crit;
14
+ if (crit === void 0) return;
15
+ assertCritShape(crit, {
16
+ family,
17
+ code: "ERR_INVALID_OPTION"
18
+ });
19
+ for (const param of crit) {
20
+ if (Object.hasOwn(header, param)) continue;
21
+ throw new JWTError(`"crit" lists "${param}", which the protected header does not carry.`, "ERR_INVALID_OPTION");
22
+ }
23
+ }
24
+ const PROTECTED_ONLY_PARAMS = {
25
+ JWS: ["crit", "b64"],
26
+ JWE: ["crit"]
27
+ };
28
+ function assertProtectedOnlyOption(header, options) {
29
+ if (!header) return;
30
+ const { tier, family } = options;
31
+ for (const param of PROTECTED_ONLY_PARAMS[family]) {
32
+ if (!Object.hasOwn(header, param)) continue;
33
+ throw new JWTError(`${family} "${param}" must be in the protected header, not the ${tier} header.`, "ERR_INVALID_OPTION");
34
+ }
35
+ }
36
+ function assertProducerKeyHeaders(header, options) {
37
+ if (!header) return;
38
+ const { tier, family } = options;
39
+ if (Object.hasOwn(header, "jwk") && !isPublicJWK(Reflect.get(header, "jwk"))) throw new JWTError(`${family} "jwk" in the ${tier} header must be a public JWK.`, "ERR_INVALID_OPTION");
40
+ if (Object.hasOwn(header, "epk")) throw new JWTError(`${family} "epk" is not a header option, use "ecdh.ephemeralKey".`, "ERR_INVALID_OPTION");
41
+ }
42
+ function assertProducerConfirmation(payload) {
43
+ if (typeof payload !== "object" || payload === null) return;
44
+ const cnf = Reflect.get(payload, "cnf");
45
+ if (typeof cnf !== "object" || cnf === null || !Object.hasOwn(cnf, "jwk")) return;
46
+ if (!isPublicJWK(Reflect.get(cnf, "jwk"))) throw new JWTError("Invalid JWT \"cnf\": \"jwk\" must be a public JWK.", "ERR_JWT_CLAIM_INVALID");
47
+ }
48
+ function assertOptionEntry(entry, options) {
49
+ const { label, objects } = options;
50
+ assertPlainObject(entry, label);
51
+ for (const member of objects) if (entry[member] !== void 0) assertPlainObject(entry[member], `${label}.${member}`);
52
+ }
53
+ function assertConsumerOptions(options) {
54
+ assertOptionEntry(options, {
55
+ label: "options",
56
+ objects: ["limits"]
57
+ });
58
+ const typ = options.typ;
59
+ if (typ !== void 0 && (typeof typ !== "string" || typ === "")) throw new JWTError("\"typ\" must be a non-empty string.", "ERR_INVALID_OPTION");
60
+ assertStringList(options.algorithms, "algorithms");
61
+ assertStringList(options.encryptionAlgorithms, "encryptionAlgorithms");
62
+ assertStringList(options.recognizedHeaders, "recognizedHeaders");
63
+ assertClaimValidationOptions(options);
64
+ }
65
+ function assertCompactToken(token, family) {
66
+ if (typeof token !== "string") throw new JWTError(`Invalid ${family}: token must be a string.`, `ERR_${family}_INVALID`);
67
+ }
68
+ function assertSerializationObject(value, family) {
69
+ if (!isPlainObject(value)) throw new JWTError(`Invalid ${family} JSON Serialization: expected an object.`, `ERR_${family}_INVALID_SERIALIZATION`);
70
+ }
71
+ function checkSerializationEntry(entry, options) {
72
+ const { family, label, objects, strings } = options;
73
+ const code = `ERR_${family}_INVALID`;
74
+ if (!isPlainObject(entry)) return new JWTError(`Invalid ${family}: ${label} must be a JSON object.`, code);
75
+ 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);
76
+ 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);
77
+ }
78
+ function typMatches(expected, actual) {
79
+ if (typeof actual !== "string") return false;
80
+ return normalizeTyp(expected) === normalizeTyp(actual);
81
+ }
82
+ function checkProtectedTyp(expected, protectedHeader, options) {
83
+ if (expected === void 0) return void 0;
84
+ const actual = protectedHeader.typ;
85
+ if (typMatches(expected, actual)) return void 0;
86
+ const { family, label } = options;
87
+ const where = label ? ` on ${label}` : "";
88
+ const message = actual === void 0 ? `Invalid ${family}: the protected header${where} carries no "typ", expected "${expected}".` : `Invalid ${family}: "typ" mismatch${where}, expected "${expected}".`;
89
+ return new JWTError(message, `ERR_${family}_INVALID`);
90
+ }
91
+ function normalizeTyp(typ) {
92
+ const lowered = typ.toLowerCase();
93
+ return lowered.includes("/") ? lowered : `application/${lowered}`;
94
+ }
95
+ function decodeProtectedHeader(encoded, family) {
96
+ let parsed = {};
97
+ if (encoded) {
98
+ try {
99
+ parsed = safeJsonParse(base64UrlParse(encoded));
100
+ } catch (error) {
101
+ throw new JWTError(`Invalid ${family}: Protected header could not be decoded.`, `ERR_${family}_INVALID`, error);
102
+ }
103
+ if (!isPlainObject(parsed)) throw new JWTError(`Invalid ${family}: Protected header must be a JSON object.`, `ERR_${family}_INVALID`);
104
+ }
105
+ return parsed;
106
+ }
107
+ function decodeSegment(encoded, options) {
108
+ try {
109
+ return base64UrlParse(encoded, { returnAs: "uint8array" });
110
+ } catch (error) {
111
+ throw new JWTError(`Invalid ${options.family}: ${options.what} could not be decoded.`, `ERR_${options.family}_INVALID`, error);
112
+ }
8
113
  }
9
114
  const HASHED_SIGNATURE_ALGORITHMS = /* @__PURE__ */ Object.freeze({
10
115
  HS256: "HMAC",
@@ -1160,91 +1265,33 @@ function assertJWKSetCandidates(candidates, options) {
1160
1265
  }
1161
1266
  assertCandidateLimit(candidates.length, options.limit);
1162
1267
  }
1163
- function createPBES2Budget(limit) {
1164
- let remaining = limit;
1165
- return { spend(attempt) {
1166
- const { alg, p2c } = attempt;
1167
- if (!alg.startsWith("PBES2")) return;
1168
- if (typeof p2c !== "number" || !(p2c > 0)) return;
1169
- assertPBES2Iterations(p2c, attempt);
1170
- if (p2c > remaining) throw new JWTError(`PBES2 iteration budget of ${limit} exhausted.`, "ERR_JWE_INVALID");
1171
- remaining -= p2c;
1172
- } };
1268
+ function asKeyLookupError(error, what) {
1269
+ return asJWTError(error, {
1270
+ code: "ERR_JWK_KEY_NOT_FOUND",
1271
+ message: `Key lookup failed for ${what}.`
1272
+ });
1173
1273
  }
1174
- function serializeProtectedHeader(header) {
1274
+ function asJWTError(error, options) {
1275
+ if (error instanceof JWTError) return error;
1276
+ return new JWTError(options.message, options.code, error);
1277
+ }
1278
+ function copyJsonObject(value, options) {
1175
1279
  try {
1176
- return JSON.stringify(header);
1280
+ return sanitizeObjectCopy(value);
1177
1281
  } catch (error) {
1178
- throw new JWTError("The protected header is not JSON-serializable.", "ERR_INVALID_OPTION", error);
1282
+ throw asJWTError(error, options);
1179
1283
  }
1180
1284
  }
1181
- function assertProducerCrit(header, family) {
1182
- const crit = header.crit;
1183
- if (crit === void 0) return;
1184
- assertCritShape(crit, {
1185
- family,
1186
- code: "ERR_INVALID_OPTION"
1285
+ function asDecryptionError(error) {
1286
+ return asJWTError(error, {
1287
+ code: "ERR_JWE_DECRYPTION_FAILED",
1288
+ message: "JWE decryption failed."
1187
1289
  });
1188
- for (const param of crit) {
1189
- if (Object.hasOwn(header, param)) continue;
1190
- throw new JWTError(`"crit" lists "${param}", which the protected header does not carry.`, "ERR_INVALID_OPTION");
1191
- }
1192
- }
1193
- const PROTECTED_ONLY_PARAMS = {
1194
- JWS: ["crit", "b64"],
1195
- JWE: ["crit"]
1196
- };
1197
- function assertProtectedOnlyOption(header, options) {
1198
- if (!header) return;
1199
- const { tier, family } = options;
1200
- for (const param of PROTECTED_ONLY_PARAMS[family]) {
1201
- if (!Object.hasOwn(header, param)) continue;
1202
- throw new JWTError(`${family} "${param}" must be in the protected header, not the ${tier} header.`, "ERR_INVALID_OPTION");
1203
- }
1204
- }
1205
- function assertProducerKeyHeaders(header, options) {
1206
- if (!header) return;
1207
- const { tier, family } = options;
1208
- if (Object.hasOwn(header, "jwk") && !isPublicJWK(Reflect.get(header, "jwk"))) throw new JWTError(`${family} "jwk" in the ${tier} header must be a public JWK.`, "ERR_INVALID_OPTION");
1209
- if (Object.hasOwn(header, "epk")) throw new JWTError(`${family} "epk" is not a header option, use "ecdh.ephemeralKey".`, "ERR_INVALID_OPTION");
1210
- }
1211
- function assertProducerConfirmation(payload) {
1212
- if (typeof payload !== "object" || payload === null) return;
1213
- const cnf = Reflect.get(payload, "cnf");
1214
- if (typeof cnf !== "object" || cnf === null || !Object.hasOwn(cnf, "jwk")) return;
1215
- if (!isPublicJWK(Reflect.get(cnf, "jwk"))) throw new JWTError("Invalid JWT \"cnf\": \"jwk\" must be a public JWK.", "ERR_JWT_CLAIM_INVALID");
1216
- }
1217
- function assertOptionEntry(entry, options) {
1218
- const { label, objects } = options;
1219
- assertPlainObject(entry, label);
1220
- for (const member of objects) if (entry[member] !== void 0) assertPlainObject(entry[member], `${label}.${member}`);
1221
1290
  }
1222
1291
  function assertProducerPartyInfo(name, value) {
1223
1292
  if (!(value instanceof Uint8Array)) throw new JWTError(`"${name === "apu" ? "partyUInfo" : "partyVInfo"}" (${name}) must be a Uint8Array.`, "ERR_INVALID_OPTION");
1224
1293
  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");
1225
1294
  }
1226
- function assertProducerCEK(cek, enc) {
1227
- if (cek === void 0) return;
1228
- const expected = bitLengthCEK(enc) >> 3;
1229
- if (!(cek instanceof Uint8Array) || cek.length !== expected) throw new JWTError(`"cek" must be ${expected} bytes for ${enc}.`, "ERR_INVALID_OPTION");
1230
- }
1231
- function assertProducerIV(iv, enc) {
1232
- if (iv === void 0) return;
1233
- const expected = bitLengthIV(enc) >> 3;
1234
- if (!(iv instanceof Uint8Array) || iv.length !== expected) throw new JWTError(`"contentEncryptionIV" must be ${expected} bytes for ${enc}.`, "ERR_INVALID_OPTION");
1235
- }
1236
- function assertConsumerOptions(options) {
1237
- assertOptionEntry(options, {
1238
- label: "options",
1239
- objects: ["limits"]
1240
- });
1241
- const typ = options.typ;
1242
- if (typ !== void 0 && (typeof typ !== "string" || typ === "")) throw new JWTError("\"typ\" must be a non-empty string.", "ERR_INVALID_OPTION");
1243
- assertStringList(options.algorithms, "algorithms");
1244
- assertStringList(options.encryptionAlgorithms, "encryptionAlgorithms");
1245
- assertStringList(options.recognizedHeaders, "recognizedHeaders");
1246
- assertClaimValidationOptions(options);
1247
- }
1248
1295
  const JWK_SET_KEY_OPS = /* @__PURE__ */ Object.freeze({
1249
1296
  sig: ["verify"],
1250
1297
  enc: [
@@ -1262,9 +1309,12 @@ function buildJWKSetFilter(header, options) {
1262
1309
  const keyOps = JWK_SET_KEY_OPS[op];
1263
1310
  return (k) => {
1264
1311
  if (!isJWK(k)) return false;
1265
- if (k.kty === "oct" && !allowSymmetric) return false;
1312
+ if (!allowSymmetric && hasSymmetricSecret(k)) return false;
1266
1313
  if (kid && k.kid !== kid) return false;
1267
- if (k.alg && k.alg !== alg) return false;
1314
+ if (k.alg && !(alg && jwkAlgServes({
1315
+ kty: k.kty,
1316
+ alg: k.alg
1317
+ }, alg))) return false;
1268
1318
  if (k.use !== void 0 && k.use !== use) return false;
1269
1319
  const ops = k.key_ops;
1270
1320
  if (ops !== void 0 && !(Array.isArray(ops) && ops.some((o) => keyOps.includes(o)))) return false;
@@ -1318,152 +1368,14 @@ function buildECDHAgreementParams(ecdh) {
1318
1368
  }
1319
1369
  return params;
1320
1370
  }
1321
- async function resolveSigningKey(alg, key, usage) {
1322
- if (key instanceof Uint8Array) {
1323
- if (alg !== "HS256" && alg !== "HS384" && alg !== "HS512") throw new JWTError(`${alg} needs an asymmetric key, not raw bytes.`, "ERR_JWK_INVALID");
1324
- assertOctKeyLength(key, alg);
1325
- return crypto.subtle.importKey("raw", key, {
1326
- name: "HMAC",
1327
- hash: jwsHashOf(alg)
1328
- }, false, [usage]);
1329
- }
1330
- if (RSA_SIGNATURE_ALGORITHMS.has(alg)) {
1331
- const modulusLength = modulusLengthOf(key.algorithm);
1332
- if (typeof modulusLength !== "number" || modulusLength < 2048) throw new JWTError(`${alg} requires a key modulusLength of at least 2048 bits`, "ERR_JWK_INVALID");
1333
- }
1334
- return key;
1335
- }
1336
- function validateClaimsIfJson(payload, mode, options) {
1337
- if (mode !== "json" || options.validateClaims === false) return;
1338
- validateJwtClaims(payload, options);
1339
- }
1340
- const PAYLOAD_MODES = /* @__PURE__ */ new Set([
1341
- "json",
1342
- "string",
1343
- "bytes"
1344
- ]);
1345
- function resolvePayloadMode(options) {
1346
- const { payload, forceUint8Array, validateClaims } = options;
1347
- if (payload !== void 0 && !PAYLOAD_MODES.has(payload)) throw new JWTError("\"payload\" must be \"json\", \"string\" or \"bytes\".", "ERR_INVALID_OPTION");
1348
- let mode = payload ?? "json";
1349
- if (forceUint8Array !== void 0) {
1350
- if (payload === void 0) mode = forceUint8Array ? "bytes" : "json";
1351
- else if (forceUint8Array !== (payload === "bytes")) throw new JWTError("\"forceUint8Array\" contradicts \"payload\", pass \"payload\" alone.", "ERR_INVALID_OPTION");
1352
- }
1353
- if (validateClaims === true && mode !== "json") throw new JWTError("\"validateClaims\" requires payload: \"json\".", "ERR_INVALID_OPTION");
1354
- return mode;
1355
- }
1356
1371
  function stringKeyError() {
1357
1372
  return new JWTError("Key must be a JWK, CryptoKey or Uint8Array, not a string.", "ERR_JWK_INVALID");
1358
1373
  }
1359
- function assertNotStringKey(key) {
1360
- if (typeof key === "string") throw stringKeyError();
1361
- }
1362
1374
  function resolvePasswordKey(alg, key) {
1363
1375
  if (typeof key !== "string") return key;
1364
1376
  if (!isPBES2Algorithm(alg)) throw stringKeyError();
1365
1377
  return textEncoder.encode(key);
1366
1378
  }
1367
- const JWS_ALG_CTX = /* @__PURE__ */ Object.freeze({
1368
- infer: inferJWSAllowedAlgorithms,
1369
- octRoles: false,
1370
- errorCode: "ERR_JWS_ALG_NOT_ALLOWED",
1371
- label: "Algorithm",
1372
- op: "sig"
1373
- });
1374
- const JWE_ALG_CTX = /* @__PURE__ */ Object.freeze({
1375
- infer: inferJWEAllowedAlgorithms,
1376
- octRoles: true,
1377
- errorCode: "ERR_JWE_ALG_NOT_ALLOWED",
1378
- label: "Key management algorithm",
1379
- op: "enc"
1380
- });
1381
- function checkAlgAllowed(alg, key, options) {
1382
- const { ctx, algorithms, allowSymmetric } = options;
1383
- if (algorithms !== void 0) return algorithms.includes(alg) ? void 0 : notAllowed(alg, ctx);
1384
- 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);
1385
- const inferred = ctx.infer(key, { allowSymmetric });
1386
- if (!inferred) return new JWTError("Cannot infer allowed algorithms from this key, pass \"algorithms\".", ctx.errorCode);
1387
- return inferred.includes(alg) ? void 0 : notAllowed(alg, ctx);
1388
- }
1389
- function notAllowed(alg, ctx) {
1390
- return new JWTError(`${ctx.label} not allowed: ${alg}`, ctx.errorCode);
1391
- }
1392
- function keyMatchesHeader(header, keyMaterial, options) {
1393
- const { ctx, allowSymmetric } = options;
1394
- if (isJWKSet(keyMaterial)) {
1395
- const candidates = keyMaterial.keys.filter(buildJWKSetFilter(header, {
1396
- op: ctx.op,
1397
- allowSymmetric
1398
- }));
1399
- return candidates.length === 0 || candidates.some((k) => keyServesHeaderAlg(header, k, ctx));
1400
- }
1401
- if (isJWK(keyMaterial)) return keyServesHeaderAlg(header, keyMaterial, ctx);
1402
- if (isCryptoKey(keyMaterial)) return keyServesHeaderAlg(header, keyMaterial, ctx);
1403
- return true;
1404
- }
1405
- function assertJWSAlgSupported(alg) {
1406
- const error = checkJWSAlgSupported(alg);
1407
- if (error) throw error;
1408
- }
1409
- function checkJWSAlgSupported(alg) {
1410
- return checkAlgSupported(alg, {
1411
- supported: isJWSAlgorithm,
1412
- code: "ERR_JWS_ALG_NOT_ALLOWED",
1413
- label: "Algorithm",
1414
- role: "signing algorithm"
1415
- });
1416
- }
1417
- function checkJWSB64(header) {
1418
- if (Object.hasOwn(header, "b64") && typeof header.b64 !== "boolean") return new JWTError("Invalid JWS: \"b64\" must be a boolean.", "ERR_JWS_INVALID");
1419
- if (header.b64 !== false) return void 0;
1420
- if (Array.isArray(header.crit) && header.crit.includes("b64")) return void 0;
1421
- return new JWTError("Invalid JWS: \"b64\" must be listed in \"crit\".", "ERR_JWS_INVALID");
1422
- }
1423
- function assertB64Option(header) {
1424
- if (!header || !Object.hasOwn(header, "b64") || typeof header.b64 === "boolean") return;
1425
- throw new JWTError("\"b64\" must be a boolean.", "ERR_INVALID_OPTION");
1426
- }
1427
- function applyB64Header(header) {
1428
- assertB64Option(header);
1429
- if (header.b64 === true) {
1430
- if (!(Array.isArray(header.crit) && header.crit.includes("b64"))) delete header.b64;
1431
- return;
1432
- }
1433
- if (header.b64 !== false) return;
1434
- const crit = header.crit;
1435
- if (crit === void 0) header.crit = ["b64"];
1436
- else if (Array.isArray(crit) && !crit.includes("b64")) header.crit = [...crit, "b64"];
1437
- }
1438
- function assertCompactToken(token, family) {
1439
- if (typeof token !== "string") throw new JWTError(`Invalid ${family}: token must be a string.`, `ERR_${family}_INVALID`);
1440
- }
1441
- function assertSerializationObject(value, family) {
1442
- if (!isPlainObject(value)) throw new JWTError(`Invalid ${family} JSON Serialization: expected an object.`, `ERR_${family}_INVALID_SERIALIZATION`);
1443
- }
1444
- function checkSerializationEntry(entry, options) {
1445
- const { family, label, objects, strings } = options;
1446
- const code = `ERR_${family}_INVALID`;
1447
- if (!isPlainObject(entry)) return new JWTError(`Invalid ${family}: ${label} must be a JSON object.`, code);
1448
- 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);
1449
- 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);
1450
- }
1451
- function asKeyLookupError(error, what) {
1452
- return asJWTError(error, {
1453
- code: "ERR_JWK_KEY_NOT_FOUND",
1454
- message: `Key lookup failed for ${what}.`
1455
- });
1456
- }
1457
- function asJWTError(error, options) {
1458
- if (error instanceof JWTError) return error;
1459
- return new JWTError(options.message, options.code, error);
1460
- }
1461
- function asDecryptionError(error) {
1462
- return asJWTError(error, {
1463
- code: "ERR_JWE_DECRYPTION_FAILED",
1464
- message: "JWE decryption failed."
1465
- });
1466
- }
1467
1379
  async function resolveKeyInput(key, options) {
1468
1380
  if (typeof key !== "function") return key;
1469
1381
  const { header, token, what } = options;
@@ -1476,184 +1388,11 @@ async function resolveKeyInput(key, options) {
1476
1388
  if (resolved === void 0 || resolved === null) throw new JWTError(`Key lookup returned no key for ${what}.`, "ERR_JWK_KEY_NOT_FOUND");
1477
1389
  return resolved;
1478
1390
  }
1479
- function asKeyUsageError(error, alg) {
1480
- return asJWTError(error, {
1481
- code: "ERR_JWK_INVALID",
1482
- message: `Key is not usable for ${alg}.`
1483
- });
1484
- }
1485
- const JWE_ENC_CEK_FORMAT = /* @__PURE__ */ Object.freeze({
1486
- "A128GCM": "cryptokey",
1487
- "A192GCM": "cryptokey",
1488
- "A256GCM": "cryptokey",
1489
- "A128CBC-HS256": "raw",
1490
- "A192CBC-HS384": "raw",
1491
- "A256CBC-HS512": "raw"
1492
- });
1493
1391
  function assertDirectKeyRole(key, enc) {
1494
1392
  if (!isJWK(key) || typeof key.alg !== "string" || key.alg === "dir") return;
1495
1393
  if (enc !== void 0 && key.alg === enc) return;
1496
1394
  throw new JWTError(`JWK "alg" is "${key.alg}" but "dir" requires "dir" or the token's "enc".`, "ERR_JWK_INVALID");
1497
1395
  }
1498
- const JWE_DIRECT_ALGS = /* @__PURE__ */ new Set(["dir", "ECDH-ES"]);
1499
- function checkJWEAlgSupported(alg) {
1500
- return checkAlgSupported(alg, {
1501
- supported: isKeyManagementAlgorithm,
1502
- code: "ERR_JWE_ALG_NOT_ALLOWED",
1503
- label: "Key management algorithm",
1504
- role: "key management algorithm"
1505
- });
1506
- }
1507
- function checkJWEEncSupported(enc) {
1508
- if (typeof enc === "string" && isContentEncryptionAlgorithm(enc)) return void 0;
1509
- return new JWTError(`Invalid JWE: unsupported "enc" ${quoteTokenValue(enc)}`, "ERR_JWE_INVALID");
1510
- }
1511
- function isJWEAlgSupported(alg) {
1512
- return isKeyManagementAlgorithm(alg);
1513
- }
1514
- function assertJWEAlgSupported(alg) {
1515
- const error = checkJWEAlgSupported(alg);
1516
- if (error) throw error;
1517
- }
1518
- function assertJWEEncSupported(enc) {
1519
- const error = checkJWEEncSupported(enc);
1520
- if (error) throw error;
1521
- }
1522
- function checkJWEEncAllowed(enc, encryptionAlgorithms) {
1523
- if (encryptionAlgorithms === void 0 || encryptionAlgorithms.includes(enc)) return void 0;
1524
- return new JWTError(`Content encryption algorithm not allowed: ${enc}`, "ERR_JWE_ALG_NOT_ALLOWED");
1525
- }
1526
- async function exportReturnedCek(cek) {
1527
- if (!isCryptoKey(cek)) return cek;
1528
- if (!cek.extractable) throw new JWTError("\"returnCek\" requires an extractable content encryption key.", "ERR_INVALID_OPTION");
1529
- return new Uint8Array(await crypto.subtle.exportKey("raw", cek));
1530
- }
1531
- function cekFormatForEnc(enc) {
1532
- return JWE_ENC_CEK_FORMAT[enc];
1533
- }
1534
- function buildUnwrapKeyOptions(header, algorithms, options) {
1535
- const { alg, enc } = algorithms;
1536
- const opts = {
1537
- alg,
1538
- enc,
1539
- format: cekFormatForEnc(enc),
1540
- keyUsage: options?.keyUsage || ["decrypt"]
1541
- };
1542
- if (header.iv) opts.iv = header.iv;
1543
- if (header.tag) opts.tag = header.tag;
1544
- if (header.p2s) opts.p2s = header.p2s;
1545
- if (header.p2c) opts.p2c = header.p2c;
1546
- if (header.epk) opts.epk = header.epk;
1547
- if (header.apu) opts.apu = header.apu;
1548
- if (header.apv) opts.apv = header.apv;
1549
- if (options?.unwrappedKeyAlgorithm) opts.unwrappedKeyAlgorithm = options.unwrappedKeyAlgorithm;
1550
- if (options?.extractable !== void 0) opts.extractable = options.extractable;
1551
- if (options?.minIterations !== void 0) opts.minIterations = options.minIterations;
1552
- if (options?.maxIterations !== void 0) opts.maxIterations = options.maxIterations;
1553
- return opts;
1554
- }
1555
- function checkJWEDirectEncryptedKey(alg, encryptedKey) {
1556
- if (!JWE_DIRECT_ALGS.has(alg) || !encryptedKey) return void 0;
1557
- return new JWTError(`Invalid JWE: Encrypted key must be empty for ${alg}.`, "ERR_JWE_INVALID");
1558
- }
1559
- function checkJWEContentSegments(enc, iv, tag) {
1560
- const ivBytes = bitLengthIV(enc) >> 3;
1561
- if (iv.length !== ivBytes) return new JWTError(`Invalid JWE: Initialization vector must be ${ivBytes} bytes for ${enc} (got ${iv.length}).`, "ERR_JWE_INVALID");
1562
- const tagBytes = bitLengthTag(enc) >> 3;
1563
- if (tag.length !== tagBytes) return new JWTError(`Invalid JWE: Authentication tag must be ${tagBytes} bytes for ${enc} (got ${tag.length}).`, "ERR_JWE_INVALID");
1564
- }
1565
- function checkJWEZip(header) {
1566
- if (!header || !Object.hasOwn(header, "zip")) return void 0;
1567
- return new JWTError("Invalid JWE: compression is not supported.", "ERR_JWE_INVALID");
1568
- }
1569
- function assertNoZipOption(header, tier) {
1570
- if (!header || !Object.hasOwn(header, "zip")) return;
1571
- throw new JWTError(`JWE compression ("zip") in the ${tier} header is not supported.`, "ERR_INVALID_OPTION");
1572
- }
1573
- function checkJWEUnprotectedCrit(header) {
1574
- if (!header || !Object.hasOwn(header, "crit")) return void 0;
1575
- return new JWTError("Invalid JWE: \"crit\" must be integrity protected.", "ERR_JWE_INVALID");
1576
- }
1577
- function typMatches(expected, actual) {
1578
- if (typeof actual !== "string") return false;
1579
- return normalizeTyp(expected) === normalizeTyp(actual);
1580
- }
1581
- function checkProtectedTyp(expected, protectedHeader, options) {
1582
- if (expected === void 0) return void 0;
1583
- const actual = protectedHeader.typ;
1584
- if (typMatches(expected, actual)) return void 0;
1585
- const { family, label } = options;
1586
- const where = label ? ` on ${label}` : "";
1587
- const message = actual === void 0 ? `Invalid ${family}: the protected header${where} carries no "typ", expected "${expected}".` : `Invalid ${family}: "typ" mismatch${where}, expected "${expected}".`;
1588
- return new JWTError(message, `ERR_${family}_INVALID`);
1589
- }
1590
- function normalizeTyp(typ) {
1591
- const lowered = typ.toLowerCase();
1592
- return lowered.includes("/") ? lowered : `application/${lowered}`;
1593
- }
1594
- function decodeProtectedHeader(encoded, family) {
1595
- let parsed = {};
1596
- if (encoded) {
1597
- try {
1598
- parsed = safeJsonParse(base64UrlParse(encoded));
1599
- } catch (error) {
1600
- throw new JWTError(`Invalid ${family}: Protected header could not be decoded.`, `ERR_${family}_INVALID`, error);
1601
- }
1602
- if (!isPlainObject(parsed)) throw new JWTError(`Invalid ${family}: Protected header must be a JSON object.`, `ERR_${family}_INVALID`);
1603
- }
1604
- return parsed;
1605
- }
1606
- function decodeSegment(encoded, options) {
1607
- try {
1608
- return base64UrlParse(encoded, { returnAs: "uint8array" });
1609
- } catch (error) {
1610
- throw new JWTError(`Invalid ${options.family}: ${options.what} could not be decoded.`, `ERR_${options.family}_INVALID`, error);
1611
- }
1612
- }
1613
- function decodeJWSPayload(payloadSegment, useB64, mode) {
1614
- if (!useB64) return mode === "string" ? payloadSegment : parsePayloadBytes(textEncoder.encode(payloadSegment), {
1615
- payload: mode,
1616
- family: "JWS"
1617
- });
1618
- try {
1619
- return parsePayloadSegment(payloadSegment, {
1620
- payload: mode,
1621
- family: "JWS"
1622
- });
1623
- } catch (error) {
1624
- if (error instanceof JWTError) throw error;
1625
- throw new JWTError("Invalid JWS: Payload could not be decoded.", "ERR_JWS_INVALID", error);
1626
- }
1627
- }
1628
- function decodeJWEPayload(plaintext, mode) {
1629
- return parsePayloadBytes(plaintext, {
1630
- payload: mode,
1631
- family: "JWE"
1632
- });
1633
- }
1634
- function checkAlgSupported(alg, options) {
1635
- const { supported, code, label, role } = options;
1636
- if (alg === "none") return new JWTError(`"none" is not a valid ${role}`, code);
1637
- if (!supported(alg)) return new JWTError(`${label} not supported: ${quoteTokenValue(alg)}`, code);
1638
- }
1639
- function keyServesHeaderAlg(header, key, ctx) {
1640
- const { alg } = header;
1641
- if (!alg) return false;
1642
- const inferred = ctx.infer(key);
1643
- if (inferred && !inferred.includes(alg)) return false;
1644
- if (!isECDHESAlgorithm(alg)) return true;
1645
- const epkCurve = header.epk?.crv;
1646
- const keyCurve = isCryptoKey(key) ? cryptoKeyCurve(key) : "crv" in key ? key.crv : void 0;
1647
- return !epkCurve || !keyCurve || epkCurve === keyCurve;
1648
- }
1649
- const RSA_SIGNATURE_ALGORITHMS = /* @__PURE__ */ new Set([
1650
- "RS256",
1651
- "RS384",
1652
- "RS512",
1653
- "PS256",
1654
- "PS384",
1655
- "PS512"
1656
- ]);
1657
1396
  var WeakMapJWKCache = class {
1658
1397
  _map = /* @__PURE__ */ new WeakMap();
1659
1398
  get(jwk, alg) {
@@ -1683,8 +1422,9 @@ async function importKey(key, algOrOptions) {
1683
1422
  return key;
1684
1423
  }
1685
1424
  if (isJWK(key)) {
1425
+ if (key.kty !== "oct" && Object.hasOwn(key, "k")) throw new JWTError(`JWK "k" is defined only for "oct" keys, not "${key.kty}".`, "ERR_JWK_INVALID");
1686
1426
  assertJWKAlgAuthority(key, alg);
1687
- if ("k" in key && typeof key.k === "string") {
1427
+ if (key.kty === "oct" && typeof key.k === "string") {
1688
1428
  const rawBytes = decodeSegment(key.k, {
1689
1429
  family: "JWK",
1690
1430
  what: "\"k\""
@@ -1722,9 +1462,10 @@ async function importKey(key, algOrOptions) {
1722
1462
  throw new JWTError("Invalid key type provided to importKey", "ERR_JWK_INVALID");
1723
1463
  }
1724
1464
  function assertJWKAlgAuthority(jwk, alg) {
1725
- if (!alg || !jwk.alg || jwk.alg === alg) return;
1726
- if (jwk.kty === "oct" && alg === "dir" && isContentEncryptionAlgorithm(jwk.alg)) return;
1727
- if (isEd25519Signature(jwk.alg) && isEd25519Signature(alg)) return;
1465
+ if (!alg || !jwk.alg || jwkAlgServes({
1466
+ kty: jwk.kty,
1467
+ alg: jwk.alg
1468
+ }, alg)) return;
1728
1469
  throw new JWTError(`JWK "alg" is "${jwk.alg}" but the operation requires "${alg}".`, "ERR_JWK_INVALID");
1729
1470
  }
1730
1471
  function assertIntentOnJWK(jwk, expect) {
@@ -1743,4 +1484,58 @@ function getJWKsFromSet(jwkSet, filter) {
1743
1484
  const keys = jwkSet.keys.filter((key) => isJWK(key));
1744
1485
  return filter ? keys.filter(filter) : keys;
1745
1486
  }
1746
- export { DEFAULT_JOSE_LIMITS, DEFAULT_PBES2_ITERATIONS, JWE_ALG_CTX, JWE_DIRECT_ALGS, JWS_ALG_CTX, MAX_PARTY_INFO_BYTES, WeakMapJWKCache, aesKwUnwrap, aesKwWrap, applyB64Header, asDecryptionError, asJWTError, asKeyLookupError, asKeyUsageError, assertB64Option, assertCompactToken, assertConsumerOptions, assertDirectKeyRole, assertECDHKeyAllowed, assertEntryLimit, assertJWEAlgSupported, assertJWEEncSupported, assertJWKSetCandidates, assertJWSAlgSupported, assertNoZipOption, assertNotStringKey, assertOctKeyLength, assertOptionEntry, assertPBES2Count, assertPBES2Params, assertPBES2Salt, assertProducerCEK, assertProducerConfirmation, assertProducerCrit, assertProducerIV, assertProducerKeyHeaders, assertProtectedOnlyOption, assertSerializationObject, bitLengthCEK, bitLengthIV, bitLengthTag, buildECDHAgreementParams, buildJWKSetFilter, buildUnwrapKeyOptions, checkAlgAllowed, checkJWEAlgSupported, checkJWEContentSegments, checkJWEDirectEncryptedKey, checkJWEEncAllowed, checkJWEEncSupported, checkJWEUnprotectedCrit, checkJWEZip, checkJWSAlgSupported, checkJWSB64, checkProtectedTyp, checkSerializationEntry, clearJWKCache, configureJWKCache, createPBES2Budget, decodeJWEPayload, decodeJWSPayload, decodeProtectedHeader, decodeSegment, decrypt, decryptRSAES, deriveECDHESKey, deriveKey, ecdhDerivedBits, ecdhesWrap, encrypt, encryptKey, encryptRSAES, exportReturnedCek, fromPKCS8, fromSPKI, fromX509, gcmkwDecrypt, gcmkwEncrypt, generateCEK, generateIV, getJWKsFromSet, importKey, isJWEAlgSupported, keyMatchesHeader, keyToJWK, normalizeEpk, pbes2Unwrap, pbes2Wrap, quoteTokenValue, resolveKeyInput, resolveLimit, resolvePasswordKey, resolvePayloadMode, resolveSigningKey, serializeProtectedHeader, sign, stringKeyError, thumbprint, toPKCS8, toSPKI, validateClaimsIfJson, verify };
1487
+ const JWS_ALG_CTX = /* @__PURE__ */ Object.freeze({
1488
+ infer: inferJWSAllowedAlgorithms,
1489
+ octRoles: false,
1490
+ errorCode: "ERR_JWS_ALG_NOT_ALLOWED",
1491
+ label: "Algorithm",
1492
+ op: "sig"
1493
+ });
1494
+ function checkAlgAllowed(alg, key, options) {
1495
+ const { ctx, algorithms, allowSymmetric } = options;
1496
+ if (algorithms !== void 0) return algorithms.includes(alg) ? void 0 : notAllowed(alg, ctx);
1497
+ if (isJWK(key) && typeof key.alg === "string" && (!ctx.octRoles || key.kty !== "oct")) return isSameAlgorithm(key.alg, alg) ? void 0 : notAllowed(alg, ctx);
1498
+ const inferred = ctx.infer(key, { allowSymmetric });
1499
+ if (!inferred) return new JWTError("Cannot infer allowed algorithms from this key, pass \"algorithms\".", ctx.errorCode);
1500
+ return inferred.includes(alg) ? void 0 : notAllowed(alg, ctx);
1501
+ }
1502
+ function notAllowed(alg, ctx) {
1503
+ return new JWTError(`${ctx.label} not allowed: ${alg}`, ctx.errorCode);
1504
+ }
1505
+ function keyMatchesHeader(header, keyMaterial, options) {
1506
+ const { ctx, allowSymmetric } = options;
1507
+ if (isJWKSet(keyMaterial)) {
1508
+ const candidates = keyMaterial.keys.filter(buildJWKSetFilter(header, {
1509
+ op: ctx.op,
1510
+ allowSymmetric
1511
+ }));
1512
+ return candidates.length === 0 || candidates.some((k) => keyServesHeaderAlg(header, k, ctx));
1513
+ }
1514
+ if (isJWK(keyMaterial)) return keyServesHeaderAlg(header, keyMaterial, ctx);
1515
+ if (isCryptoKey(keyMaterial)) return keyServesHeaderAlg(header, keyMaterial, ctx);
1516
+ return true;
1517
+ }
1518
+ function checkJWEEncSupported(enc) {
1519
+ if (typeof enc === "string" && isContentEncryptionAlgorithm(enc)) return void 0;
1520
+ return new JWTError(`Invalid JWE: unsupported "enc" ${quoteTokenValue(enc)}`, "ERR_JWE_INVALID");
1521
+ }
1522
+ function assertJWEEncSupported(enc) {
1523
+ const error = checkJWEEncSupported(enc);
1524
+ if (error) throw error;
1525
+ }
1526
+ function checkAlgSupported(alg, options) {
1527
+ const { supported, code, label, role } = options;
1528
+ if (alg === "none") return new JWTError(`"none" is not a valid ${role}`, code);
1529
+ if (!supported(alg)) return new JWTError(`${label} not supported: ${quoteTokenValue(alg)}`, code);
1530
+ }
1531
+ function keyServesHeaderAlg(header, key, ctx) {
1532
+ const { alg } = header;
1533
+ if (!alg) return false;
1534
+ const inferred = ctx.infer(key);
1535
+ if (inferred && !inferred.includes(alg)) return false;
1536
+ if (!isECDHESAlgorithm(alg)) return true;
1537
+ const epkCurve = header.epk?.crv;
1538
+ const keyCurve = isCryptoKey(key) ? cryptoKeyCurve(key) : "crv" in key ? key.crv : void 0;
1539
+ return !epkCurve || !keyCurve || epkCurve === keyCurve;
1540
+ }
1541
+ export { DEFAULT_JOSE_LIMITS, DEFAULT_PBES2_ITERATIONS, JWS_ALG_CTX, MAX_PARTY_INFO_BYTES, WeakMapJWKCache, aesKwUnwrap, aesKwWrap, asDecryptionError, asJWTError, asKeyLookupError, assertCompactToken, assertConsumerOptions, assertDirectKeyRole, assertECDHKeyAllowed, assertEntryLimit, assertJWEEncSupported, assertJWKSetCandidates, assertOctKeyLength, assertOptionEntry, assertPBES2Count, assertPBES2Iterations, assertPBES2Params, assertPBES2Salt, assertProducerConfirmation, assertProducerCrit, assertProducerKeyHeaders, assertProtectedOnlyOption, assertSerializationObject, bitLengthCEK, bitLengthIV, bitLengthTag, buildECDHAgreementParams, buildJWKSetFilter, checkAlgAllowed, checkAlgSupported, checkJWEEncSupported, checkProtectedTyp, checkSerializationEntry, clearJWKCache, configureJWKCache, copyJsonObject, decodeProtectedHeader, decodeSegment, decrypt, decryptRSAES, deriveECDHESKey, deriveKey, ecdhDerivedBits, ecdhesWrap, encrypt, encryptKey, encryptRSAES, fromPKCS8, fromSPKI, fromX509, gcmkwDecrypt, gcmkwEncrypt, generateCEK, generateIV, getJWKsFromSet, importKey, jwkTokey, keyMatchesHeader, keyToJWK, normalizeEpk, pbes2Unwrap, pbes2Wrap, resolveKeyInput, resolveLimit, resolvePasswordKey, serializeProtectedHeader, sign, stringKeyError, thumbprint, toPKCS8, toSPKI, verify };