unjwt 0.6.0 → 0.7.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.
package/dist/core/jwe.mjs CHANGED
@@ -1,161 +1,3 @@
1
- import { D as getPlaintextBytes, E as decodePayloadFromBytes, M as JWTError, N as isJWTError, S as computeJwtTimeClaims, a as base64UrlEncode, b as applyTypCtyDefaults, c as isCryptoKey, d as isJWKSet, g as randomBytes, i as base64UrlDecode, j as validateJwtClaims, k as validateCriticalHeadersJWE, l as isCryptoKeyPair, u as isJWK, v as textEncoder, y as sanitizeObject } from "../_chunks/utils.mjs";
2
- import { T as generateIV, b as decrypt$1, o as encryptKey, x as encrypt$1 } from "../_chunks/_crypto.mjs";
3
- import { getJWKsFromSet, importKey, unwrapKey } from "./jwk.mjs";
4
- //#region src/core/jwe.ts
5
- async function encrypt(payload, key, options = {}) {
6
- const { protectedHeader: userHeader, cek: providedCek, contentEncryptionIV: providedContentIV, keyManagementIV, p2s, p2c, ecdh } = options;
7
- let { alg, enc } = options;
8
- if (!alg) {
9
- if (typeof key === "string" || key instanceof Uint8Array) alg = "PBES2-HS256+A128KW";
10
- else if (isJWK(key)) alg = key.alg === "A128GCM" || key.alg === "A192GCM" || key.alg === "A256GCM" ? `${key.alg}KW` : key.alg;
11
- }
12
- if (!alg) throw new TypeError("JWE \"alg\" (Key Management Algorithm) must be provided in options or inferable from the key");
13
- if (!enc) if (alg === "dir") {
14
- enc = isJWK(key) && "enc" in key ? key.enc : void 0;
15
- if (!enc) throw new TypeError("JWE \"enc\" must be provided when alg is \"dir\"");
16
- } else enc = isJWK(key) && "enc" in key ? key.enc : "A128GCM";
17
- const jweKeyManagementParams = {};
18
- if (keyManagementIV) jweKeyManagementParams.iv = keyManagementIV;
19
- if (p2s) jweKeyManagementParams.p2s = p2s;
20
- else if (alg?.startsWith("PBES2")) jweKeyManagementParams.p2s = randomBytes(16);
21
- if (p2c) jweKeyManagementParams.p2c = p2c;
22
- else if (alg?.startsWith("PBES2")) jweKeyManagementParams.p2c = 6e5;
23
- if (ecdh?.partyUInfo) jweKeyManagementParams.apu = ecdh.partyUInfo;
24
- if (ecdh?.partyVInfo) jweKeyManagementParams.apv = ecdh.partyVInfo;
25
- if (ecdh?.ephemeralKey) {
26
- const { epk, epkPrivateKey } = parseEphemeralKey(ecdh.ephemeralKey);
27
- jweKeyManagementParams.epk = epk;
28
- jweKeyManagementParams.epkPrivateKey = epkPrivateKey;
29
- }
30
- const wrappingKeyMaterial = await importKey(key, alg);
31
- const { cek: finalCek, encryptedKey: jweEncryptedKey, parameters: keyManagementHeaderParams } = await encryptKey(alg, enc, wrappingKeyMaterial, providedCek, jweKeyManagementParams);
32
- const protectedHeader = _buildJWEHeader(alg, enc, key, userHeader, keyManagementHeaderParams, payload);
33
- const plaintextBytes = getPlaintextBytes(computeJwtTimeClaims(payload, protectedHeader.typ, options.expiresIn, options.currentDate) || payload);
34
- const protectedHeaderEncoded = base64UrlEncode(JSON.stringify(protectedHeader));
35
- const aadBytes = textEncoder.encode(protectedHeaderEncoded);
36
- const contentIVBytes = providedContentIV ?? generateIV(enc);
37
- const { ciphertext: contentCiphertext, tag: contentAuthTag, iv: actualContentIV } = await encrypt$1(enc, plaintextBytes, finalCek, contentIVBytes, aadBytes);
38
- if (!actualContentIV) throw new JWTError("Content encryption IV was not generated or returned.", "ERR_JWE_INVALID");
39
- if (!contentAuthTag) throw new JWTError("Content encryption auth tag was not generated or returned.", "ERR_JWE_INVALID");
40
- return [
41
- protectedHeaderEncoded,
42
- jweEncryptedKey ? base64UrlEncode(jweEncryptedKey) : "",
43
- base64UrlEncode(actualContentIV),
44
- base64UrlEncode(contentCiphertext),
45
- base64UrlEncode(contentAuthTag)
46
- ].join(".");
47
- }
48
- async function decrypt(jwe, key, options = {}) {
49
- const parts = jwe.split(".");
50
- if (parts.length !== 5) throw new JWTError("Invalid JWE: Must contain five sections (RFC7516, section-3).", "ERR_JWE_INVALID");
51
- const [protectedHeaderEncoded, encryptedKeyEncoded, ivEncoded, ciphertextEncoded, authTagEncoded] = parts;
52
- let protectedHeader;
53
- try {
54
- const protectedHeaderJson = base64UrlDecode(protectedHeaderEncoded);
55
- protectedHeader = sanitizeObject(JSON.parse(protectedHeaderJson));
56
- } catch {
57
- throw new JWTError("Invalid JWE: Protected header could not be decoded.", "ERR_JWE_INVALID");
58
- }
59
- if (!protectedHeader || typeof protectedHeader !== "object" || !protectedHeader.alg || !protectedHeader.enc) throw new JWTError("Invalid JWE: Protected header must be an object with \"alg\" and \"enc\" properties.", "ERR_JWE_INVALID");
60
- const alg = protectedHeader.alg;
61
- const enc = protectedHeader.enc;
62
- if (options?.algorithms && !options.algorithms.includes(alg)) throw new JWTError(`Key management algorithm not allowed: ${alg}`, "ERR_JWE_ALG_NOT_ALLOWED");
63
- if (options?.encryptionAlgorithms && !options.encryptionAlgorithms.includes(enc)) throw new JWTError(`Content encryption algorithm not allowed: ${enc}`, "ERR_JWE_ALG_NOT_ALLOWED");
64
- const rawKeyMaterial = typeof key === "function" ? await key(protectedHeader, jwe) : key;
65
- const encryptedKeyBytes = base64UrlDecode(encryptedKeyEncoded, false);
66
- const contentIVBytes = base64UrlDecode(ivEncoded, false);
67
- const contentAuthTagBytes = base64UrlDecode(authTagEncoded, false);
68
- const ciphertextBytes = base64UrlDecode(ciphertextEncoded, false);
69
- const unwrapKeyOpts = {
70
- enc,
71
- format: enc.includes("GCM") ? "cryptokey" : "raw",
72
- keyUsage: options?.keyUsage || ["decrypt"]
73
- };
74
- if (protectedHeader.iv) unwrapKeyOpts.iv = protectedHeader.iv;
75
- if (protectedHeader.tag) unwrapKeyOpts.tag = protectedHeader.tag;
76
- if (protectedHeader.p2s) unwrapKeyOpts.p2s = protectedHeader.p2s;
77
- if (protectedHeader.p2c) unwrapKeyOpts.p2c = protectedHeader.p2c;
78
- if (protectedHeader.epk) unwrapKeyOpts.epk = protectedHeader.epk;
79
- if (protectedHeader.apu) unwrapKeyOpts.apu = protectedHeader.apu;
80
- if (protectedHeader.apv) unwrapKeyOpts.apv = protectedHeader.apv;
81
- if (options?.unwrappedKeyAlgorithm) unwrapKeyOpts.unwrappedKeyAlgorithm = options.unwrappedKeyAlgorithm;
82
- if (options?.extractable) unwrapKeyOpts.extractable = options.extractable;
83
- const aadBytes = textEncoder.encode(protectedHeaderEncoded);
84
- let cek;
85
- let plaintextBytes;
86
- if (isJWKSet(rawKeyMaterial)) {
87
- const candidates = getJWKsFromSet(rawKeyMaterial, _buildJWESetFilter(protectedHeader));
88
- if (candidates.length === 0) throw new JWTError(`No key found in JWK Set${protectedHeader.kid ? ` with kid "${protectedHeader.kid}"` : ""}.`, "ERR_JWK_KEY_NOT_FOUND");
89
- let decrypted = false;
90
- for (const candidate of candidates) try {
91
- const candidateCek = await unwrapKey(alg, encryptedKeyBytes, await importKey(candidate, alg), unwrapKeyOpts);
92
- plaintextBytes = await decrypt$1(enc, candidateCek, ciphertextBytes, contentIVBytes, contentAuthTagBytes, aadBytes);
93
- cek = candidateCek;
94
- decrypted = true;
95
- break;
96
- } catch {}
97
- if (!decrypted) throw new JWTError("JWE decryption failed.", "ERR_JWE_DECRYPTION_FAILED");
98
- } else {
99
- const unwrappingKey = await importKey(rawKeyMaterial, alg);
100
- try {
101
- cek = await unwrapKey(alg, encryptedKeyBytes, unwrappingKey, unwrapKeyOpts);
102
- plaintextBytes = await decrypt$1(enc, cek, ciphertextBytes, contentIVBytes, contentAuthTagBytes, aadBytes);
103
- } catch (error_) {
104
- if (error_ instanceof JWTError) throw error_;
105
- throw new JWTError("JWE decryption failed.", "ERR_JWE_DECRYPTION_FAILED", error_);
106
- }
107
- }
108
- const payload = decodePayloadFromBytes(plaintextBytes, protectedHeader, options?.forceUint8Array);
109
- if (protectedHeader.crit || options?.recognizedHeaders?.length) validateCriticalHeadersJWE(protectedHeader, options?.recognizedHeaders);
110
- if (payload && typeof payload === "object" && options.validateClaims !== false && (options.validateClaims === true || protectedHeader.typ?.toLowerCase().includes("jwt")) && !options.forceUint8Array && !(payload instanceof Uint8Array)) validateJwtClaims(payload, options);
111
- const result = {
112
- payload,
113
- protectedHeader
114
- };
115
- if (options.returnCek) {
116
- result.cek = isCryptoKey(cek) ? new Uint8Array(await crypto.subtle.exportKey("raw", cek)) : cek;
117
- result.aad = aadBytes;
118
- }
119
- return result;
120
- }
121
- function parseEphemeralKey(ephemeralKey) {
122
- let epk;
123
- let epkPrivateKey;
124
- if (isCryptoKeyPair(ephemeralKey)) {
125
- epk = ephemeralKey.publicKey;
126
- epkPrivateKey = ephemeralKey.privateKey;
127
- } else if (typeof ephemeralKey === "object" && ephemeralKey !== null && "publicKey" in ephemeralKey && "privateKey" in ephemeralKey) {
128
- const candidate = ephemeralKey;
129
- if (!candidate.publicKey || !candidate.privateKey) throw new TypeError("ECDH-ES custom ephemeral key must include both publicKey and privateKey.");
130
- epk = candidate.publicKey;
131
- epkPrivateKey = candidate.privateKey;
132
- } else if (isCryptoKey(ephemeralKey)) {
133
- if (ephemeralKey.type !== "private") throw new TypeError("ECDH-ES custom ephemeral CryptoKey must include private key material.");
134
- epk = ephemeralKey;
135
- epkPrivateKey = ephemeralKey;
136
- } else if (isJWK(ephemeralKey)) {
137
- if (!("d" in ephemeralKey) || typeof ephemeralKey.d !== "string") throw new TypeError("ECDH-ES custom ephemeral JWK must include private parameter \"d\".");
138
- epk = ephemeralKey;
139
- epkPrivateKey = ephemeralKey;
140
- } else throw new TypeError("Unsupported ECDH-ES ephemeral key material provided in options.");
141
- return {
142
- epk,
143
- epkPrivateKey
144
- };
145
- }
146
- function _buildJWESetFilter(header) {
147
- const { kid, alg } = header;
148
- return (k) => (!kid || k.kid === kid) && (!k.alg || k.alg === alg);
149
- }
150
- function _buildJWEHeader(alg, enc, key, userHeader, keyManagementParams, payload) {
151
- const safeHeader = sanitizeObject(userHeader);
152
- return applyTypCtyDefaults({
153
- ...isJWK(key) && key.kid ? { kid: key.kid } : {},
154
- ...safeHeader,
155
- ...keyManagementParams,
156
- alg,
157
- enc
158
- }, payload);
159
- }
160
- //#endregion
161
- export { JWTError, decrypt, encrypt, isJWTError };
1
+ import { D as JWTError, O as isJWTError } from "../_chunks/utils.mjs";
2
+ import { a as generalToFlattened, i as encryptMulti, n as encrypt, r as decryptMulti, t as decrypt } from "../_chunks/jwe.mjs";
3
+ export { JWTError, decrypt, decryptMulti, encrypt, encryptMulti, generalToFlattened, isJWTError };
@@ -1,24 +1,91 @@
1
- import { $ as JWK_OKP_SIGN, A as JWK, B as JWK_AES_GCM_KW, C as DeriveKeyOptions, D as GenerateKeyAlgorithm, E as GenerateJWKReturn, F as JWKPEMAlgorithm, G as JWK_ECDH_ES, H as JWK_Asymmetric, I as JWKParameters, J as JWK_EC_Public, K as JWK_ECDSA, L as JWKSet, M as JWKCacheAdapter, N as JWKLookupFunction, O as GenerateKeyOptions, P as JWKLookupFunctionHeader, Q as JWK_OKP_Public, R as JWK_AES_CBC_HMAC, S as ContentEncryptionAlgorithm, T as GenerateJWKOptions, U as JWK_Asymmetric_Algorithm, V as JWK_AES_KW, W as JWK_EC, X as JWK_OKP, Y as JWK_HMAC, Z as JWK_OKP_Private, at as JWK_RSA_ENC, b as JoseHeaderParameters, ct as JWK_RSA_Public, dt as JWK_Symmetric_Algorithm, et as JWK_PBES2, ft as JWK_oct, gt as WrapKeyResult, ht as WrapKeyOptions, it as JWK_RSA, j as JWKAlgorithm, k as GenerateKeyReturn, lt as JWK_RSA_SIGN, mt as UnwrapKeyOptions, nt as JWK_Private, ot as JWK_RSA_PSS, pt as KeyManagementAlgorithm, q as JWK_EC_Private, rt as JWK_Public, st as JWK_RSA_Private, tt as JWK_Pair, ut as JWK_Symmetric, w as DeriveKeyReturn, x as CompositeKey, z as JWK_AES_GCM } from "../_chunks/index.mjs";
2
- import { i as isJWTError, n as JWTErrorCauseMap, r as JWTErrorCode, t as JWTError } from "../_chunks/error.mjs";
3
-
4
- //#region src/core/jwk.d.ts
1
+ import { $ as JWKAlgorithm, At as JWK_RSA_Public, Ct as JWK_Pair, Dt as JWK_RSA_ENC, Et as JWK_RSA, F as JWTErrorCauseMap, Ft as KeyManagementAlgorithm, G as DeriveKeyOptions, H as JoseHeaderParameters, I as JWTErrorCode, It as UnwrapKeyOptions, J as GenerateJWKReturn, K as DeriveKeyReturn, L as isJWTError, Lt as WrapKeyOptions, Mt as JWK_Symmetric, Nt as JWK_Symmetric_Algorithm, Ot as JWK_RSA_PSS, P as JWTError, Pt as JWK_oct, Q as JWK, Rt as WrapKeyResult, St as JWK_PBES2, Tt as JWK_Public, U as CompositeKey, W as ContentEncryptionAlgorithm, X as GenerateKeyOptions, Y as GenerateKeyAlgorithm, Z as GenerateKeyReturn, _t as JWK_HMAC, at as JWKSet, bt as JWK_OKP_Public, ct as JWK_AES_GCM_KW, dt as JWK_Asymmetric_Algorithm, et as JWKCacheAdapter, ft as JWK_EC, gt as JWK_EC_Public, ht as JWK_EC_Private, it as JWKParameters, jt as JWK_RSA_SIGN, kt as JWK_RSA_Private, lt as JWK_AES_KW, mt as JWK_ECDSA, nt as JWKLookupFunctionHeader, ot as JWK_AES_CBC_HMAC, pt as JWK_ECDH_ES, q as GenerateJWKOptions, rt as JWKPEMAlgorithm, st as JWK_AES_GCM, tt as JWKLookupFunction, ut as JWK_Asymmetric, vt as JWK_OKP, wt as JWK_Private, xt as JWK_OKP_SIGN, yt as JWK_OKP_Private } from "../_chunks/index.mjs";
5
2
  /**
6
- * Generates a cryptographic key for the specified algorithm.
3
+ * Generates a cryptographic key for the specified JWA algorithm.
7
4
  *
8
- * @param alg The JWA algorithm identifier (e.g., "HS256", "RS256", "A128GCM").
9
- * @param options Configuration options for key generation.
10
- * @returns A Promise resolving to the generated key (CryptoKey, CryptoKeyPair, or Uint8Array) or its JWK representation.
5
+ * The return type is narrowed by `alg` and `options.toJWK`. When `toJWK` is not set
6
+ * (or is `false`):
7
+ *
8
+ * - **Symmetric algorithms** (`HS*`, `A*KW`, `A*GCM`, `A*GCMKW`) → `CryptoKey`. The key
9
+ * is imported with Web Crypto usages derived from the algorithm (e.g. `["sign", "verify"]`
10
+ * for HMAC, `["wrapKey", "unwrapKey"]` for AES-KW, `["encrypt", "decrypt"]` for AES-GCM).
11
+ * - **AES-CBC + HMAC composites** (`A128CBC-HS256`, `A192CBC-HS384`, `A256CBC-HS512`) →
12
+ * `Uint8Array`. These keys are returned as raw bytes because the composite layout
13
+ * (AES key ∥ HMAC key) is not directly importable via `crypto.subtle.importKey`. They
14
+ * are split internally during encrypt/decrypt.
15
+ * - **Asymmetric algorithms** (`RS*`, `PS*`, `ES*`, `RSA-OAEP*`, `Ed25519`, `EdDSA`,
16
+ * `ECDH-ES*`) → `CryptoKeyPair`.
17
+ *
18
+ * When `options.toJWK` is `true`, the same call returns a JWK / JWK pair instead, with
19
+ * a freshly generated `kid` attached (use {@link generateJWK} to customise `kid`,
20
+ * `use`, etc.). Composite AES-CBC+HMAC keys are serialised to a single `JWK_oct` and
21
+ * re-split internally on use.
22
+ *
23
+ * PBES2 is not a key-generation algorithm — use {@link deriveKeyFromPassword} or
24
+ * {@link deriveJWKFromPassword} instead.
25
+ *
26
+ * @param alg The JWA algorithm identifier (e.g. `"HS256"`, `"RS256"`, `"A128GCM"`,
27
+ * `"A256CBC-HS512"`). PBES2, `"dir"`, and `"none"` are not accepted.
28
+ * @param options
29
+ * - `toJWK?` — when `true`, return JWK / JWK pair instead of `CryptoKey` / `CryptoKeyPair`.
30
+ * - `extractable?` — forwarded to `crypto.subtle.generateKey`. Defaults to `true`.
31
+ * - `keyUsage?` — override the default usages derived from `alg`.
32
+ * - `modulusLength?` — RSA only; defaults to `2048`.
33
+ * - `publicExponent?` — RSA only; defaults to `0x010001`.
34
+ * - `namedCurve?` — EC and OKP only; defaults to `"P-256"` for EC and `"Ed25519"` for OKP.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * // HS256 → CryptoKey
39
+ * const hmac = await generateKey("HS256");
40
+ *
41
+ * // A256CBC-HS512 → Uint8Array (composite key)
42
+ * const cek = await generateKey("A256CBC-HS512");
43
+ *
44
+ * // RS256 → CryptoKeyPair
45
+ * const rsa = await generateKey("RS256", { modulusLength: 2048 });
46
+ *
47
+ * // As JWK pair
48
+ * const { privateKey, publicKey } = await generateKey("ES256", { toJWK: true });
49
+ * ```
11
50
  */
