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.
@@ -1,4 +1,3 @@
1
- //#region src/core/types/jwk.d.ts
2
1
  /**
3
2
  * The decoded JOSE protected header received by a {@link JWKLookupFunction}.
4
3
  *
@@ -81,9 +80,15 @@ interface GenerateKeyOptions {
81
80
  type GenerateKeyReturnJWK<TAlg extends GenerateKeyAlgorithm> = TAlg extends JWK_Asymmetric_Algorithm ? TAlg extends JWK_RSA_SIGN | JWK_RSA_PSS | JWK_RSA_ENC ? {
82
81
  privateKey: JWK_RSA_Private;
83
82
  publicKey: JWK_RSA_Public;
84
- } : TAlg extends JWK_ECDSA | JWK_ECDH_ES ? {
83
+ } : TAlg extends JWK_ECDSA ? {
85
84
  privateKey: JWK_EC_Private;
86
85
  publicKey: JWK_EC_Public;
86
+ } : TAlg extends JWK_ECDH_ES ? {
87
+ privateKey: JWK_EC_Private;
88
+ publicKey: JWK_EC_Public;
89
+ } | {
90
+ privateKey: JWK_OKP_Private;
91
+ publicKey: JWK_OKP_Public;
87
92
  } : TAlg extends JWK_OKP_SIGN ? {
88
93
  privateKey: JWK_OKP_Private;
89
94
  publicKey: JWK_OKP_Public;
@@ -140,25 +145,31 @@ interface WrapKeyOptions {
140
145
  enc?: ContentEncryptionAlgorithm;
141
146
  };
142
147
  }
143
- /** Result of the wrapKey function. */
144
- interface WrapKeyResult {
145
- /** The wrapped key (Ciphertext). */
146
- encryptedKey: Uint8Array<ArrayBuffer>;
147
- /** Initialization Vector used (only for AES-GCMKW). Base64URL encoded. */
148
- iv?: string;
149
- /** Authentication Tag generated (only for AES-GCMKW). Base64URL encoded. */
150
- tag?: string;
151
- /** PBES2 Salt value used (only for PBES2). Base64URL encoded. */
152
- p2s?: string;
153
- /** PBES2 Iteration count used (only for PBES2). */
154
- p2c?: number;
155
- /** ECDH-ES Ephemeral Public Key used (only for ECDH-ES). */
156
- epk?: JWK_EC_Public;
157
- /** ECDH-ES Agreement PartyUInfo used (only for ECDH-ES). Base64URL encoded. */
158
- apu?: string;
159
- /** ECDH-ES Agreement PartyVInfo used (only for ECDH-ES). Base64URL encoded. */
148
+ /**
149
+ * Result of {@link wrapKey}, discriminated by key management algorithm family.
150
+ *
151
+ * Narrow the shape by passing a literal `alg` to `wrapKey`:
152
+ * - PBES2 → `{ encryptedKey, p2s, p2c }`
153
+ * - AES-GCMKW → `{ encryptedKey, iv, tag }`
154
+ * - ECDH-ES / ECDH-ES+A*KW → `{ encryptedKey, epk, apu?, apv? }`
155
+ * - dir / AES-KW / RSA-OAEP → `{ encryptedKey }`
156
+ */
157
+ type WrapKeyResult<TAlg extends KeyManagementAlgorithm = KeyManagementAlgorithm> = TAlg extends JWK_PBES2 ? {
158
+ encryptedKey: Uint8Array<ArrayBuffer>; /** PBES2 Salt value (p2s). Base64URL encoded. */
159
+ p2s: string; /** PBES2 Iteration count (p2c). */
160
+ p2c: number;
161
+ } : TAlg extends JWK_AES_GCM_KW ? {
162
+ encryptedKey: Uint8Array<ArrayBuffer>; /** AES-GCMKW Initialization Vector. Base64URL encoded. */
163
+ iv: string; /** AES-GCMKW Authentication Tag. Base64URL encoded. */
164
+ tag: string;
165
+ } : TAlg extends JWK_ECDH_ES ? {
166
+ encryptedKey: Uint8Array<ArrayBuffer>; /** Ephemeral Public Key. */
167
+ epk: JWK_EC_Public; /** Agreement PartyUInfo. Base64URL encoded. Present only when supplied. */
168
+ apu?: string; /** Agreement PartyVInfo. Base64URL encoded. Present only when supplied. */
160
169
  apv?: string;
161
- }
170
+ } : {
171
+ encryptedKey: Uint8Array<ArrayBuffer>;
172
+ };
162
173
  /** Options for the unwrapKey function. */
