@aura-stack/jose 0.1.0 → 0.3.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.
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @todo: add link attribute to docs when available
3
+ */
4
+ declare class AuraJoseError extends Error {
5
+ static code: string;
6
+ readonly code: string;
7
+ constructor(message?: string, options?: ErrorOptions);
8
+ }
9
+ declare class JWTEncodingError extends AuraJoseError {
10
+ static code: string;
11
+ }
12
+ declare class JWTDecodingError extends AuraJoseError {
13
+ static code: string;
14
+ }
15
+ declare class InvalidPayloadError extends AuraJoseError {
16
+ static code: string;
17
+ }
18
+ declare class JWSVerificationError extends AuraJoseError {
19
+ static code: string;
20
+ }
21
+ declare class JWSSigningError extends AuraJoseError {
22
+ static code: string;
23
+ }
24
+ declare class JWEDecryptionError extends AuraJoseError {
25
+ static code: string;
26
+ }
27
+ declare class JWEEncryptionError extends AuraJoseError {
28
+ static code: string;
29
+ }
30
+ declare class InvalidSecretError extends AuraJoseError {
31
+ static code: string;
32
+ }
33
+
34
+ export { AuraJoseError, InvalidPayloadError, InvalidSecretError, JWEDecryptionError, JWEEncryptionError, JWSSigningError, JWSVerificationError, JWTDecodingError, JWTEncodingError };
package/dist/errors.js ADDED
@@ -0,0 +1,22 @@
1
+ import {
2
+ AuraJoseError,
3
+ InvalidPayloadError,
4
+ InvalidSecretError,
5
+ JWEDecryptionError,
6
+ JWEEncryptionError,
7
+ JWSSigningError,
8
+ JWSVerificationError,
9
+ JWTDecodingError,
10
+ JWTEncodingError
11
+ } from "./chunk-BMXFAB6Q.js";
12
+ export {
13
+ AuraJoseError,
14
+ InvalidPayloadError,
15
+ InvalidSecretError,
16
+ JWEDecryptionError,
17
+ JWEEncryptionError,
18
+ JWSSigningError,
19
+ JWSVerificationError,
20
+ JWTDecodingError,
21
+ JWTEncodingError
22
+ };
package/dist/index.cjs CHANGED
@@ -30,87 +30,205 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ MIN_SECRET_ENTROPY_BITS: () => MIN_SECRET_ENTROPY_BITS,
33
34
  createDeriveKey: () => createDeriveKey,
34
35
  createJWE: () => createJWE,
35
36
  createJWS: () => createJWS,
36
37
  createJWT: () => createJWT,
38
+ createSecret: () => createSecret,
37
39
  decodeJWT: () => decodeJWT,
38
40
  decryptJWE: () => decryptJWE,
39
41
  deriveKey: () => deriveKey,
40
42
  encodeJWT: () => encodeJWT,
41
43
  encryptJWE: () => encryptJWE,
44
+ getEntropy: () => getEntropy,
45
+ getSecrets: () => getSecrets,
42
46
  signJWS: () => signJWS,
43
47
  verifyJWS: () => verifyJWS
44
48
  });
45
49
  module.exports = __toCommonJS(index_exports);
46
50
 
47
- // src/encrypt.ts
48
- var import_node_crypto = __toESM(require("crypto"), 1);
51
+ // src/sign.ts
52
+ var import_crypto = __toESM(require("crypto"), 1);
49
53
  var import_jose = require("jose");
50
54
 