12
51
  declare function generateKey<TAlg extends GenerateKeyAlgorithm, TOptions extends GenerateKeyOptions>(alg: TAlg, options?: TOptions): Promise<GenerateKeyReturn<TAlg, TOptions>>;
13
52
  /**
14
- * Generates a Json Web Key (JWK) for the specified algorithm.
53
+ * Generates a ready-to-use JWK (or JWK pair) for the specified algorithm.
54
+ *
55
+ * Always returns JWK form with a `kid` attached — auto-generated via
56
+ * `crypto.randomUUID()` when not supplied. For a `CryptoKey` / `CryptoKeyPair`
57
+ * result instead, use {@link generateKey}. PBES2 is not a key-generation
58
+ * algorithm — use {@link deriveJWKFromPassword}.
59
+ *
60
+ * Composite AES-CBC+HMAC keys (`A128CBC-HS256`, `A192CBC-HS384`, `A256CBC-HS512`)
61
+ * are serialised to a single `JWK_oct` and re-split internally on use.
15
62
  *
16
- * @param alg The JWA algorithm identifier (e.g., "HS256", "RS256", "A128GCM").
17
- * @param jwkParams Optional partial JWK to merge with the generated key, allowing overrides.
18
- * @param options Configuration options for key generation.
19
- * @returns A Promise resolving to the generated JWK or JWK pair representation.
63
+ * @param alg The JWA algorithm identifier (e.g. `"HS256"`, `"RS256"`, `"ES256"`,
64
+ * `"A128GCM"`, `"A256CBC-HS512"`). PBES2, `"dir"`, and `"none"` are
65
+ * not accepted.
66
+ * @param options
67
+ * - `extractable?` — forwarded to `crypto.subtle.generateKey`. Defaults to `true`.
68
+ * - `keyUsage?` — override the default usages derived from `alg`.
69
+ * - `modulusLength?` — RSA only; defaults to `2048`.
70
+ * - `publicExponent?` — RSA only; defaults to `0x010001`.
71
+ * - `namedCurve?` — EC and OKP only; defaults to `"P-256"` for EC and `"Ed25519"` for OKP.
72
+ * - JWK metadata (`kid`, `use`, `x5c`, `x5t`, `x5t#S256`, `x5u`) is merged onto the
73
+ * result. `alg`, `kty`, `key_ops`, and `ext` are managed by the library and cannot
74
+ * be overridden here.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * // HS256 → JWK_oct
79
+ * const hmac = await generateJWK("HS256");
80
+ *
81
+ * // RS256 → { privateKey: JWK_RSA_Private; publicKey: JWK_RSA_Public }
82
+ * const rsa = await generateJWK("RS256", { modulusLength: 2048, kid: "rsa-1" });
83
+ *
84
+ * // ES256 with explicit metadata
85
+ * const { privateKey, publicKey } = await generateJWK("ES256", { kid: "ec-1", use: "sig" });
86
+ * ```
20
87
  */