163
174
  interface UnwrapKeyOptions {
164
175
  /**
@@ -176,6 +187,10 @@ interface UnwrapKeyOptions {
176
187
  p2s?: Uint8Array<ArrayBuffer> | string;
177
188
  /** PBES2 Iteration count (required for PBES2). */
178
189
  p2c?: number;
190
+ /** Minimum accepted PBES2 `p2c` on unwrap. Defaults to 1000 (RFC 7518 §4.8.1.2). */
191
+ minIterations?: number;
192
+ /** Maximum accepted PBES2 `p2c` on unwrap. Defaults to 1_000_000 to cap PBKDF2 DoS potential. */
193
+ maxIterations?: number;
179
194
  /** ECDH-ES Ephemeral Public Key (required for ECDH-ES). */
180
195
  epk?: JWK_EC_Public | CryptoKey;
181
196
  /** ECDH-ES Agreement PartyUInfo. Base64URL encoded or Uint8Array. */
@@ -345,8 +360,6 @@ type JWK_Symmetric_Algorithm = JWK_HMAC | JWK_AES_KW | JWK_AES_GCM | JWK_AES_GCM
345
360
  type JWK_Asymmetric_Algorithm = JWK_RSA_SIGN | JWK_RSA_PSS | JWK_ECDSA | JWK_RSA_ENC | JWK_OKP_SIGN | JWK_ECDH_ES;
346
361
  type JWKAlgorithm = JWK_Symmetric_Algorithm | JWK_Asymmetric_Algorithm | JWK_AES_CBC_HMAC | JWK_PBES2 | JWK_ECDH_ES | "dir";
347
362
  type JWKPEMAlgorithm = JWK_RSA_PSS | JWK_RSA_SIGN | JWK_RSA_ENC | JWK_ECDSA | JWK_ECDH_ES | JWK_OKP_SIGN;
348
- //#endregion
349
- //#region src/core/types/jwt.d.ts
350
363
  /** Header Parameters common to JWE and JWS */
351
364
  interface JoseHeaderParameters {
352
365
  /** "kid" (Key ID) Header Parameter */
@@ -412,7 +425,11 @@ interface JWTClaimValidationOptions {
412
425
  subject?: string;
413
426
  /** Maximum token age, from the JWT "iat" (Issued At) Claim value. Implies presence requirement. */
414
427
  maxTokenAge?: MaxTokenAge;
415
- /** Clock skew tolerance (in seconds) for validating time-based claims (nbf/exp/iat). */
428
+ /**
429
+ * Clock skew tolerance (in seconds) for validating time-based claims (nbf/exp/iat).
430
+ *
431
+ * @default 0
432
+ */
416
433
  clockTolerance?: number;
417
434
  /** Expected JWT "typ" (Type) Header Parameter value. Implies presence requirement. */
418
435
  typ?: string;
@@ -428,8 +445,71 @@ interface JWTClaimValidationOptions {
428
445
  */
429
446
  recognizedHeaders?: string[];
430
447
  }
431
- //#endregion
432
- //#region src/core/types/jws.d.ts
448
+ /**
449
+ * All known error codes thrown by unjwt.
450
+ *
451
+ * Code naming follows the JOSE spec hierarchy:
452
+ * ERR_JWT_* — RFC 7519 JSON Web Token claim validation
453
+ * ERR_JWS_* — RFC 7515 JSON Web Signature
454
+ * ERR_JWE_* — RFC 7516 JSON Web Encryption
455
+ * ERR_JWK_* — RFC 7517 JSON Web Key
456
+ */
457
+ type JWTErrorCode = "ERR_JWT_EXPIRED" | "ERR_JWT_NBF" | "ERR_JWT_CLAIM_INVALID" | "ERR_JWT_CLAIM_MISSING" | "ERR_JWS_INVALID" | "ERR_JWS_INVALID_SERIALIZATION" | "ERR_JWS_SIGNATURE_INVALID" | "ERR_JWS_ALG_NOT_ALLOWED" | "ERR_JWS_ALG_MISSING" | "ERR_JWS_SIGNER_ALG_INFERENCE" | "ERR_JWS_NO_MATCHING_SIGNER" | "ERR_JWS_HEADER_PARAMS_NOT_DISJOINT" | "ERR_JWS_B64_INCONSISTENT" | "ERR_JWE_INVALID" | "ERR_JWE_INVALID_SERIALIZATION" | "ERR_JWE_DECRYPTION_FAILED" | "ERR_JWE_ALG_NOT_ALLOWED" | "ERR_JWE_ALG_MISSING" | "ERR_JWE_ALG_FORBIDDEN_IN_MULTI" | "ERR_JWE_ENC_MISSING" | "ERR_JWE_RECIPIENT_ALG_INFERENCE" | "ERR_JWE_NO_MATCHING_RECIPIENT" | "ERR_JWE_HEADER_PARAMS_NOT_DISJOINT" | "ERR_JWK_INVALID" | "ERR_JWK_KEY_NOT_FOUND" | "ERR_JWK_UNSUPPORTED" | (string & {});
458
+ /**
459
+ * Maps known error codes to their structured `cause` shapes.
460
+ * Only codes that carry decoded context beyond the message appear here.
461
+ * Extend this interface when new structured causes are introduced.
462
+ */
463
+ interface JWTErrorCauseMap {
464
+ /** Decoded claims available at the point the lifetime check failed. */
465
+ ERR_JWT_EXPIRED: {
466
+ jti?: string;
467
+ iat?: number;
468
+ exp?: number;
469
+ };
470
+ }
471
+ /**
472
+ * Base error class for all unjwt errors. Every error thrown by the library is
473
+ * an instance of `JWTError`, so a single `instanceof` check is sufficient to
474
+ * distinguish library errors from other thrown values. Use the `code` property
475
+ * (or the `isJWTError` type guard) to narrow to a specific error condition.
476
+ *
477
+ * @example
478
+ * import { JWTError, isJWTError } from "unjwt/jws";
479
+ *
480
+ * try {
481
+ * await verify(token, key);
482
+ * } catch (err) {
483
+ * if (isJWTError(err, "ERR_JWT_EXPIRED")) {
484
+ * console.log(err.cause.jti); // string | undefined
485
+ * }
486
+ * }
487
+ */
488
+ declare class JWTError<TCode extends JWTErrorCode = JWTErrorCode> extends Error {
489
+ readonly code: TCode;
490
+ override readonly cause?: unknown;
491
+ constructor(message: string, code: TCode, cause?: unknown);
492
+ }
493
+ /**
494
+ * Type guard that narrows `error` to `JWTError`.
495
+ *
496
+ * When called with a code that is a key of `JWTErrorCauseMap`, the return
497
+ * type is additionally narrowed to include the structured `cause` shape for
498
+ * that code. When called with any other `JWTErrorCode`, `code` is narrowed
499
+ * but `cause` remains `unknown`. When called without a code, narrows only to
500
+ * `JWTError`.
501
+ *
502
+ * @example
503
+ * if (isJWTError(err, "ERR_JWT_EXPIRED")) {
504
+ * err.cause.jti // string | undefined ✓
505
+ * }
506
+ */
507
+ declare function isJWTError<T extends keyof JWTErrorCauseMap>(error: unknown, code: T): error is JWTError<T> & {
508
+ cause: JWTErrorCauseMap[T];
509
+ };
510
+ declare function isJWTError<T extends JWTErrorCode>(error: unknown, code: T): error is JWTError<T>;
511
+ declare function isJWTError(error: unknown): error is JWTError;
512
+ type StrictOmit<T, K extends keyof T | (string & {}) | (number & {}) | (symbol & {})> = { [P in keyof T as P extends K ? never : P]: T[P] };
433
513
  /** JWS Signing Algorithm Identifier. */
434
514
  type JWSAlgorithm = JWK_HMAC | JWK_RSA_SIGN | JWK_RSA_PSS | JWK_ECDSA | JWK_OKP_SIGN;
435
515
  /** Recognized JWS Header Parameters, any other Header Members may also be present. */
@@ -455,16 +535,45 @@ interface JWSSignOptions {
455
535
  /** The JWS Algorithm to use. Must be provided. */
456
536
  alg?: JWSAlgorithm;
457
537
  /**
458
- * Additional protected header parameters. `alg` is automatically included.
459
- * `typ` defaults to "JWT" if not provided and payload is an object.
538
+ * Additional protected header parameters. `alg` is always derived from the top-level `alg`
539
+ * option (or inferred from the key) and cannot be overridden. `typ` defaults to `"JWT"`
540
+ * when the payload is a JSON object.
460
541
  */
461
- protectedHeader?: JWSHeaderParameters;
542
+ protectedHeader?: StrictOmit<JWSHeaderParameters, "alg"> & {
543
+ alg?: never;
544
+ };
462
545
  /** Date to use when comparing NumericDate claims, defaults to `new Date()`. */
463
546
  currentDate?: Date;
464
547
  /**
465
- * Time at which the JWS should expire, if no `exp` was already provided.
548
+ * Duration until the JWS should expire, relative to `currentDate` (or `new Date()`).
549
+ * Skipped when the payload already carries an `exp` claim.
550
+ *
551
+ * Mutually exclusive with {@link expiresAt}.
466
552
  */
467
553
  expiresIn?: ExpiresIn;
554
+ /**
555
+ * Absolute moment at which the JWS should expire (sets the `exp` claim directly).
556
+ * Skipped when the payload already carries an `exp` claim.
557
+ *
558
+ * Mutually exclusive with {@link expiresIn}.
559
+ */
560
+ expiresAt?: Date;
561
+ /**
562
+ * Duration from `iat` before which the JWS must not be accepted.
563
+ * `0` is allowed and sets `nbf = iat` (explicit temporal floor at sign time).
564
+ * Skipped when the payload already carries an `nbf` claim.
565
+ *
566
+ * Mutually exclusive with {@link notBeforeAt}.
567
+ */
568
+ notBeforeIn?: ExpiresIn;
569
+ /**
570
+ * Absolute moment before which the JWS must not be accepted (sets the `nbf`
571
+ * claim directly per RFC 7519 §4.1.5). Skipped when the payload already
572
+ * carries an `nbf` claim.
573
+ *
574
+ * Mutually exclusive with {@link notBeforeIn}.
575
+ */
576
+ notBeforeAt?: Date;
468
577
  }
469
578
  /** Result of JWS verification */
470
579
  interface JWSVerifyResult<T extends JOSEPayload = JOSEPayload> {
@@ -488,11 +597,119 @@ interface JWSVerifyOptions extends JWTClaimValidationOptions {
488
597
  */
489
598
  validateClaims?: boolean;
490
599
  }
491
- //#endregion
492
- //#region src/core/utils/types.d.ts
493
- type StrictOmit<T, K extends keyof T | (string & {}) | (number & {}) | (symbol & {})> = { [P in keyof T as P extends K ? never : P]: T[P] };
494
- //#endregion
495
- //#region src/core/types/jwe.d.ts
600
+ /**
601
+ * JWS Flattened JSON Serialization, RFC 7515 §7.2.2. Accepted as input by
602
+ * {@link verifyMulti} and normalized to {@link JWSGeneralSerialization}
603
+ * internally. Emitted by {@link generalToFlattenedJWS} on a single-signature
604
+ * General serialization.
605
+ */
606
+ interface JWSFlattenedSerialization {
607
+ /** The JWS Payload. base64url-encoded when `b64 !== false`. */
608
+ payload: string;
609
+ /** Base64URL-encoded JWS Protected Header (part of the signing input). */
610
+ protected?: string;
611
+ /** JWS Unprotected Header (not part of the signing input). */
612
+ header?: JWSHeaderParameters;
613
+ /** Base64URL-encoded signature bytes. */
614
+ signature: string;
615
+ }
616
+ /**
617
+ * JWS General JSON Serialization, RFC 7515 §7.2.1. Canonical multi-signature
618
+ * output shape of {@link signMulti}.
619
+ *
620
+ * `payload` is shared across all signatures and carries base64url-encoded
621
+ * bytes by default. When the consistent `b64: false` signing mode is used
622
+ * (RFC 7797), `payload` holds the raw UTF-8 payload string instead.
623
+ */
624
+ interface JWSGeneralSerialization extends Omit<JWSFlattenedSerialization, "protected" | "header" | "signature"> {
625
+ /** One entry per signer. */
626
+ signatures: JWSGeneralSignature[];
627
+ }
628
+ /** A single signature entry within {@link JWSGeneralSerialization.signatures}. */
629
+ type JWSGeneralSignature = Pick<JWSFlattenedSerialization, "protected" | "header" | "signature">;
630
+ /**
631
+ * Input shape for a single signer passed to {@link signMulti}.
632
+ *
633
+ * `alg` is inferred from `key.alg`; throws `ERR_JWS_SIGNER_ALG_INFERENCE`
634
+ * when absent. `kid` is pulled from `key.kid` when present.
635
+ */
636
+ interface JWSMultiSigner {
637
+ /** Signing key (JWK-first; `alg` inferred from `key.alg`). */
638
+ key: JWK;
639
+ /**
640
+ * Extra per-signer JWS Protected Header parameters (RFC 7515 §7.2.1).
641
+ * `alg` is always derived from the JWK and cannot be set here. `b64`
642
+ * MUST be consistent across every signer (RFC 7797 §3) — if set on one
643
+ * signer it must match on all.
644
+ */
645
+ protectedHeader?: StrictOmit<JWSHeaderParameters, "alg"> & {
646
+ alg?: never;
647
+ };
648
+ /** Per-signer JWS Unprotected Header (not part of signing input). */
649
+ unprotectedHeader?: JWSHeaderParameters;
650
+ }
651
+ /**
652
+ * Options for {@link signMulti}. Mirrors {@link JWSSignOptions} minus the
653
+ * per-signer fields (`alg`, `protectedHeader` — set those on each
654
+ * {@link JWSMultiSigner} instead).
655
+ */
656
+ interface JWSMultiSignOptions extends StrictOmit<JWSSignOptions, "alg" | "protectedHeader"> {}
657
+ /** Options for {@link verifyMulti}. Extends {@link JWSVerifyOptions}. */
658
+ interface JWSMultiVerifyOptions extends JWSVerifyOptions {
659
+ /**
660
+ * When `false` (default), verification trials signatures in order — mirrors
661
+ * the multi-key retry behaviour of {@link verify} against a JWK Set. When
662
+ * `true`, only signatures whose header unambiguously matches the provided
663
+ * key (by `kid`, then by `kty`/`crv`/length) are attempted, and any
664
+ * mismatch throws `ERR_JWS_NO_MATCHING_SIGNER` before any crypto work.
665
+ */
666
+ strictSignerMatch?: boolean;
667
+ }
668
+ /**
669
+ * Result of a {@link verifyMulti} operation. Extends {@link JWSVerifyResult}
670
+ * with the per-signer header and matched signature index.
671
+ */
672
+ interface JWSMultiVerifyResult<T extends JOSEPayload = JOSEPayload> extends JWSVerifyResult<T> {
673
+ /** Parsed per-signer unprotected header of the signature that verified. */
674
+ signerHeader?: JWSHeaderParameters;
675
+ /** Index into `jws.signatures` of the signature that successfully verified. */
676
+ signerIndex: number;
677
+ }
678
+ /**
679
+ * Options for {@link verifyMultiAll}. Inherits the same validation knobs as
680
+ * {@link JWSMultiVerifyOptions} minus `strictSignerMatch` (not meaningful when
681
+ * every signature is independently reported).
682
+ */
683
+ interface JWSMultiVerifyAllOptions extends StrictOmit<JWSMultiVerifyOptions, "strictSignerMatch"> {}
684
+ /**
685
+ * Per-signature outcome collected by {@link verifyMultiAll}. Discriminated by
686
+ * `verified`:
687
+ *
688
+ * - `verified: true` — the signature cryptographically verified and any
689
+ * claim/`crit` validation the caller asked for also passed. `payload` is
690
+ * provided.
691
+ * - `verified: false` — verification could not be completed for this
692
+ * signature. `error` carries the {@link JWTError} reason (signature
693
+ * invalid, disallowed alg, `typ` mismatch, key-resolver failure, malformed
694
+ * protected header, expired claim, etc.). `protectedHeader` / `signerHeader`
695
+ * are populated when they were successfully parsed before failure.
696
+ *
697
+ * Callers apply their own policy over the returned array — e.g. "all must
698
+ * verify", "quorum of N", "signed by these specific kids".
699
+ */
700
+ type JWSMultiVerifyOutcome<T extends JOSEPayload = JOSEPayload> = {
701
+ signerIndex: number;
702
+ verified: true;
703
+ payload: T;
704
+ protectedHeader: JWSProtectedHeader;
705
+ signerHeader?: JWSHeaderParameters;
706
+ } | {
707
+ signerIndex: number;
708
+ verified: false;
709
+ error: JWTError;
710
+ protectedHeader?: JWSProtectedHeader;
711
+ signerHeader?: JWSHeaderParameters;
712
+ };
496
713
  /** Recognized JWE Header Parameters, any other Header Members may also be present. */
497
714
  interface JWEHeaderParameters extends JoseHeaderParameters {
498
715
  /**
@@ -569,8 +786,36 @@ interface JWEEncryptOptions {
569
786
  enc?: ContentEncryptionAlgorithm;
570
787
  /** Date to use when computing NumericDate claims, defaults to `new Date()`. */
571
788
  currentDate?: Date;
572
- /** Time at which the JWT should expire, if no `exp` was already provided (only when typ is "JWT" or explicitly parsing JWT). */
789
+ /**
790
+ * Duration until the JWT should expire, relative to `currentDate` (or `new Date()`).
791
+ * Skipped when the payload already carries an `exp` claim.
792
+ *
793
+ * Mutually exclusive with {@link expiresAt}.
794
+ */
573
795
  expiresIn?: ExpiresIn;
796
+ /**
797
+ * Absolute moment at which the JWT should expire (sets the `exp` claim directly).
798
+ * Skipped when the payload already carries an `exp` claim.
799
+ *
800
+ * Mutually exclusive with {@link expiresIn}.
801
+ */
802
+ expiresAt?: Date;
803
+ /**
804
+ * Duration from `iat` before which the JWT must not be accepted.
805
+ * `0` is allowed and sets `nbf = iat` (explicit temporal floor at sign time).
806
+ * Skipped when the payload already carries an `nbf` claim.
807
+ *
808
+ * Mutually exclusive with {@link notBeforeAt}.
809
+ */
810
+ notBeforeIn?: ExpiresIn;
811
+ /**
812
+ * Absolute moment before which the JWT must not be accepted (sets the `nbf`
813
+ * claim directly per RFC 7519 §4.1.5). Skipped when the payload already
814
+ * carries an `nbf` claim.
815
+ *
816
+ * Mutually exclusive with {@link notBeforeIn}.
817
+ */
818
+ notBeforeAt?: Date;
574
819
  /** Additional JWE Protected Header parameters. */
575
820
  protectedHeader?: StrictOmit<JWEHeaderParameters, "alg" | "enc" | "iv" | "tag" | "p2s" | "p2c" | "epk" | "apu" | "apv">;
576
821
  /** Initialization Vector for AES-GCMKW key wrapping. Generated if not provided. */
@@ -629,6 +874,10 @@ interface JWEDecryptOptions extends JWTClaimValidationOptions {
629
874
  validateClaims?: boolean;
630
875
  /** If true, include the Content Encryption Key (CEK) and Additional Authenticated Data (AAD) in the result. */
631
876
  returnCek?: boolean;
877
+ /** Minimum accepted PBES2 `p2c` on unwrap. Defaults to 1000 (RFC 7518 §4.8.1.2). */
878
+ minIterations?: number;
879
+ /** Maximum accepted PBES2 `p2c` on unwrap. Defaults to 1_000_000 to cap PBKDF2 DoS potential. */
880
+ maxIterations?: number;
632
881
  }
633
882
  /**
634
883
  * JWE Protected Header — the parsed and validated protected header returned
@@ -654,9 +903,120 @@ interface JWEDecryptResult<T extends JOSEPayload = JOSEPayload> {
654
903
  /** The Additional Authenticated Data (AAD) used, as Uint8Array. Only present when `returnCek` is true. */
655
904
  aad?: Uint8Array<ArrayBuffer>;
656
905
  }
657
- //#endregion
658
- //#region src/core/types/index.d.ts
659
- type ExpiresIn = number | `${number}` | `${number}${"s" | "second" | "seconds" | "m" | "minute" | "minutes" | "h" | "hour" | "hours" | "D" | "day" | "days" | "W" | "week" | "weeks" | "M" | "month" | "months" | "Y" | "year" | "years"}`;
660
- type MaxTokenAge = ExpiresIn;
661
- //#endregion
662
- export { JWK_OKP_SIGN as $, JWK as A, JWK_AES_GCM_KW as B, DeriveKeyOptions as C, GenerateKeyAlgorithm as D, GenerateJWKReturn as E, JWKPEMAlgorithm as F, JWK_ECDH_ES as G, JWK_Asymmetric as H, JWKParameters as I, JWK_EC_Public as J, JWK_ECDSA as K, JWKSet as L, JWKCacheAdapter as M, JWKLookupFunction as N, GenerateKeyOptions as O, JWKLookupFunctionHeader as P, JWK_OKP_Public as Q, JWK_AES_CBC_HMAC as R, ContentEncryptionAlgorithm as S, GenerateJWKOptions as T, JWK_Asymmetric_Algorithm as U, JWK_AES_KW as V, JWK_EC as W, JWK_OKP as X, JWK_HMAC as Y, JWK_OKP_Private as Z, JWT as _, JWEEncryptOptions as a, JWK_RSA_ENC as at, JoseHeaderParameters as b, JWEProtectedHeader as c, JWK_RSA_Public as ct, JWSHeaderParameters as d, JWK_Symmetric_Algorithm as dt, JWK_PBES2 as et, JWSProtectedHeader as f, JWK_oct as ft, JOSEPayload as g, WrapKeyResult as gt, JWSVerifyResult as h, WrapKeyOptions as ht, JWEDecryptResult as i, JWK_RSA as it, JWKAlgorithm as j, GenerateKeyReturn as k, StrictOmit as l, JWK_RSA_SIGN as lt, JWSVerifyOptions as m, UnwrapKeyOptions as mt, MaxTokenAge as n, JWK_Private as nt, JWEHeaderParameters as o, JWK_RSA_PSS as ot, JWSSignOptions as p, KeyManagementAlgorithm as pt, JWK_EC_Private as q, JWEDecryptOptions as r, JWK_Public as rt, JWEKeyManagementHeaderParameters as s, JWK_RSA_Private as st, ExpiresIn as t, JWK_Pair as tt, JWSAlgorithm as u, JWK_Symmetric as ut, JWTClaimValidationOptions as v, DeriveKeyReturn as w, CompositeKey as x, JWTClaims as y, JWK_AES_GCM as z };
906
+ /**
907
+ * JWE Flattened JSON Serialization, RFC 7516 §7.2.2.
908
+ */
909
+ interface JWEFlattenedSerialization {
910
+ header?: JWEHeaderParameters;
911
+ encrypted_key?: string;
912
+ /** Base64URL-encoded JWE Protected Header (part of AAD). */
913
+ protected?: string;
914
+ /** Shared JWE Unprotected Header (JSON, not part of AAD). */
915
+ unprotected?: JWEHeaderParameters;
916
+ /** Base64URL-encoded external Additional Authenticated Data. */
917
+ aad?: string;
918
+ /** Base64URL-encoded IV (Initialization Vector). */
919
+ iv?: string;
920
+ /** Base64URL-encoded ciphertext. */
921
+ ciphertext: string;
922
+ /** Base64URL-encoded authentication tag. */
923
+ tag?: string;
924
+ }
925
+ /**
926
+ * JWE General JSON Serialization, RFC 7516 §7.2.1. The canonical
927
+ * multi-recipient output shape of {@link encryptMulti}.
928
+ */
929
+ interface JWEGeneralSerialization extends Omit<JWEFlattenedSerialization, "encrypted_key" | "header"> {
930
+ /** One entry per recipient. */
931
+ recipients: JWEGeneralRecipient[];
932
+ }
933
+ /** A single recipient entry within {@link JWEGeneralSerialization.recipients}. */
934
+ interface JWEGeneralRecipient {
935
+ /** Per-recipient JWE Unprotected Header (JSON, not part of AAD). */
936
+ header?: JWEHeaderParameters;
937
+ /** Base64URL-encoded encrypted CEK for this recipient. */
938
+ encrypted_key?: string;
939
+ }
940
+ /**
941
+ * Input shape for a single recipient passed to {@link encryptMulti}.
942
+ *
943
+ * `alg` is inferred from `key.alg` or from the JWK's kty/curve/length using
944
+ * the same rules as {@link encrypt}. `kid` is pulled from `key.kid` when
945
+ * present. To override either, spread or set via {@link JWEMultiRecipient.header}.
946
+ */
947
+ interface JWEMultiRecipient {
948
+ /** Recipient key (JWK-first; `alg` inferred if absent from JWK). */
949
+ key: JWK;
950
+ /**
951
+ * Extra per-recipient JWE Unprotected Header parameters (RFC 7516 §7.2.1).
952
+ * Excludes fields the library writes automatically: `alg`, `enc`, `iv`,
953
+ * `tag`, `p2s`, `p2c`, `epk`, `apu`, `apv`.
954
+ *
955
+ * Typical use: `x5c`, `x5t`, custom routing metadata.
956
+ */
957
+ header?: StrictOmit<JWEHeaderParameters, "alg" | "enc" | "iv" | "tag" | "p2s" | "p2c" | "epk" | "apu" | "apv">;
958
+ /** ECDH-ES ephemeral key / party info for this recipient. */
959
+ ecdh?: JWEEncryptOptions["ecdh"];
960
+ /** PBES2 salt for this recipient. Randomized (16 bytes) when omitted. */
961
+ p2s?: Uint8Array<ArrayBuffer>;
962
+ /** PBES2 iteration count for this recipient. Defaults to 600_000. */
963
+ p2c?: number;
964
+ /** Initialization vector for AES-GCMKW key wrapping for this recipient. */
965
+ keyManagementIV?: Uint8Array<ArrayBuffer>;
966
+ }
967
+ /**
968
+ * Options for {@link encryptMulti}. Extends {@link JWEEncryptOptions} and drops
969
+ * the fields that are per-recipient in multi-recipient mode (`alg`, `ecdh`,
970
+ * `p2s`, `p2c`, `keyManagementIV` — set those on each {@link JWEMultiRecipient}
971
+ * instead).
972
+ */
973
+ interface JWEMultiEncryptOptions extends StrictOmit<JWEEncryptOptions, "alg" | "ecdh" | "p2s" | "p2c" | "keyManagementIV"> {
974
+ /** Shared JWE Unprotected Header (surfaces as `unprotected` in the output). */
975
+ sharedUnprotectedHeader?: Record<string, unknown>;
976
+ /**
977
+ * External Additional Authenticated Data (RFC 7516 §5.1). Encoded as
978
+ * base64url and written to the `aad` field; the content cipher AAD becomes
979
+ * `BASE64URL(protected) || '.' || BASE64URL(aad)`.
980
+ */
981
+ aad?: Uint8Array<ArrayBuffer> | string;
982
+ }
983
+ /**
984
+ * Options for {@link decryptMulti}. Extends {@link JWEDecryptOptions}.
985
+ */
986
+ interface JWEMultiDecryptOptions extends JWEDecryptOptions {
987
+ /**
988
+ * When `false` (default) decryption trials recipients in order — mirrors the
989
+ * multi-key retry behaviour of {@link decrypt} against a JWK Set. When
990
+ * `true`, only recipients whose header unambiguously matches the provided
991
+ * key (by `kid`, then by `kty`/`crv`/length) are attempted, and any mismatch
992
+ * throws `ERR_JWE_NO_MATCHING_RECIPIENT` before any crypto work.
993
+ */
994
+ strictRecipientMatch?: boolean;
995
+ }
996
+ /**
997
+ * Result of a {@link decryptMulti} operation. Extends {@link JWEDecryptResult}
998
+ * with the per-recipient header tier surfaced on the matching recipient.
999
+ */
1000
+ interface JWEMultiDecryptResult<T extends JOSEPayload = JOSEPayload> extends JWEDecryptResult<T> {
1001
+ /** Parsed shared unprotected header, when present on the serialization. */
1002
+ sharedUnprotectedHeader?: JWEHeaderParameters;
1003
+ /** Parsed per-recipient unprotected header of the recipient that decrypted. */
1004
+ recipientHeader?: JWEHeaderParameters;
1005
+ /** Index into `jwe.recipients` of the recipient that successfully decrypted. */
1006
+ recipientIndex: number;
1007
+ }
1008
+ /**
1009
+ * A time duration, expressed as an integer number of seconds or a human-readable
1010
+ * shorthand like `"10m"`, `"2h"`, `"7D"`.
1011
+ *
1012
+ * Shared base type for every duration-valued option in the library:
1013
+ * {@link ExpiresIn}, {@link NotBeforeIn}, {@link MaxTokenAge}.
1014
+ */
1015
+ type Duration = number | `${number}` | `${number}${"s" | "second" | "seconds" | "m" | "minute" | "minutes" | "h" | "hour" | "hours" | "D" | "day" | "days" | "W" | "week" | "weeks" | "M" | "month" | "months" | "Y" | "year" | "years"}`;
1016
+ /** Duration until `exp` — the `expiresIn` option on {@link sign} / {@link encrypt}. */
1017
+ type ExpiresIn = Duration;
1018
+ /** Duration from `iat` for `nbf` — the `notBeforeIn` option on {@link sign} / {@link encrypt}. */
1019
+ type NotBeforeIn = Duration;
1020
+ /** Duration for `maxTokenAge` validation on {@link verify} / {@link decrypt}. */
1021
+ type MaxTokenAge = Duration;
1022
+ export { JWKAlgorithm as $, JWSSignOptions as A, JWK_RSA_Public as At, JWTClaimValidationOptions as B, JWSMultiSignOptions as C, JWK_Pair as Ct, JWSMultiVerifyOutcome as D, JWK_RSA_ENC as Dt, JWSMultiVerifyOptions as E, JWK_RSA as Et, JWTErrorCauseMap as F, KeyManagementAlgorithm as Ft, DeriveKeyOptions as G, JoseHeaderParameters as H, JWTErrorCode as I, UnwrapKeyOptions as It, GenerateJWKReturn as J, DeriveKeyReturn as K, isJWTError as L, WrapKeyOptions as Lt, JWSVerifyResult as M, JWK_Symmetric as Mt, StrictOmit as N, JWK_Symmetric_Algorithm as Nt, JWSMultiVerifyResult as O, JWK_RSA_PSS as Ot, JWTError as P, JWK_oct as Pt, JWK as Q, JOSEPayload as R, WrapKeyResult as Rt, JWSHeaderParameters as S, JWK_PBES2 as St, JWSMultiVerifyAllOptions as T, JWK_Public as Tt, CompositeKey as U, JWTClaims as V, ContentEncryptionAlgorithm as W, GenerateKeyOptions as X, GenerateKeyAlgorithm as Y, GenerateKeyReturn as Z, JWEProtectedHeader as _, JWK_HMAC as _t, JWEDecryptOptions as a, JWKSet as at, JWSGeneralSerialization as b, JWK_OKP_Public as bt, JWEFlattenedSerialization as c, JWK_AES_GCM_KW as ct, JWEHeaderParameters as d, JWK_Asymmetric_Algorithm as dt, JWKCacheAdapter as et, JWEKeyManagementHeaderParameters as f, JWK_EC as ft, JWEMultiRecipient as g, JWK_EC_Public as gt, JWEMultiEncryptOptions as h, JWK_EC_Private as ht, NotBeforeIn as i, JWKParameters as it, JWSVerifyOptions as j, JWK_RSA_SIGN as jt, JWSProtectedHeader as k, JWK_RSA_Private as kt, JWEGeneralRecipient as l, JWK_AES_KW as lt, JWEMultiDecryptResult as m, JWK_ECDSA as mt, ExpiresIn as n, JWKLookupFunctionHeader as nt, JWEDecryptResult as o, JWK_AES_CBC_HMAC as ot, JWEMultiDecryptOptions as p, JWK_ECDH_ES as pt, GenerateJWKOptions as q, MaxTokenAge as r, JWKPEMAlgorithm as rt, JWEEncryptOptions as s, JWK_AES_GCM as st, Duration as t, JWKLookupFunction as tt, JWEGeneralSerialization as u, JWK_Asymmetric as ut, JWSAlgorithm as v, JWK_OKP as vt, JWSMultiSigner as w, JWK_Private as wt, JWSGeneralSignature as x, JWK_OKP_SIGN as xt, JWSFlattenedSerialization as y, JWK_OKP_Private as yt, JWT as z };
@@ -0,0 +1,82 @@
1
+ import { Ft as KeyManagementAlgorithm, Mt as JWK_Symmetric, Q as JWK, R as JOSEPayload, W as ContentEncryptionAlgorithm, a as JWEDecryptOptions, at as JWKSet, c as JWEFlattenedSerialization, g as JWEMultiRecipient, h as JWEMultiEncryptOptions, m as JWEMultiDecryptResult, o as JWEDecryptResult, p as JWEMultiDecryptOptions, s as JWEEncryptOptions, tt as JWKLookupFunction, u as JWEGeneralSerialization, wt as JWK_Private } from "./index.mjs";
2
+ /**
3
+ * Encrypt a payload to multiple recipients using JWE General JSON Serialization
4
+ * (RFC 7516 §7.2.1).
5
+ *
6
+ * One shared CEK encrypts the payload once; the CEK is then wrapped
7
+ * independently per recipient using each recipient's key-management algorithm.
8
+ * Per-recipient `alg` is read from `key.alg` and throws `ERR_JWE_RECIPIENT_ALG_INFERENCE`
9
+ * when absent.
10
+ *
11
+ * Throws `ERR_JWE_ALG_FORBIDDEN_IN_MULTI` when any recipient resolves to `dir`
12
+ * or bare `ECDH-ES` — those algorithms require exactly one recipient; use
13
+ * {@link encrypt} instead.
14
+ *
15
+ * @example
16
+ * const jwe = await encryptMulti({ sub: "u1" }, [
17
+ * { key: aliceRsaPublicJwk },
18
+ * { key: bobEcdhPublicJwk },
19
+ * ], { enc: "A256GCM", expiresIn: "1h" });
20
+ */
21
+ declare function encryptMulti(payload: JOSEPayload, recipients: JWEMultiRecipient[], options?: JWEMultiEncryptOptions): Promise<JWEGeneralSerialization>;
22
+ /**
23
+ * Decrypt a JWE in JSON Serialization object form (General RFC 7516 §7.2.1 or
24
+ * Flattened §7.2.2 — both accepted).
25
+ *
26
+ * Matches recipients by, in order: `kid` equality, `kty`/`crv`/length
27
+ * compatibility, then trial decryption. Set `strictRecipientMatch: true` to
28
+ * disable the trial fallback.
29
+ *
30
+ * For compact (string) tokens, use {@link decrypt}.
31
+ */
32
+ declare function decryptMulti<T extends JOSEPayload = JOSEPayload>(jwe: JWEGeneralSerialization | JWEFlattenedSerialization, keyOrLookup: CryptoKey | JWKSet | JWK_Private | JWK_Symmetric | string | Uint8Array<ArrayBuffer> | JWKLookupFunction, options?: JWEMultiDecryptOptions): Promise<JWEMultiDecryptResult<T>>;
33
+ /**
34
+ * Convert a {@link JWEGeneralSerialization} with exactly one recipient into
35
+ * the {@link JWEFlattenedSerialization} form (RFC 7516 §7.2.2). Throws
36
+ * `ERR_JWE_INVALID_SERIALIZATION` when the input has zero or multiple
37
+ * recipients — Flattened is strictly single-recipient.
38
+ *
39
+ * `encryptMulti` never emits Flattened itself (stable return shape across
40
+ * recipient counts); this is the canonical post-processing step when
41
+ * interoperating with a strict Flattened-only consumer.
42
+ *
43
+ * @example
44
+ * const general = await encryptMulti(payload, [recipient], opts);
45
+ * const flattened = generalToFlattened(general);
46
+ */
47
+ declare function generalToFlattened(jwe: JWEGeneralSerialization): JWEFlattenedSerialization;
48
+ /**
49
+ * Encrypts a payload to produce a JWE Compact Serialization string.
50
+ *
51
+ * @param payload The payload to encrypt. Can be a string, Uint8Array, or a JSON-serializable object.
52
+ * @param key The key encryption key (KEK). Can be a CryptoKey, JWK, or for PBES2, a password string/Uint8Array.
53
+ * @param options JWE encryption options, including `alg` (key management algorithm) and `enc` (content encryption algorithm).
54
+ * @returns A Promise resolving to the JWE Compact Serialization string.
55
+ */
56
+ declare function encrypt(payload: JOSEPayload, key: JWK | string | Uint8Array<ArrayBuffer>, options?: JWEEncryptOptions): Promise<string>;
57
+ declare function encrypt(payload: JOSEPayload, key: CryptoKey | JWK_Symmetric | Uint8Array<ArrayBuffer>, options: JWEEncryptOptions & {
58
+ alg: "dir";
59
+ enc: ContentEncryptionAlgorithm;
60
+ }): Promise<string>;
61
+ declare function encrypt(payload: JOSEPayload, key: CryptoKey, options: JWEEncryptOptions & {
62
+ alg: KeyManagementAlgorithm;
63
+ enc: ContentEncryptionAlgorithm;
64
+ }): Promise<string>;
65
+ declare function encrypt(payload: JOSEPayload, key: CryptoKey | JWK | string | Uint8Array<ArrayBuffer>, options: JWEEncryptOptions & {
66
+ alg: KeyManagementAlgorithm;
67
+ enc: ContentEncryptionAlgorithm;
68
+ }): Promise<string>;
69
+ /**
70
+ * Decrypts a JWE Compact Serialization string.
71
+ *
72
+ * @param jwe The JWE Compact Serialization string.
73
+ * @param key The key decryption key (KEK) or a function to look up the key.
74
+ * @param options JWE decryption options.
75
+ * @returns A Promise resolving to an object containing the decrypted plaintext, protected header, CEK, and AAD.
76
+ * @throws If JWE is invalid, decryption fails, or options are not met.
77
+ */
78
+ declare function decrypt<T extends JOSEPayload>(jwe: string, key: CryptoKey | JWKSet | JWK_Private | JWK_Symmetric | string | Uint8Array<ArrayBuffer> | JWKLookupFunction, options?: JWEDecryptOptions): Promise<JWEDecryptResult<T>>;
79
+ declare function decrypt(jwe: string, key: CryptoKey | JWKSet | JWK_Private | JWK_Symmetric | string | Uint8Array<ArrayBuffer> | JWKLookupFunction, options: JWEDecryptOptions & {
80
+ forceUint8Array: true;
81
+ }): Promise<JWEDecryptResult<Uint8Array<ArrayBuffer>>>;
82
+ export { generalToFlattened as a, encryptMulti as i, encrypt as n, decryptMulti as r, decrypt as t };