55
+ // src/errors.ts
56
+ var AuraJoseError = class extends Error {
57
+ static code = "ERR_AURA_JOSE_ERROR";
58
+ code;
59
+ constructor(message, options) {
60
+ super(message, options);
61
+ this.name = new.target.name;
62
+ this.code = new.target.code;
63
+ Error.captureStackTrace(this, new.target);
64
+ }
65
+ };
66
+ var JWTEncodingError = class extends AuraJoseError {
67
+ static code = "ERR_JWT_ENCODING";
68
+ };
69
+ var JWTDecodingError = class extends AuraJoseError {
70
+ static code = "ERR_JWT_DECODING";
71
+ };
72
+ var InvalidPayloadError = class extends AuraJoseError {
73
+ static code = "ERR_INVALID_PAYLOAD";
74
+ };
75
+ var JWSVerificationError = class extends AuraJoseError {
76
+ static code = "ERR_JWS_VERIFICATION";
77
+ };
78
+ var JWSSigningError = class extends AuraJoseError {
79
+ static code = "ERR_JWS_SIGNING";
80
+ };
81
+ var JWEDecryptionError = class extends AuraJoseError {
82
+ static code = "ERR_JWE_DECRYPTION";
83
+ };
84
+ var JWEEncryptionError = class extends AuraJoseError {
85
+ static code = "ERR_JWE_ENCRYPTION";
86
+ };
87
+ var InvalidSecretError = class extends AuraJoseError {
88
+ static code = "ERR_INVALID_SECRET";
89
+ };
90
+
91
+ // src/assert.ts
92
+ var isAuraJoseError = (error) => {
93
+ return error instanceof AuraJoseError;
94
+ };
95
+ var isFalsy = (value) => {
96
+ return value === null || value === void 0 || value === false || value === 0 || value === "" || Number.isNaN(value);
97
+ };
98
+ var isObject = (value) => {
99
+ return typeof value === "object" && value !== null && !Array.isArray(value);
100
+ };
101
+ var isInvalidPayload = (payload) => {
102
+ return isFalsy(payload) || !isObject(payload) || typeof payload === "object" && payload !== null && !Array.isArray(payload) && Object.keys(payload).length === 0;
103
+ };
104
+
51
105
  // src/secret.ts