21
- declare function generateJWK<TAlg extends GenerateKeyAlgorithm>(alg: TAlg, jwkParams?: Omit<JWKParameters, "alg" | "kty" | "key_ops" | "ext">, options?: GenerateJWKOptions): Promise<GenerateJWKReturn<TAlg>>;
88
+ declare function generateJWK<TAlg extends GenerateKeyAlgorithm>(alg: TAlg, options?: GenerateJWKOptions & Omit<JWKParameters, "alg" | "kty" | "key_ops" | "ext">): Promise<GenerateJWKReturn<TAlg>>;
22
89
  /**
23
90
  * Derives a key from a password using PBKDF2 as specified by PBES2 algorithms.
24
91
  *
@@ -29,15 +96,25 @@ declare function generateJWK<TAlg extends GenerateKeyAlgorithm>(alg: TAlg, jwkPa
29
96
  */
30
97
  declare function deriveKeyFromPassword<TAlg extends JWK_PBES2, TOptions extends DeriveKeyOptions>(password: string | Uint8Array<ArrayBuffer>, alg: TAlg, options: TOptions): Promise<DeriveKeyReturn<TOptions>>;
31
98
  /**
32
- * Derives a Json Web Key (JWK) from a password using PBKDF2 as specified by PBES2 algorithms.
99
+ * Derives a `JWK_oct` from a password using PBKDF2 as specified by PBES2
100
+ * (RFC 7518 §4.8). The resulting JWK's `alg` is the underlying AES-KW variant
101
+ * (`A128KW` / `A192KW` / `A256KW`), ready to use with {@link wrapKey} /
102
+ * {@link unwrapKey}.
33
103
  *
34
- * @param password The password to derive the key from (string or Uint8Array).
35
- * @param alg The PBES2 algorithm identifier (e.g., "PBES2-HS256+A128KW").
36
- * @param jwkParams Optional partial JWK to merge with the generated key, allowing overrides.
37
- * @param options Configuration options including salt and iterations.
38
- * @returns A Promise resolving to the derived JWK (JWK_oct).
104
+ * For a `CryptoKey` result without JWK metadata, use {@link deriveKeyFromPassword}.
105
+ *
106
+ * @param password The password to derive the key from (string or `Uint8Array`).
107
+ * @param alg The PBES2 algorithm identifier (e.g. `"PBES2-HS256+A128KW"`).
108
+ * @param options
109
+ * - `salt` — PBKDF2 salt input (`p2s`). Must be at least 8 octets (RFC 7518 §4.8.1.1).
110
+ * - `iterations` — PBKDF2 iteration count (`p2c`). Must be a positive integer.
111
+ * - `keyUsage?` — defaults to `["wrapKey", "unwrapKey"]`.
112
+ * - `extractable?` — forwarded to `crypto.subtle.importKey`. Defaults to `false`.
113
+ * - JWK metadata (`kid`, `use`, `x5c`, `x5t`, `x5t#S256`, `x5u`) is merged onto the
114
+ * result. `alg`, `kty`, `key_ops`, and `ext` are managed by the library and cannot
115
+ * be overridden here.
39
116
  */
40
- declare function deriveJWKFromPassword(password: string | Uint8Array<ArrayBuffer>, alg: JWK_PBES2, options: Omit<DeriveKeyOptions, "toJWK">, jwkParams?: Omit<JWKParameters, "alg" | "kty" | "key_ops" | "ext">): Promise<JWK_oct>;
117
+ declare function deriveJWKFromPassword(password: string | Uint8Array<ArrayBuffer>, alg: JWK_PBES2, options: Omit<DeriveKeyOptions, "toJWK"> & Omit<JWKParameters, "alg" | "kty" | "key_ops" | "ext">): Promise<JWK_oct>;
41
118
  /**
42
119
  * Default JWK import cache backed by a WeakMap.
43
120
  *
@@ -86,14 +163,21 @@ declare function clearJWKCache(): void;
86
163
  /**
87
164
  * Imports a key from various formats (CryptoKey, JWK, Uint8Array).
88
165
  *
89
- * - If `key` is a CryptoKey, it's returned directly.
90
- * - If `key` is a Uint8Array, it's returned directly.
91
- * - If `key` is a JWK_oct (symmetric key with 'k'), the raw key bytes are returned as Uint8Array.
92
- * - If `key` is any other JWK type (asymmetric), the `alg` parameter is required, and a CryptoKey is returned.
166
+ * - If `key` is a `CryptoKey`, it's returned directly.
167
+ * - If `key` is a `Uint8Array`, it's returned directly.
168
+ * - If `key` is a `JWK_oct` (symmetric key with `k`), the raw key bytes are returned as `Uint8Array`.
169
+ * - If `key` is any other JWK type (asymmetric), an algorithm hint is required (positional or via options)
170
+ * and a `CryptoKey` is returned.
171
+ *
172
+ * ### `expect` option (asymmetric only)
173
+ *
174
+ * Pass `expect: "public"` or `expect: "private"` to validate the caller's intent against the key's
175
+ * shape before the import. A private JWK passed with `expect: "public"` throws `ERR_JWK_INVALID`
176
+ * instead of silently importing the private material. Callers who deliberately want to drop private
177
+ * fields can do so themselves — no silent stripping.
93
178
  *
94
- * @param key The key to import.
95
- * @param alg The algorithm hint, required when importing asymmetric JWKs.
96
- * @returns A Promise resolving to the imported key as CryptoKey or Uint8Array.
179
+ * `expect` is a no-op for symmetric (`oct`) JWKs and for `CryptoKey` instances whose
180
+ * `algorithm.type` is `"secret"`.
97
181
  */