52
- var createSecret = (secret) => {
53
- if (secret === void 0) throw new Error("Secret is required");
106
+ var MIN_SECRET_ENTROPY_BITS = 4.5;
107
+ var getEntropy = (secret) => {
108
+ const charFreq = /* @__PURE__ */ new Map();
109
+ for (const char of secret) {
110
+ if (!charFreq.has(char)) {
111
+ charFreq.set(char, 0);
112
+ }
113
+ charFreq.set(char, charFreq.get(char) + 1);
114
+ }
115
+ let entropy = 0;
116
+ const length = secret.length;
117
+ for (const freq of charFreq.values()) {
118
+ const p = freq / length;
119
+ entropy -= p * Math.log2(p);
120
+ }
121
+ return entropy;
122
+ };
123
+ var createSecret = (secret, length = 32) => {
124
+ if (!Boolean(secret)) throw new InvalidSecretError("Secret is required");
54
125
  if (typeof secret === "string") {
55
- if (new TextEncoder().encode(secret).byteLength < 32) {
56
- throw new Error("Secret string must be at least 32 characters long");
126
+ const byteLength = new TextEncoder().encode(secret).byteLength;
127
+ if (byteLength < length) {
128
+ throw new InvalidSecretError(`Secret string must be at least ${length} bytes long`);
129
+ }
130
+ const entropy = getEntropy(secret);
131
+ if (entropy < MIN_SECRET_ENTROPY_BITS) {
132
+ throw new InvalidSecretError(
133
+ `Secret string must have an entropy of at least ${MIN_SECRET_ENTROPY_BITS} bits per character`
134
+ );
57
135
  }
58
136
  return new Uint8Array(Buffer.from(secret, "utf-8"));
59
137
  }
60
138
  return secret;
61
139
  };
140
+ var getSecrets = (secret) => {
141
+ const jwsSecret = isObject(secret) && "jws" in secret ? secret.jws : secret;
142
+ const jweSecret = isObject(secret) && "jwe" in secret ? secret.jwe : secret;
143
+ return {
144
+ jwsSecret,
145
+ jweSecret
146
+ };
147
+ };
62
148
 
63
- // src/encrypt.ts
64
- var encryptJWE = async (payload, secret) => {
65
- const secretKey = createSecret(secret);
66
- const jti = import_node_crypto.default.randomBytes(32).toString("base64");
67
- return new import_jose.EncryptJWT({ token: payload }).setProtectedHeader({ alg: "dir", enc: "A256GCM", typ: "JWT", cty: "JWT" }).setIssuedAt().setNotBefore("0s").setExpirationTime("15d").setJti(jti).encrypt(secretKey);
149
+ // src/sign.ts
150
+ var signJWS = async (payload, secret) => {
151
+ try {
152
+ if (isInvalidPayload(payload)) {
153
+ throw new InvalidPayloadError("The payload must be a non-empty object");
154
+ }
155
+ const secretKey = createSecret(secret);
156
+ const jti = import_crypto.default.randomBytes(32).toString("base64url");
157
+ return new import_jose.SignJWT(payload).setProtectedHeader({ alg: "HS256", typ: "JWT" }).setIssuedAt().setNotBefore(payload.nbf ?? "0s").setExpirationTime(payload.exp ?? "15d").setJti(jti).sign(secretKey);
158
+ } catch (error) {
159
+ if (isAuraJoseError(error)) {
160
+ throw error;
161
+ }
162
+ throw new JWSSigningError("JWS signing failed", { cause: error });
163
+ }
68
164
  };
69
- var decryptJWE = async (token, secret) => {
165
+ var verifyJWS = async (token, secret, options) => {
70
166
  try {
167
+ if (isFalsy(token)) {
168
+ throw new InvalidPayloadError("The token must be a non-empty string");
169
+ }
71
170
  const secretKey = createSecret(secret);
72
- const { payload } = await (0, import_jose.jwtDecrypt)(token, secretKey);
73
- return payload.token;
171
+ const { payload } = await (0, import_jose.jwtVerify)(token, secretKey, options);
172
+ return payload;
74
173
  } catch (error) {
75
- throw new Error("Invalid JWE", { cause: error });
174
+ if (isAuraJoseError(error)) {
175
+ throw error;
176
+ }
177
+ throw new JWSVerificationError("JWS signature verification failed", { cause: error });
76
178
  }
77
179
  };
78
- var createJWE = (secret) => {
180
+ var createJWS = (secret) => {
79
181
  return {
80
- encryptJWE: (payload) => encryptJWE(payload, secret),
81
- decryptJWE: (payload) => decryptJWE(payload, secret)
182
+ signJWS: (payload) => signJWS(payload, secret),
183
+ verifyJWS: (payload, options) => verifyJWS(payload, secret, options)
82
184
  };
83
185
  };
84
186
 
85
- // src/sign.ts
86
- var import_node_crypto2 = __toESM(require("crypto"), 1);
187
+ // src/encrypt.ts
188
+ var import_crypto2 = __toESM(require("crypto"), 1);
87
189
  var import_jose2 = require("jose");
88
- var signJWS = async (payload, secret) => {
89
- const secretKey = createSecret(secret);
90
- const jti = import_node_crypto2.default.randomBytes(32).toString("base64");
91
- return new import_jose2.SignJWT(payload).setProtectedHeader({ alg: "HS256", typ: "JWT" }).setIssuedAt().setNotBefore("0s").setExpirationTime("15d").setJti(jti).sign(secretKey);
190
+ var encryptJWE = async (payload, secret, options) => {
191
+ try {
192
+ if (isFalsy(payload)) {
193
+ throw new InvalidPayloadError("The payload must be a non-empty string");
194
+ }
195
+ const secretKey = createSecret(secret);
196
+ const jti = import_crypto2.default.randomBytes(32).toString("base64url");
197
+ return new import_jose2.EncryptJWT({ payload }).setProtectedHeader({ alg: "dir", enc: "A256GCM", typ: "JWT", cty: "JWT" }).setIssuedAt().setNotBefore(options?.nbf ?? "0s").setExpirationTime(options?.exp ?? "15d").setJti(jti).encrypt(secretKey);
198
+ } catch (error) {
199
+ if (isAuraJoseError(error)) {
200
+ throw error;
201
+ }
202
+ throw new JWEEncryptionError("JWE encryption failed", { cause: error });
203
+ }
92
204
  };
93
- var verifyJWS = async (token, secret) => {
205
+ var decryptJWE = async (token, secret, options) => {
94
206
  try {
207
+ if (isFalsy(token)) {
208
+ throw new InvalidPayloadError("The token must be a non-empty string");
209
+ }
95
210
  const secretKey = createSecret(secret);
96
- const { payload } = await (0, import_jose2.jwtVerify)(token, secretKey);
97
- return payload;
211
+ const { payload } = await (0, import_jose2.jwtDecrypt)(token, secretKey, options);
212
+ return payload.payload;
98
213
  } catch (error) {
99
- throw new Error("Invalid JWS", { cause: error });
214
+ if (isAuraJoseError(error)) {
215
+ throw error;
216
+ }
217
+ throw new JWEDecryptionError("JWE decryption verification failed", { cause: error });
100
218
  }
101
219
  };
102
- var createJWS = (secret) => {
220
+ var createJWE = (secret) => {
103
221
  return {
104
- signJWS: (payload) => signJWS(payload, secret),
105
- verifyJWS: (payload) => verifyJWS(payload, secret)
222
+ encryptJWE: (payload, options) => encryptJWE(payload, secret, options),
223
+ decryptJWE: (payload, options) => decryptJWE(payload, secret, options)
106
224
  };
107
225
  };
108
226
 
109
227
  // src/deriveKey.ts
110
- var import_node_crypto3 = require("crypto");
228
+ var import_crypto3 = require("crypto");
111
229
  var deriveKey = (secret, salt, info, length = 32) => {
112
230
  try {
113
- const key = (0, import_node_crypto3.hkdfSync)("SHA256", secret, salt, info, length);
231
+ const key = (0, import_crypto3.hkdfSync)("SHA256", secret, salt, info, length);
114
232
  const derivedKey = Buffer.from(key);
115
233
  return {
116
234
  key,
@@ -128,22 +246,30 @@ var createDeriveKey = (secret, salt, info, length = 32) => {
128
246
  // src/index.ts
129
247
  var encodeJWT = async (token, secret) => {
130
248
  try {
131
- const { signJWS: signJWS2 } = createJWS(secret);
132
- const { encryptJWE: encryptJWE2 } = createJWE(secret);
249
+ const { jweSecret, jwsSecret } = getSecrets(secret);
250
+ const { signJWS: signJWS2 } = createJWS(jwsSecret);
251
+ const { encryptJWE: encryptJWE2 } = createJWE(jweSecret);
133
252
  const signed = await signJWS2(token);
134
253
  return await encryptJWE2(signed);
135
254
  } catch (error) {
136
- throw new Error("Failed to encode JWT", { cause: error });
255
+ if (isAuraJoseError(error)) {
256
+ throw error;
257
+ }
258
+ throw new JWTEncodingError("JWT encoding failed", { cause: error });
137
259
  }
138
260
  };
139
- var decodeJWT = async (token, secret) => {
261
+ var decodeJWT = async (token, secret, options) => {
140
262
  try {
141
- const { verifyJWS: verifyJWS2 } = createJWS(secret);
142
- const { decryptJWE: decryptJWE2 } = createJWE(secret);
143
- const decrypted = await decryptJWE2(token);
144
- return await verifyJWS2(decrypted);
263
+ const { jweSecret, jwsSecret } = getSecrets(secret);
264
+ const { verifyJWS: verifyJWS2 } = createJWS(jwsSecret);
265
+ const { decryptJWE: decryptJWE2 } = createJWE(jweSecret);
266
+ const decrypted = await decryptJWE2(token, options?.jwt);
267
+ return await verifyJWS2(decrypted, options?.jws);
145
268
  } catch (error) {
146
- throw new Error("Failed to decode JWT", { cause: error });
269
+ if (isAuraJoseError(error)) {
270
+ throw error;
271
+ }
272
+ throw new JWTDecodingError("JWT decoding failed", { cause: error });
147
273
  }
148
274
  };
149
275
  var createJWT = (secret) => {
@@ -154,15 +280,19 @@ var createJWT = (secret) => {
154
280
  };
155
281
  // Annotate the CommonJS export names for ESM import in node:
156
282
  0 && (module.exports = {
283
+ MIN_SECRET_ENTROPY_BITS,
157
284
  createDeriveKey,
158
285
  createJWE,
159
286
  createJWS,
160
287
  createJWT,
288
+ createSecret,
161
289
  decodeJWT,
162
290
  decryptJWE,
163
291
  deriveKey,
164
292
  encodeJWT,
165
293
  encryptJWE,
294
+ getEntropy,
295
+ getSecrets,
166
296
  signJWS,
167
297
  verifyJWS
168
298
  });
package/dist/index.d.ts CHANGED
@@ -1,145 +1,3 @@
1
- import { KeyObject, BinaryLike } from 'node:crypto';
2
- import { JWTPayload } from 'jose';
3
-
4
- /**
5
- * Sign a standard JWT token with the following claims:
6
- * - alg: algorithm used to sign the JWT
7
- * - typ: type of the token
8
- * - iat: time at which the JWT was issued
9
- * - nbf: not before time of the JWT
10
- * - exp: expiration time of the JWT
11
- * - jti: unique identifier to avoid collisions
12
- *
13
- * @param payload - Payload data information to sign the JWT
14
- * @param secret - Secret key to sign the JWT (CryptoKey, KeyObject, string or Uint8Array)
15
- * @returns Signed JWT string
16
- */
17
- declare const signJWS: (payload: JWTPayload, secret: SecretInput) => Promise<string>;
18
- /**
19
- * Verify the integrity of a JWT token and return the payload if valid, rejecting
20
- * tokens that use the "none" algorithm to prevent unsecured tokens.
21
- *
22
- * @see https://datatracker.ietf.org/doc/html/rfc7519#section-6 Unsecured JWTs
23
- * @param token - JWT string to verify
24
- * @param secret - CryptoKey or KeyObject used to verify the JWT
25
- * @returns verify and return the payload of the JWT
26
- */
27
- declare const verifyJWS: (token: string, secret: SecretInput) => Promise<JWTPayload>;
28
- /**
29
- * Create a JWS (JSON Web Signature) signer and verifier. It implements the `signJWS`
30
- * and `verifyJWS` functions of the module.
31
- *
32
- * @param secret - Secret key used for signing and verifying the JWS
33
- * @returns signJWS and verifyJWS functions
34
- */
35
- declare const createJWS: (secret: SecretInput) => {
36
- signJWS: (payload: JWTPayload) => Promise<string>;
37
- verifyJWS: (payload: string) => Promise<JWTPayload>;
38
- };
39
-
40
- interface EncryptedPayload {
41
- token: string;
42
- }
43
- /**
44
- * Encrypt a standard JWT token with the following claims:
45
- * - alg: algorithm used to encrypt the JWT
46
- * - enc: encryption method used
47
- * - typ: type of the token
48
- * - cty: content type of the token
49
- *
50
- * @param payload - Payload data information to encrypt the JWT
51
- * @param secret - Secret key to encrypt the JWT (CryptoKey, KeyObject, string or Uint8Array)
52
- * @returns Encrypted JWT string
53
- */
54
- declare const encryptJWE: (payload: string, secret: SecretInput) => Promise<string>;
55
- /**
56
- * Decrypt a JWE token and return the payload if valid.
57
- *
58
- * @param token - Encrypted JWT string to decrypt
59
- * @param secret - Secret key to decrypt the JWT (CryptoKey, KeyObject, string or Uint8Array)
60
- * @returns Decrypted JWT payload string
61
- */
62
- declare const decryptJWE: (token: string, secret: SecretInput) => Promise<string>;
63
- /**
64
- * Creates a `JWE (JSON Web Encryption)` encrypter and decrypter. It implements the `encryptJWE`
65
- * and `decryptJWE` functions of the module.
66
- *
67
- * @param secret - Secret key used for encrypting and decrypting the JWE
68
- * @returns encryptJWE and decryptJWE functions
69
- */
70
- declare const createJWE: (secret: SecretInput) => {
71
- encryptJWE: (payload: string) => Promise<string>;
72
- decryptJWE: (payload: string) => Promise<string>;
73
- };
74
-
75
- /**
76
- * @module @aura-stack/jose
77
- */
78
-
79
- type SecretInput = KeyObject | Uint8Array | string;
80
- /**
81
- * Encode a JWT signed and encrypted token. The token first signed using JWS
82
- * and then encrypted using JWE to ensure both integrity and confidentiality.
83
- * It implements the `signJWS` and `encryptJWE` functions of the module.
84
- *
85
- * Based on the RFC 7519 standard
86
- * - Official RFC: https://datatracker.ietf.org/doc/html/rfc7519
87
- * - Nested JWTs should be signed and then encrypted: https://datatracker.ietf.org/doc/html/rfc7519#section-5.2
88
- * - Ensuring the integrity and confidentiality of the claims: https://datatracker.ietf.org/doc/html/rfc7519#section-11.2
89
- *
90
- * @param token - Payload data to encode in the JWT
91
- * @param secret - Secret key used for both signing and encrypting the JWT
92
- * @returns Promise resolving to the signed and encrypted JWT string
93
- */
94
- declare const encodeJWT: (token: JWTPayload, secret: SecretInput) => Promise<string>;
95
- /**
96
- * Decode a JWT signed and encrypted token. The token is first decrypted using JWE
97
- * and then verified using JWS to ensure both confidentiality and integrity. It
98
- * implements the `decryptJWE` and `verifyJWS` functions of the module.
99
- *
100
- * Based on the RFC 7519 standard
101
- * - Official RFC: https://datatracker.ietf.org/doc/html/rfc7519
102
- * - Validating a JWT: https://datatracker.ietf.org/doc/html/rfc7519#section-7.2
103
- * @param token
104
- * @param secret
105
- * @returns
106
- */
107
- declare const decodeJWT: (token: string, secret: SecretInput) => Promise<JWTPayload>;
108
- /**
109
- * Create a JWT handler with encode and decode methods to `signJWS/encryptJWE` and `verifyJWS/decryptJWE`
110
- * JWT tokens. The JWTs are signed and verified using JWS and encrypted and decrypted using JWE. It
111
- * implements the `signJWS`, `verifyJWS`, `encryptJWE` and `decryptJWE` functions of the module.
112
- *
113
- * @param secret - Secret key used for signing, verifying, encrypting and decrypting the JWT
114
- * @returns JWT handler object with `signJWS/encryptJWE` and `verifyJWS/decryptJWE` methods
115
- */
116
- declare const createJWT: (secret: SecretInput) => {
117
- encodeJWT: (payload: JWTPayload) => Promise<string>;
118
- decodeJWT: (token: string) => Promise<JWTPayload>;
119
- };
120
-
121
- /**
122
- * Generate a derived key using HKDF (HMAC-based Extract-and-Expand Key Derivation Function)
123
- *
124
- * @param secret Value used as the input keying material
125
- * @param salt Cryptographic salt
126
- * @param info Context and application specific information
127
- * @param length Size of the derived key in bytes (default is 32 bytes)
128
- * @returns Derived key as Uint8Array and base64 encoded string
129
- */
130
- declare const deriveKey: (secret: SecretInput, salt: BinaryLike, info: string, length?: number) => {
131
- key: ArrayBuffer;
132
- derivedKey: Buffer<ArrayBuffer>;
133
- };
134
- /**
135
- * Create a derived key from a given secret.
136
- *
137
- * @param secret - The secret as a string or Uint8Array
138
- * @returns The secret in Uint8Array format
139
- */
140
- declare const createDeriveKey: (secret: SecretInput, salt?: BinaryLike, info?: string, length?: number) => {
141
- key: ArrayBuffer;
142
- derivedKey: Buffer<ArrayBuffer>;
143
- };
144
-
145
- export { type EncryptedPayload, type SecretInput, createDeriveKey, createJWE, createJWS, createJWT, decodeJWT, decryptJWE, deriveKey, encodeJWT, encryptJWE, signJWS, verifyJWS };
1
+ export { JWTDecryptOptions, JWTVerifyOptions } from 'jose';
2
+ import 'crypto';
3
+ export { h as DecodedJWTPayloadOptions, D as DerivedKeyInput, a as EncryptOptions, E as EncryptedPayload, M as MIN_SECRET_ENTROPY_BITS, S as SecretInput, m as createDeriveKey, c as createJWE, createJWS, k as createJWT, b as createSecret, j as decodeJWT, d as decryptJWE, l as deriveKey, i as encodeJWT, e as encryptJWE, g as getEntropy, f as getSecrets, signJWS, verifyJWS } from './sign.js';
package/dist/index.js CHANGED
@@ -1,38 +1,58 @@
1
1
  import {
2
2
  createDeriveKey,
3
3
  deriveKey
4
- } from "./chunk-ODRHALUH.js";
4
+ } from "./chunk-CXN54JNY.js";
5
5
  import {
6
6
  createJWE,
7
7
  decryptJWE,
8
8
  encryptJWE
9
- } from "./chunk-T7MMDRY3.js";
9
+ } from "./chunk-URDLFFH3.js";
10
10
  import {
11
11
  createJWS,
12
12
  signJWS,
13
13
  verifyJWS
14
- } from "./chunk-KSVD3YEC.js";
15
- import "./chunk-M4WAOCIJ.js";
14
+ } from "./chunk-EX3NULRX.js";
15
+ import {
16
+ MIN_SECRET_ENTROPY_BITS,
17
+ createSecret,
18
+ getEntropy,
19
+ getSecrets
20
+ } from "./chunk-SES6WQL3.js";
21
+ import {
22
+ isAuraJoseError
23
+ } from "./chunk-ZHFHDRQH.js";
24
+ import {
25
+ JWTDecodingError,
26
+ JWTEncodingError
27
+ } from "./chunk-BMXFAB6Q.js";
16
28
 
17
29
  // src/index.ts
18
30
  var encodeJWT = async (token, secret) => {
19
31
  try {
20
- const { signJWS: signJWS2 } = createJWS(secret);
21
- const { encryptJWE: encryptJWE2 } = createJWE(secret);
32
+ const { jweSecret, jwsSecret } = getSecrets(secret);
33
+ const { signJWS: signJWS2 } = createJWS(jwsSecret);
34
+ const { encryptJWE: encryptJWE2 } = createJWE(jweSecret);
22
35
  const signed = await signJWS2(token);
23
36
  return await encryptJWE2(signed);
24
37
  } catch (error) {
25
- throw new Error("Failed to encode JWT", { cause: error });
38
+ if (isAuraJoseError(error)) {
39
+ throw error;
40
+ }
41
+ throw new JWTEncodingError("JWT encoding failed", { cause: error });
26
42
  }
27
43
  };
28
- var decodeJWT = async (token, secret) => {
44
+ var decodeJWT = async (token, secret, options) => {
29
45
  try {
30
- const { verifyJWS: verifyJWS2 } = createJWS(secret);
31
- const { decryptJWE: decryptJWE2 } = createJWE(secret);
32
- const decrypted = await decryptJWE2(token);
33
- return await verifyJWS2(decrypted);
46
+ const { jweSecret, jwsSecret } = getSecrets(secret);
47
+ const { verifyJWS: verifyJWS2 } = createJWS(jwsSecret);
48
+ const { decryptJWE: decryptJWE2 } = createJWE(jweSecret);
49
+ const decrypted = await decryptJWE2(token, options?.jwt);
50
+ return await verifyJWS2(decrypted, options?.jws);
34
51
  } catch (error) {
35
- throw new Error("Failed to decode JWT", { cause: error });
52
+ if (isAuraJoseError(error)) {
53
+ throw error;
54
+ }
55
+ throw new JWTDecodingError("JWT decoding failed", { cause: error });
36
56
  }
37
57
  };
38
58
  var createJWT = (secret) => {
@@ -42,15 +62,19 @@ var createJWT = (secret) => {
42
62
  };
43
63
  };
44
64
  export {
65
+ MIN_SECRET_ENTROPY_BITS,
45
66
  createDeriveKey,
46
67
  createJWE,
47
68
  createJWS,
48
69
  createJWT,
70
+ createSecret,
49
71
  decodeJWT,
50
72
  decryptJWE,
51
73
  deriveKey,
52
74
  encodeJWT,
53
75
  encryptJWE,
76
+ getEntropy,
77
+ getSecrets,
54
78
  signJWS,
55
79
  verifyJWS
56
80
  };
package/dist/secret.cjs CHANGED
@@ -20,20 +20,80 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/secret.ts
21
21
  var secret_exports = {};
22
22
  __export(secret_exports, {
23
- createSecret: () => createSecret
23
+ MIN_SECRET_ENTROPY_BITS: () => MIN_SECRET_ENTROPY_BITS,
24
+ createSecret: () => createSecret,
25
+ getEntropy: () => getEntropy,
26
+ getSecrets: () => getSecrets
24
27
  });
25
28
  module.exports = __toCommonJS(secret_exports);
26
- var createSecret = (secret) => {
27
- if (secret === void 0) throw new Error("Secret is required");
29
+
30
+ // src/errors.ts
31
+ var AuraJoseError = class extends Error {
32
+ static code = "ERR_AURA_JOSE_ERROR";
33
+ code;
34
+ constructor(message, options) {
35
+ super(message, options);
36
+ this.name = new.target.name;
37
+ this.code = new.target.code;
38
+ Error.captureStackTrace(this, new.target);
39
+ }
40
+ };
41
+ var InvalidSecretError = class extends AuraJoseError {
42
+ static code = "ERR_INVALID_SECRET";
43
+ };
44
+
45
+ // src/assert.ts
46
+ var isObject = (value) => {
47
+ return typeof value === "object" && value !== null && !Array.isArray(value);
48
+ };
49
+
50
+ // src/secret.ts
51
+ var MIN_SECRET_ENTROPY_BITS = 4.5;
52
+ var getEntropy = (secret) => {
53
+ const charFreq = /* @__PURE__ */ new Map();
54
+ for (const char of secret) {
55
+ if (!charFreq.has(char)) {
56
+ charFreq.set(char, 0);
57
+ }
58
+ charFreq.set(char, charFreq.get(char) + 1);
59
+ }
60
+ let entropy = 0;
61
+ const length = secret.length;
62
+ for (const freq of charFreq.values()) {
63
+ const p = freq / length;
64
+ entropy -= p * Math.log2(p);
65
+ }
66
+ return entropy;
67
+ };
68
+ var createSecret = (secret, length = 32) => {
69
+ if (!Boolean(secret)) throw new InvalidSecretError("Secret is required");
28
70
  if (typeof secret === "string") {
29
- if (new TextEncoder().encode(secret).byteLength < 32) {
30
- throw new Error("Secret string must be at least 32 characters long");
71
+ const byteLength = new TextEncoder().encode(secret).byteLength;
72
+ if (byteLength < length) {
73
+ throw new InvalidSecretError(`Secret string must be at least ${length} bytes long`);
74
+ }
75
+ const entropy = getEntropy(secret);
76
+ if (entropy < MIN_SECRET_ENTROPY_BITS) {
77
+ throw new InvalidSecretError(
78
+ `Secret string must have an entropy of at least ${MIN_SECRET_ENTROPY_BITS} bits per character`
79
+ );
31
80
  }
32
81
  return new Uint8Array(Buffer.from(secret, "utf-8"));
33
82
  }
34
83
  return secret;
35
84
  };
85
+ var getSecrets = (secret) => {
86
+ const jwsSecret = isObject(secret) && "jws" in secret ? secret.jws : secret;
87
+ const jweSecret = isObject(secret) && "jwe" in secret ? secret.jwe : secret;
88
+ return {
89
+ jwsSecret,
90
+ jweSecret
91
+ };
92
+ };
36
93
  // Annotate the CommonJS export names for ESM import in node:
37
94
  0 && (module.exports = {
38
- createSecret
95
+ MIN_SECRET_ENTROPY_BITS,
96
+ createSecret,
97
+ getEntropy,
98
+ getSecrets
39
99
  });