98
182
  declare function importKey(key: string): Promise<Uint8Array<ArrayBuffer>>;
99
183
  declare function importKey(key: Uint8Array<ArrayBuffer>): Promise<Uint8Array<ArrayBuffer>>;
@@ -105,6 +189,10 @@ declare function importKey(key: JWK_oct, options: {
105
189
  usage: KeyUsage[]; /** Mark the key as extractable. Defaults to `false`. */
106
190
  extractable?: boolean;
107
191
  }): Promise<CryptoKey>;
192
+ declare function importKey(key: CryptoKey | JWK | Uint8Array<ArrayBuffer> | string, options: {
193
+ /** Algorithm hint. Required when `key.alg` is absent on an asymmetric JWK. */alg?: string; /** Reject on shape mismatch instead of silently importing. */
194
+ expect?: "public" | "private";
195
+ }): Promise<CryptoKey | Uint8Array<ArrayBuffer>>;
108
196
  declare function importKey(key: CryptoKey | JWK | Uint8Array<ArrayBuffer> | string, alg?: string): Promise<CryptoKey | Uint8Array<ArrayBuffer>>;
109
197
  /**
110
198
  * Exports a CryptoKey to a JWK (JSON Web Key) format.
@@ -113,17 +201,19 @@ declare function importKey(key: CryptoKey | JWK | Uint8Array<ArrayBuffer> | stri
113
201
  * @param jwk Optional partial JWK to merge with the exported key, allowing overrides.
114
202
  * @returns A Promise resolving to the exported JWK.
115
203
  */
116
- declare function exportKey<T extends JWK>(key: CryptoKey, jwk?: Partial<JWK>): Promise<T>;
204
+ declare function exportKey<T extends JWK>(key: CryptoKey, jwkParams?: Omit<JWKParameters, "alg" | "kty" | "key_ops" | "ext">): Promise<T>;
117
205
  /**
118
206
  * Wraps a Content Encryption Key (CEK) using the specified algorithm and wrapping key.
119
207
  *
208
+ * The return shape is narrowed by `alg` — see {@link WrapKeyResult}.
209
+ *
120
210
  * @param alg The JWA key management algorithm (e.g., "A128KW", "RSA-OAEP", "PBES2-HS256+A128KW").
121
211
  * @param keyToWrap The key to be wrapped (CEK), typically a symmetric key as Uint8Array or CryptoKey.
122
212
  * @param wrappingKey The key used to wrap the CEK (CryptoKey, JWK, or password string/Uint8Array for PBES2).
123
213
  * @param options Additional options required by certain algorithms (e.g., p2s, p2c for PBES2).
124
- * @returns A Promise resolving to an object containing the wrapped key and any necessary parameters (iv, tag, epk, etc.).
214
+ * @returns A Promise resolving to an alg-specific {@link WrapKeyResult}.
125
215
  */
126
- declare function wrapKey(alg: KeyManagementAlgorithm, keyToWrap: CryptoKey | Uint8Array<ArrayBuffer>, wrappingKey: CryptoKey | JWK | string | Uint8Array<ArrayBuffer>, options?: WrapKeyOptions): Promise<WrapKeyResult>;
216
+ declare function wrapKey<TAlg extends KeyManagementAlgorithm>(alg: TAlg, keyToWrap: CryptoKey | Uint8Array<ArrayBuffer>, wrappingKey: CryptoKey | JWK | string | Uint8Array<ArrayBuffer>, options?: WrapKeyOptions): Promise<WrapKeyResult<TAlg>>;
127
217
  /**
128
218
  * Unwraps a Content Encryption Key (CEK) using the specified algorithm and unwrapping key.
129
219
  *
@@ -141,28 +231,95 @@ declare function unwrapKey(alg: KeyManagementAlgorithm, wrappedKey: Uint8Array<A
141
231
  }): Promise<CryptoKey>;
142
232
  declare function unwrapKey(alg: KeyManagementAlgorithm, wrappedKey: Uint8Array<ArrayBuffer>, unwrappingKey: CryptoKey | JWK | string | Uint8Array<ArrayBuffer>, options: UnwrapKeyOptions): Promise<CryptoKey | Uint8Array<ArrayBuffer>>;
143
233
  /**
144
- * Imports a key from a PEM-encoded string and converts it to a JWK.
234
+ * Imports a PEM-encoded key and returns it as a JWK.
235
+ *
236
+ * The PEM type is inferred from the `-----BEGIN <X>-----` label:
237
+ * - `PRIVATE KEY` → PKCS#8 private key (RFC 5208)
238
+ * - `PUBLIC KEY` → SubjectPublicKeyInfo public key (RFC 5280 §4.1.2.7)
239
+ * - `CERTIFICATE` → X.509 certificate; its SPKI is extracted into the JWK and all cert metadata
240
+ * (issuer, validity, extensions) is discarded — a JWK cannot represent it
241
+ *
242
+ * A caller can override the inference via `options.pemType`; the underlying label assertion
243
+ * still runs, so a mismatched override (e.g. `pemType: "pkcs8"` on a SPKI body) throws
244
+ * `ERR_JWK_INVALID` before any crypto work.
145
245
  *
146
246
  * @param pem The PEM-encoded string.
147
- * @param pemType The type of PEM encoding ('pkcs8' for private keys, 'spki' for public keys, 'x509' for certificates).
148
- * @param alg The JWA algorithm identifier. This is crucial for `crypto.subtle.importKey`
149
- * to understand the key's intended algorithm and for setting the 'alg' field in the resulting JWK.
150
- * @param importOptions Options for the PEM import process (e.g., extractable for the CryptoKey).
151
- * @param jwkExtras Additional properties to merge into the resulting JWK.
152
- * @returns A Promise resolving to the imported key as a JWK.
247
+ * @param alg The JWA algorithm identifier. Required for `crypto.subtle.importKey` to understand
248
+ * the key's intended algorithm and for setting the `alg` field on the resulting JWK.
249
+ * @param options
250
+ * - `pemType?` — explicit PEM type; inferred from the label when omitted.
251
+ * - `extractable?` — forwarded to `crypto.subtle.importKey`. Defaults to `false` for private
252
+ * keys and `true` for public keys.
253
+ * - `jwkParams?` — additional JWK properties merged into the result (e.g. `kid`, `use`).
254
+ * `alg`, `kty`, `key_ops`, and `ext` are reserved and cannot be overridden here.
255
+ * @throws `JWTError("ERR_JWK_INVALID")` if the PEM type cannot be inferred (no recognised label
256
+ * and no `options.pemType`), or if the label does not match the requested/inferred type.
257
+ * @throws `JWTError("ERR_JWK_UNSUPPORTED")` if `options.pemType` is a value outside the supported set.
258
+ *
259
+ * @example
260
+ * ```ts
261
+ * // Inferred — label on the PEM drives selection.
262
+ * const jwk = await importPEM(pemString, "RS256", { jwkParams: { kid: "rsa-1" } });
263
+ *
264
+ * // Explicit override.
265
+ * const jwk2 = await importPEM(pemString, "RS256", { pemType: "x509" });
266
+ * ```
267
+ */
268
+ declare function importPEM<T extends JWK>(pem: string, alg: JWKPEMAlgorithm, options?: {
269
+ /** PEM type. Inferred from the PEM label when omitted. */pemType?: "pkcs8" | "spki" | "x509"; /** Passed to `crypto.subtle.importKey`. Defaults to `false` for private keys, `true` otherwise. */
270
+ extractable?: boolean; /** Additional JWK properties merged into the exported key (e.g. `kid`). */
271
+ jwkParams?: Omit<JWKParameters, "alg" | "kty" | "key_ops" | "ext">;
272
+ }): Promise<T>;
273
+ /**
274
+ * @deprecated Use {@link importPEM} instead. `pemType` has moved into the options object and
275
+ * is now inferred from the PEM label by default.
153
276
  */
154
277
  declare function importFromPEM<T extends JWK>(pem: string, pemType: "pkcs8" | "spki" | "x509", alg: JWKPEMAlgorithm, options?: {
155
- /** Passed to `crypto.subtle.importKey`. Defaults to `false` for private keys, `true` otherwise. */extractable?: boolean; /** Additional JWK properties merged into the exported key (e.g. `kid`). */
278
+ extractable?: boolean;
156
279
  jwkParams?: Omit<JWKParameters, "alg" | "kty" | "key_ops" | "ext">;
157
280
  }): Promise<T>;
158
281
  /**
159
282
  * Exports a JWK to a PEM-encoded string.
160
283
  *
161
- * @param jwk The JWK to export.
162
- * @param pemFormat The desired PEM format ('pkcs8' for private keys, 'spki' for public keys).
163
- * @param algForCryptoKeyImport If the JWK does not have an 'alg' property, this algorithm hint is
164
- * required to correctly convert it to a CryptoKey first.
165
- * @returns A Promise resolving to the PEM-encoded key string.
284
+ * The PEM format is inferred from the JWK shape:
285
+ * - JWK with `d` (private component) → PKCS#8 (`-----BEGIN PRIVATE KEY-----`)
286
+ * - JWK without `d` → SubjectPublicKeyInfo (`-----BEGIN PUBLIC KEY-----`)
287
+ *
288
+ * X.509 certificate export is intentionally not supported: a certificate carries metadata
289
+ * (subject/issuer DNs, validity window, extensions) and a CA signature that a JWK cannot provide.
290
+ * Producing a cert is a CA operation, not a key-format conversion.
291
+ *
292
+ * Symmetric `oct` JWKs cannot be exported to PEM — PKCS#8/SPKI are asymmetric-key formats.
293
+ *
294
+ * @param jwk The JWK to export. Must not be `kty: "oct"`.
295
+ * @param options
296
+ * - `pemFormat?` — force the output format. Inferred from the JWK shape when omitted.
297
+ * - `alg?` — algorithm hint used only when `jwk.alg` is absent (both `kty: "RSA"` / `"EC"` /
298
+ * `"OKP"` JWKs need an algorithm to be round-tripped through `crypto.subtle.importKey`).
299
+ * @throws `JWTError("ERR_JWK_UNSUPPORTED")` for `oct` JWKs, or an unrecognised `pemFormat`.
300
+ * @throws `JWTError("ERR_JWK_INVALID")` if the JWK requires an `alg` hint that was not supplied,
301
+ * or if `pemFormat` is forced to a value incompatible with the JWK's public/private shape.
302
+ *
303
+ * @example
304
+ * ```ts
305
+ * // Inferred — private JWKs become PKCS#8, public JWKs become SPKI.
306
+ * const pem = await exportPEM(jwk);
307
+ *
308
+ * // Override (will throw if incompatible with the JWK shape).
309
+ * const spki = await exportPEM(jwk, { pemFormat: "spki" });
310
+ *
311
+ * // JWK without `alg` — provide a hint.
312
+ * const pem2 = await exportPEM(rawJwk, { alg: "RS256" });
313
+ * ```
314
+ */
315
+ declare function exportPEM(jwk: JWK, options?: {
316
+ /** PEM format. Inferred from the JWK shape when omitted. */pemFormat?: "pkcs8" | "spki"; /** Algorithm hint used when `jwk.alg` is absent. */
317
+ alg?: JWKPEMAlgorithm;
318
+ }): Promise<string>;
319
+ /**
320
+ * @deprecated Use {@link exportPEM} instead. `pemFormat` has moved into the options object and
321
+ * is now inferred from the JWK shape by default. The `algForCryptoKeyImport` parameter has
322
+ * been renamed to `options.alg`.
166
323
  */
167
324
  declare function exportToPEM(jwk: JWK, pemFormat: "pkcs8" | "spki", algForCryptoKeyImport?: JWKPEMAlgorithm): Promise<string>;
168
325
  /**
@@ -227,5 +384,4 @@ declare function getJWKFromSet(jwkSet: JWKSet, kidOrProtectedHeader: string | (J
227
384
  * @returns An array of matching JWKs.
228
385
  */
229
386
  declare function getJWKsFromSet(jwkSet: JWKSet, filter?: (jwk: JWK) => boolean): JWK[];
230
- //#endregion
231
- export { CompositeKey, ContentEncryptionAlgorithm, DeriveKeyOptions, DeriveKeyReturn, GenerateJWKOptions, GenerateJWKReturn, GenerateKeyAlgorithm, GenerateKeyOptions, GenerateKeyReturn, JWK, JWKAlgorithm, JWKCacheAdapter, JWKLookupFunction, JWKLookupFunctionHeader, JWKPEMAlgorithm, JWKParameters, JWKSet, JWK_AES_CBC_HMAC, JWK_AES_GCM, JWK_AES_GCM_KW, JWK_AES_KW, JWK_Asymmetric, JWK_Asymmetric_Algorithm, JWK_EC, JWK_ECDH_ES, JWK_ECDSA, JWK_EC_Private, JWK_EC_Public, JWK_HMAC, JWK_OKP, JWK_OKP_Private, JWK_OKP_Public, JWK_OKP_SIGN, JWK_PBES2, JWK_Pair, JWK_Private, JWK_Public, JWK_RSA, JWK_RSA_ENC, JWK_RSA_PSS, JWK_RSA_Private, JWK_RSA_Public, JWK_RSA_SIGN, JWK_Symmetric, JWK_Symmetric_Algorithm, JWK_oct, JWTError, type JWTErrorCauseMap, type JWTErrorCode, KeyManagementAlgorithm, UnwrapKeyOptions, WeakMapJWKCache, WrapKeyOptions, WrapKeyResult, clearJWKCache, configureJWKCache, deriveJWKFromPassword, deriveKeyFromPassword, deriveSharedSecret, exportKey, exportToPEM, generateJWK, generateKey, getJWKFromSet, getJWKsFromSet, importFromPEM, importKey, isJWTError, unwrapKey, wrapKey };
387
+ export { CompositeKey, ContentEncryptionAlgorithm, DeriveKeyOptions, DeriveKeyReturn, GenerateJWKOptions, GenerateJWKReturn, GenerateKeyAlgorithm, GenerateKeyOptions, GenerateKeyReturn, JWK, JWKAlgorithm, JWKCacheAdapter, JWKLookupFunction, JWKLookupFunctionHeader, JWKPEMAlgorithm, JWKParameters, JWKSet, JWK_AES_CBC_HMAC, JWK_AES_GCM, JWK_AES_GCM_KW, JWK_AES_KW, JWK_Asymmetric, JWK_Asymmetric_Algorithm, JWK_EC, JWK_ECDH_ES, JWK_ECDSA, JWK_EC_Private, JWK_EC_Public, JWK_HMAC, JWK_OKP, JWK_OKP_Private, JWK_OKP_Public, JWK_OKP_SIGN, JWK_PBES2, JWK_Pair, JWK_Private, JWK_Public, JWK_RSA, JWK_RSA_ENC, JWK_RSA_PSS, JWK_RSA_Private, JWK_RSA_Public, JWK_RSA_SIGN, JWK_Symmetric, JWK_Symmetric_Algorithm, JWK_oct, JWTError, type JWTErrorCauseMap, type JWTErrorCode, KeyManagementAlgorithm, UnwrapKeyOptions, WeakMapJWKCache, WrapKeyOptions, WrapKeyResult, clearJWKCache, configureJWKCache, deriveJWKFromPassword, deriveKeyFromPassword, deriveSharedSecret, exportKey, exportPEM, exportToPEM, generateJWK, generateKey, getJWKFromSet, getJWKsFromSet, importFromPEM, importKey, importPEM, isJWTError, unwrapKey, wrapKey };