@aura-stack/jose 0.3.0 → 0.4.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/assert.js CHANGED
@@ -4,8 +4,8 @@ import {
4
4
  isInvalidPayload,
5
5
  isInvalidSecretError,
6
6
  isObject
7
- } from "./chunk-ZHFHDRQH.js";
8
- import "./chunk-BMXFAB6Q.js";
7
+ } from "./chunk-MWFJ4CA5.js";
8
+ import "./chunk-NGBYHSRN.js";
9
9
  export {
10
10
  isAuraJoseError,
11
11
  isFalsy,
@@ -1,9 +1,12 @@
1
1
  import {
2
2
  isObject
3
- } from "./chunk-ZHFHDRQH.js";
3
+ } from "./chunk-MWFJ4CA5.js";
4
+ import {
5
+ encoder
6
+ } from "./chunk-RQFUZSWH.js";
4
7
  import {
5
8
  InvalidSecretError
6
- } from "./chunk-BMXFAB6Q.js";
9
+ } from "./chunk-NGBYHSRN.js";
7
10
 
8
11
  // src/secret.ts
9
12
  var MIN_SECRET_ENTROPY_BITS = 4.5;
@@ -26,7 +29,8 @@ var getEntropy = (secret) => {
26
29
  var createSecret = (secret, length = 32) => {
27
30
  if (!Boolean(secret)) throw new InvalidSecretError("Secret is required");
28
31
  if (typeof secret === "string") {
29
- const byteLength = new TextEncoder().encode(secret).byteLength;
32
+ const encoded = encoder.encode(secret);
33
+ const byteLength = encoded.byteLength;
30
34
  if (byteLength < length) {
31
35
  throw new InvalidSecretError(`Secret string must be at least ${length} bytes long`);
32
36
  }
@@ -36,9 +40,15 @@ var createSecret = (secret, length = 32) => {
36
40
  `Secret string must have an entropy of at least ${MIN_SECRET_ENTROPY_BITS} bits per character`
37
41
  );
38
42
  }
39
- return new Uint8Array(Buffer.from(secret, "utf-8"));
43
+ return encoded;
44
+ }
45
+ if (secret instanceof CryptoKey || secret instanceof Uint8Array) {
46
+ if (secret instanceof Uint8Array && secret.byteLength < length) {
47
+ throw new InvalidSecretError(`Secret must be at least ${length} bytes long`);
48
+ }
49
+ return secret;
40
50
  }
41
- return secret;
51
+ throw new InvalidSecretError("Secret must be a string, Uint8Array, or CryptoKey");
42
52
  };
43
53
  var getSecrets = (secret) => {
44
54
  const jwsSecret = isObject(secret) && "jws" in secret ? secret.jws : secret;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  AuraJoseError,
3
3
  InvalidSecretError
4
- } from "./chunk-BMXFAB6Q.js";
4
+ } from "./chunk-NGBYHSRN.js";
5
5
 
6
6
  // src/assert.ts
7
7
  var isAuraJoseError = (error) => {
@@ -33,6 +33,9 @@ var JWEEncryptionError = class extends AuraJoseError {
33
33
  var InvalidSecretError = class extends AuraJoseError {
34
34
  static code = "ERR_INVALID_SECRET";
35
35
  };
36
+ var KeyDerivationError = class extends AuraJoseError {
37
+ static code = "ERR_KEY_DERIVATION";
38
+ };
36
39
 
37
40
  export {
38
41
  AuraJoseError,
@@ -43,5 +46,6 @@ export {
43
46
  JWSSigningError,
44
47
  JWEDecryptionError,
45
48
  JWEEncryptionError,
46
- InvalidSecretError
49
+ InvalidSecretError,
50
+ KeyDerivationError
47
51
  };
@@ -0,0 +1,47 @@
1
+ import {
2
+ createSecret
3
+ } from "./chunk-FCUM7BTG.js";
4
+ import {
5
+ encoder,
6
+ getSubtleCrypto
7
+ } from "./chunk-RQFUZSWH.js";
8
+ import {
9
+ KeyDerivationError
10
+ } from "./chunk-NGBYHSRN.js";
11
+
12
+ // src/deriveKey.ts
13
+ var deriveKey = async (secret, salt, info, length = 32) => {
14
+ try {
15
+ const subtle = getSubtleCrypto();
16
+ const secretBuffer = secret.buffer.slice(secret.byteOffset, secret.byteOffset + secret.byteLength);
17
+ const baseKey = await subtle.importKey("raw", secretBuffer, "HKDF", false, ["deriveBits"]);
18
+ const saltBuffer = typeof salt === "string" ? encoder.encode(salt) : salt;
19
+ const infoBuffer = typeof info === "string" ? encoder.encode(info) : info;
20
+ const derivedBits = await subtle.deriveBits(
21
+ {
22
+ name: "HKDF",
23
+ hash: "SHA-256",
24
+ salt: saltBuffer,
25
+ info: infoBuffer
26
+ },
27
+ baseKey,
28
+ length << 3
29
+ );
30
+ return new Uint8Array(derivedBits);
31
+ } catch (error) {
32
+ throw new KeyDerivationError("Failed to create a derived key (HKDF)", { cause: error });
33
+ }
34
+ };
35
+ var createDeriveKey = async (secret, salt, info, length = 32) => {
36
+ const secretKey = createSecret(secret);
37
+ if (secretKey instanceof CryptoKey) {
38
+ throw new KeyDerivationError("Cannot derive key from CryptoKey. Use Uint8Array or string secret instead.");
39
+ }
40
+ const key = await deriveKey(secretKey, salt ?? "Aura Jose secret salt", info ?? "Aura Jose secret derivation", length);
41
+ return key;
42
+ };
43
+
44
+ export {
45
+ deriveKey,
46
+ createDeriveKey
47
+ };
@@ -1,27 +1,29 @@
1
1
  import {
2
2
  createSecret
3
- } from "./chunk-SES6WQL3.js";
3
+ } from "./chunk-FCUM7BTG.js";
4
4
  import {
5
5
  isAuraJoseError,
6
6
  isFalsy
7
- } from "./chunk-ZHFHDRQH.js";
7
+ } from "./chunk-MWFJ4CA5.js";
8
+ import {
9
+ getRandomBytes
10
+ } from "./chunk-RQFUZSWH.js";
8
11
  import {
9
12
  InvalidPayloadError,
10
13
  JWEDecryptionError,
11
14
  JWEEncryptionError
12
- } from "./chunk-BMXFAB6Q.js";
15
+ } from "./chunk-NGBYHSRN.js";
13
16
 
14
17
  // src/encrypt.ts
15
- import crypto from "crypto";
16
- import { EncryptJWT, jwtDecrypt } from "jose";
18
+ import { base64url, EncryptJWT, jwtDecrypt } from "jose";
17
19
  var encryptJWE = async (payload, secret, options) => {
18
20
  try {
19
21
  if (isFalsy(payload)) {
20
22
  throw new InvalidPayloadError("The payload must be a non-empty string");
21
23
  }
22
24
  const secretKey = createSecret(secret);
23
- const jti = crypto.randomBytes(32).toString("base64url");
24
- return new EncryptJWT({ payload }).setProtectedHeader({ alg: "dir", enc: "A256GCM", typ: "JWT", cty: "JWT" }).setIssuedAt().setNotBefore(options?.nbf ?? "0s").setExpirationTime(options?.exp ?? "15d").setJti(jti).encrypt(secretKey);
25
+ const jti = base64url.encode(getRandomBytes(32));
26
+ return await new EncryptJWT({ payload }).setProtectedHeader({ alg: "dir", enc: "A256GCM", typ: "JWT", cty: "JWT" }).setIssuedAt().setNotBefore(options?.nbf ?? "0s").setExpirationTime(options?.exp ?? "15d").setJti(jti).encrypt(secretKey);
25
27
  } catch (error) {
26
28
  if (isAuraJoseError(error)) {
27
29
  throw error;
@@ -0,0 +1,19 @@
1
+ // src/crypto.ts
2
+ var encoder = new TextEncoder();
3
+ var decoder = new TextDecoder();
4
+ var getRandomBytes = (size) => {
5
+ return globalThis.crypto.getRandomValues(new Uint8Array(size));
6
+ };
7
+ var getSubtleCrypto = () => {
8
+ if (globalThis.crypto?.subtle) {
9
+ return globalThis.crypto.subtle;
10
+ }
11
+ throw new Error("SubtleCrypto is not available in this runtime");
12
+ };
13
+
14
+ export {
15
+ encoder,
16
+ decoder,
17
+ getRandomBytes,
18
+ getSubtleCrypto
19
+ };
@@ -1,28 +1,30 @@
1
1
  import {
2
2
  createSecret
3
- } from "./chunk-SES6WQL3.js";
3
+ } from "./chunk-FCUM7BTG.js";
4
4
  import {
5
5
  isAuraJoseError,
6
6
  isFalsy,
7
7
  isInvalidPayload
8
- } from "./chunk-ZHFHDRQH.js";
8
+ } from "./chunk-MWFJ4CA5.js";
9
+ import {
10
+ getRandomBytes
11
+ } from "./chunk-RQFUZSWH.js";
9
12
  import {
10
13
  InvalidPayloadError,
11
14
  JWSSigningError,
12
15
  JWSVerificationError
13
- } from "./chunk-BMXFAB6Q.js";
16
+ } from "./chunk-NGBYHSRN.js";
14
17
 
15
18
  // src/sign.ts
16
- import crypto from "crypto";
17
- import { jwtVerify, SignJWT } from "jose";
19
+ import { base64url, jwtVerify, SignJWT } from "jose";
18
20
  var signJWS = async (payload, secret) => {
19
21
  try {
20
22
  if (isInvalidPayload(payload)) {
21
23
  throw new InvalidPayloadError("The payload must be a non-empty object");
22
24
  }
23
25
  const secretKey = createSecret(secret);
24
- const jti = crypto.randomBytes(32).toString("base64url");
25
- return new SignJWT(payload).setProtectedHeader({ alg: "HS256", typ: "JWT" }).setIssuedAt().setNotBefore(payload.nbf ?? "0s").setExpirationTime(payload.exp ?? "15d").setJti(jti).sign(secretKey);
26
+ const jti = base64url.encode(getRandomBytes(32));
27
+ return await new SignJWT(payload).setProtectedHeader({ alg: "HS256", typ: "JWT" }).setIssuedAt().setNotBefore(payload.nbf ?? "0s").setExpirationTime(payload.exp ?? "15d").setJti(jti).sign(secretKey);
26
28
  } catch (error) {
27
29
  if (isAuraJoseError(error)) {
28
30
  throw error;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/crypto.ts
21
+ var crypto_exports = {};
22
+ __export(crypto_exports, {
23
+ decoder: () => decoder,
24
+ encoder: () => encoder,
25
+ getRandomBytes: () => getRandomBytes,
26
+ getSubtleCrypto: () => getSubtleCrypto
27
+ });
28
+ module.exports = __toCommonJS(crypto_exports);
29
+ var encoder = new TextEncoder();
30
+ var decoder = new TextDecoder();
31
+ var getRandomBytes = (size) => {
32
+ return globalThis.crypto.getRandomValues(new Uint8Array(size));
33
+ };
34
+ var getSubtleCrypto = () => {
35
+ if (globalThis.crypto?.subtle) {
36
+ return globalThis.crypto.subtle;
37
+ }
38
+ throw new Error("SubtleCrypto is not available in this runtime");
39
+ };
40
+ // Annotate the CommonJS export names for ESM import in node:
41
+ 0 && (module.exports = {
42
+ decoder,
43
+ encoder,
44
+ getRandomBytes,
45
+ getSubtleCrypto
46
+ });
@@ -0,0 +1,19 @@
1
+ declare const encoder: TextEncoder;
2
+ declare const decoder: TextDecoder;
3
+ /**
4
+ * Generate random bytes using the Web Crypto API
5
+ * Works in Node.js 15+, Deno, Bun, and browsers
6
+ *
7
+ * @param size - Number of random bytes to generate with a max value of 65 bytes
8
+ * @returns Uint8Array containing random bytes
9
+ */
10
+ declare const getRandomBytes: (size: number) => Uint8Array;
11
+ /**
12
+ * Get a unified source of entropy - prefers crypto.subtle but falls back if needed
13
+ * All modern runtimes support globalThis.crypto.subtle
14
+ *
15
+ * @returns SubtleCrypto interface for cryptographic operations
16
+ */
17
+ declare const getSubtleCrypto: () => SubtleCrypto;
18
+
19
+ export { decoder, encoder, getRandomBytes, getSubtleCrypto };
package/dist/crypto.js ADDED
@@ -0,0 +1,12 @@
1
+ import {
2
+ decoder,
3
+ encoder,
4
+ getRandomBytes,
5
+ getSubtleCrypto
6
+ } from "./chunk-RQFUZSWH.js";
7
+ export {
8
+ decoder,
9
+ encoder,
10
+ getRandomBytes,
11
+ getSubtleCrypto
12
+ };
@@ -24,7 +24,6 @@ __export(deriveKey_exports, {
24
24
  deriveKey: () => deriveKey
25
25
  });
26
26
  module.exports = __toCommonJS(deriveKey_exports);
27
- var import_crypto = require("crypto");
28
27
 
29
28
  // src/errors.ts
30
29
  var AuraJoseError = class extends Error {
@@ -40,6 +39,19 @@ var AuraJoseError = class extends Error {
40
39
  var InvalidSecretError = class extends AuraJoseError {
41
40
  static code = "ERR_INVALID_SECRET";
42
41
  };
42
+ var KeyDerivationError = class extends AuraJoseError {
43
+ static code = "ERR_KEY_DERIVATION";
44
+ };
45
+
46
+ // src/crypto.ts
47
+ var encoder = new TextEncoder();
48
+ var decoder = new TextDecoder();
49
+ var getSubtleCrypto = () => {
50
+ if (globalThis.crypto?.subtle) {
51
+ return globalThis.crypto.subtle;
52
+ }
53
+ throw new Error("SubtleCrypto is not available in this runtime");
54
+ };
43
55
 
44
56
  // src/secret.ts
45
57
  var MIN_SECRET_ENTROPY_BITS = 4.5;
@@ -62,7 +74,8 @@ var getEntropy = (secret) => {
62
74
  var createSecret = (secret, length = 32) => {
63
75
  if (!Boolean(secret)) throw new InvalidSecretError("Secret is required");
64
76
  if (typeof secret === "string") {
65
- const byteLength = new TextEncoder().encode(secret).byteLength;
77
+ const encoded = encoder.encode(secret);
78
+ const byteLength = encoded.byteLength;
66
79
  if (byteLength < length) {
67
80
  throw new InvalidSecretError(`Secret string must be at least ${length} bytes long`);
68
81
  }
@@ -72,27 +85,47 @@ var createSecret = (secret, length = 32) => {
72
85
  `Secret string must have an entropy of at least ${MIN_SECRET_ENTROPY_BITS} bits per character`
73
86
  );
74
87
  }
75
- return new Uint8Array(Buffer.from(secret, "utf-8"));
88
+ return encoded;
76
89
  }
77
- return secret;
90
+ if (secret instanceof CryptoKey || secret instanceof Uint8Array) {
91
+ if (secret instanceof Uint8Array && secret.byteLength < length) {
92
+ throw new InvalidSecretError(`Secret must be at least ${length} bytes long`);
93
+ }
94
+ return secret;
95
+ }
96
+ throw new InvalidSecretError("Secret must be a string, Uint8Array, or CryptoKey");
78
97
  };
79
98
 
80
99
  // src/deriveKey.ts
81
- var deriveKey = (secret, salt, info, length = 32) => {
100
+ var deriveKey = async (secret, salt, info, length = 32) => {
82
101
  try {
83
- const key = (0, import_crypto.hkdfSync)("SHA256", secret, salt, info, length);
84
- const derivedKey = Buffer.from(key);
85
- return {
86
- key,
87
- derivedKey
88
- };
102
+ const subtle = getSubtleCrypto();
103
+ const secretBuffer = secret.buffer.slice(secret.byteOffset, secret.byteOffset + secret.byteLength);
104
+ const baseKey = await subtle.importKey("raw", secretBuffer, "HKDF", false, ["deriveBits"]);
105
+ const saltBuffer = typeof salt === "string" ? encoder.encode(salt) : salt;
106
+ const infoBuffer = typeof info === "string" ? encoder.encode(info) : info;
107
+ const derivedBits = await subtle.deriveBits(
108
+ {
109
+ name: "HKDF",
110
+ hash: "SHA-256",
111
+ salt: saltBuffer,
112
+ info: infoBuffer
113
+ },
114
+ baseKey,
115
+ length << 3
116
+ );
117
+ return new Uint8Array(derivedBits);
89
118
  } catch (error) {
90
- throw new Error("Failed to create a derived key (HKDF)", { cause: error });
119
+ throw new KeyDerivationError("Failed to create a derived key (HKDF)", { cause: error });
91
120
  }
92
121
  };
93
- var createDeriveKey = (secret, salt, info, length = 32) => {
122
+ var createDeriveKey = async (secret, salt, info, length = 32) => {
94
123
  const secretKey = createSecret(secret);
95
- return deriveKey(secretKey, salt ?? "Aura Jose secret salt", info ?? "Aura Jose secret derivation", length);
124
+ if (secretKey instanceof CryptoKey) {
125
+ throw new KeyDerivationError("Cannot derive key from CryptoKey. Use Uint8Array or string secret instead.");
126
+ }
127
+ const key = await deriveKey(secretKey, salt ?? "Aura Jose secret salt", info ?? "Aura Jose secret derivation", length);
128
+ return key;
96
129
  };
97
130
  // Annotate the CommonJS export names for ESM import in node:
98
131
  0 && (module.exports = {
@@ -1,3 +1,3 @@
1
- import 'crypto';
2
- export { m as createDeriveKey, l as deriveKey } from './sign.js';
1
+ export { i as createDeriveKey, l as deriveKey } from './sign.js';
3
2
  import 'jose';
3
+ import './crypto.js';
package/dist/deriveKey.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import {
2
2
  createDeriveKey,
3
3
  deriveKey
4
- } from "./chunk-CXN54JNY.js";
5
- import "./chunk-SES6WQL3.js";
6
- import "./chunk-ZHFHDRQH.js";
7
- import "./chunk-BMXFAB6Q.js";
4
+ } from "./chunk-OG4QRUXH.js";
5
+ import "./chunk-FCUM7BTG.js";
6
+ import "./chunk-MWFJ4CA5.js";
7
+ import "./chunk-RQFUZSWH.js";
8
+ import "./chunk-NGBYHSRN.js";
8
9
  export {
9
10
  createDeriveKey,
10
11
  deriveKey
package/dist/encrypt.cjs CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/encrypt.ts
@@ -35,7 +25,6 @@ __export(encrypt_exports, {
35
25
  encryptJWE: () => encryptJWE
36
26
  });
37
27
  module.exports = __toCommonJS(encrypt_exports);
38
- var import_crypto = __toESM(require("crypto"), 1);
39
28
  var import_jose = require("jose");
40
29
 
41
30
  // src/errors.ts
@@ -70,6 +59,13 @@ var isFalsy = (value) => {
70
59
  return value === null || value === void 0 || value === false || value === 0 || value === "" || Number.isNaN(value);
71
60
  };
72
61
 
62
+ // src/crypto.ts
63
+ var encoder = new TextEncoder();
64
+ var decoder = new TextDecoder();
65
+ var getRandomBytes = (size) => {
66
+ return globalThis.crypto.getRandomValues(new Uint8Array(size));
67
+ };
68
+
73
69
  // src/secret.ts
74
70
  var MIN_SECRET_ENTROPY_BITS = 4.5;
75
71
  var getEntropy = (secret) => {
@@ -91,7 +87,8 @@ var getEntropy = (secret) => {
91
87
  var createSecret = (secret, length = 32) => {
92
88
  if (!Boolean(secret)) throw new InvalidSecretError("Secret is required");
93
89
  if (typeof secret === "string") {
94
- const byteLength = new TextEncoder().encode(secret).byteLength;
90
+ const encoded = encoder.encode(secret);
91
+ const byteLength = encoded.byteLength;
95
92
  if (byteLength < length) {
96
93
  throw new InvalidSecretError(`Secret string must be at least ${length} bytes long`);
97
94
  }
@@ -101,9 +98,15 @@ var createSecret = (secret, length = 32) => {
101
98
  `Secret string must have an entropy of at least ${MIN_SECRET_ENTROPY_BITS} bits per character`
102
99
  );
103
100
  }
104
- return new Uint8Array(Buffer.from(secret, "utf-8"));
101
+ return encoded;
102
+ }
103
+ if (secret instanceof CryptoKey || secret instanceof Uint8Array) {
104
+ if (secret instanceof Uint8Array && secret.byteLength < length) {
105
+ throw new InvalidSecretError(`Secret must be at least ${length} bytes long`);
106
+ }
107
+ return secret;
105
108
  }
106
- return secret;
109
+ throw new InvalidSecretError("Secret must be a string, Uint8Array, or CryptoKey");
107
110
  };
108
111
 
109
112
  // src/encrypt.ts
@@ -113,8 +116,8 @@ var encryptJWE = async (payload, secret, options) => {
113
116
  throw new InvalidPayloadError("The payload must be a non-empty string");
114
117
  }
115
118
  const secretKey = createSecret(secret);
116
- const jti = import_crypto.default.randomBytes(32).toString("base64url");
117
- return new import_jose.EncryptJWT({ payload }).setProtectedHeader({ alg: "dir", enc: "A256GCM", typ: "JWT", cty: "JWT" }).setIssuedAt().setNotBefore(options?.nbf ?? "0s").setExpirationTime(options?.exp ?? "15d").setJti(jti).encrypt(secretKey);
119
+ const jti = import_jose.base64url.encode(getRandomBytes(32));
120
+ return await new import_jose.EncryptJWT({ payload }).setProtectedHeader({ alg: "dir", enc: "A256GCM", typ: "JWT", cty: "JWT" }).setIssuedAt().setNotBefore(options?.nbf ?? "0s").setExpirationTime(options?.exp ?? "15d").setJti(jti).encrypt(secretKey);
118
121
  } catch (error) {
119
122
  if (isAuraJoseError(error)) {
120
123
  throw error;
package/dist/encrypt.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { JWTDecryptOptions } from 'jose';
2
- export { a as EncryptOptions, E as EncryptedPayload, c as createJWE, d as decryptJWE, e as encryptJWE } from './sign.js';
3
- import 'crypto';
2
+ export { E as EncryptOptions, a as EncryptedPayload, c as createJWE, d as decryptJWE, e as encryptJWE } from './sign.js';
3
+ import './crypto.js';
package/dist/encrypt.js CHANGED
@@ -2,10 +2,11 @@ import {
2
2
  createJWE,
3
3
  decryptJWE,
4
4
  encryptJWE
5
- } from "./chunk-URDLFFH3.js";
6
- import "./chunk-SES6WQL3.js";
7
- import "./chunk-ZHFHDRQH.js";
8
- import "./chunk-BMXFAB6Q.js";
5
+ } from "./chunk-Q2LAK6W2.js";
6
+ import "./chunk-FCUM7BTG.js";
7
+ import "./chunk-MWFJ4CA5.js";
8
+ import "./chunk-RQFUZSWH.js";
9
+ import "./chunk-NGBYHSRN.js";
9
10
  export {
10
11
  createJWE,
11
12
  decryptJWE,
package/dist/errors.cjs CHANGED
@@ -28,7 +28,8 @@ __export(errors_exports, {
28
28
  JWSSigningError: () => JWSSigningError,
29
29
  JWSVerificationError: () => JWSVerificationError,
30
30
  JWTDecodingError: () => JWTDecodingError,
31
- JWTEncodingError: () => JWTEncodingError
31
+ JWTEncodingError: () => JWTEncodingError,
32
+ KeyDerivationError: () => KeyDerivationError
32
33
  });
33
34
  module.exports = __toCommonJS(errors_exports);
34
35
  var AuraJoseError = class extends Error {
@@ -65,6 +66,9 @@ var JWEEncryptionError = class extends AuraJoseError {
65
66
  var InvalidSecretError = class extends AuraJoseError {
66
67
  static code = "ERR_INVALID_SECRET";
67
68
  };
69
+ var KeyDerivationError = class extends AuraJoseError {
70
+ static code = "ERR_KEY_DERIVATION";
71
+ };
68
72
  // Annotate the CommonJS export names for ESM import in node:
69
73
  0 && (module.exports = {
70
74
  AuraJoseError,
@@ -75,5 +79,6 @@ var InvalidSecretError = class extends AuraJoseError {
75
79
  JWSSigningError,
76
80
  JWSVerificationError,
77
81
  JWTDecodingError,
78
- JWTEncodingError
82
+ JWTEncodingError,
83
+ KeyDerivationError
79
84
  });
package/dist/errors.d.ts CHANGED
@@ -30,5 +30,8 @@ declare class JWEEncryptionError extends AuraJoseError {
30
30
  declare class InvalidSecretError extends AuraJoseError {
31
31
  static code: string;
32
32
  }
33
+ declare class KeyDerivationError extends AuraJoseError {
34
+ static code: string;
35
+ }
33
36
 
34
- export { AuraJoseError, InvalidPayloadError, InvalidSecretError, JWEDecryptionError, JWEEncryptionError, JWSSigningError, JWSVerificationError, JWTDecodingError, JWTEncodingError };
37
+ export { AuraJoseError, InvalidPayloadError, InvalidSecretError, JWEDecryptionError, JWEEncryptionError, JWSSigningError, JWSVerificationError, JWTDecodingError, JWTEncodingError, KeyDerivationError };
package/dist/errors.js CHANGED
@@ -7,8 +7,9 @@ import {
7
7
  JWSSigningError,
8
8
  JWSVerificationError,
9
9
  JWTDecodingError,
10
- JWTEncodingError
11
- } from "./chunk-BMXFAB6Q.js";
10
+ JWTEncodingError,
11
+ KeyDerivationError
12
+ } from "./chunk-NGBYHSRN.js";
12
13
  export {
13
14
  AuraJoseError,
14
15
  InvalidPayloadError,
@@ -18,5 +19,6 @@ export {
18
19
  JWSSigningError,
19
20
  JWSVerificationError,
20
21
  JWTDecodingError,
21
- JWTEncodingError
22
+ JWTEncodingError,
23
+ KeyDerivationError
22
24
  };
package/dist/index.cjs CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/index.ts
@@ -37,19 +27,22 @@ __export(index_exports, {
37
27
  createJWT: () => createJWT,
38
28
  createSecret: () => createSecret,
39
29
  decodeJWT: () => decodeJWT,
30
+ decoder: () => decoder,
40
31
  decryptJWE: () => decryptJWE,
41
32
  deriveKey: () => deriveKey,
42
33
  encodeJWT: () => encodeJWT,
34
+ encoder: () => encoder,
43
35
  encryptJWE: () => encryptJWE,
44
36
  getEntropy: () => getEntropy,
37
+ getRandomBytes: () => getRandomBytes,
45
38
  getSecrets: () => getSecrets,
39
+ getSubtleCrypto: () => getSubtleCrypto,
46
40
  signJWS: () => signJWS,
47
41
  verifyJWS: () => verifyJWS
48
42
  });
49
43
  module.exports = __toCommonJS(index_exports);
50
44
 
51
45
  // src/sign.ts
52
- var import_crypto = __toESM(require("crypto"), 1);
53
46
  var import_jose = require("jose");
54
47
 
55
48
  // src/errors.ts
@@ -87,6 +80,9 @@ var JWEEncryptionError = class extends AuraJoseError {
87
80
  var InvalidSecretError = class extends AuraJoseError {
88
81
  static code = "ERR_INVALID_SECRET";
89
82
  };
83
+ var KeyDerivationError = class extends AuraJoseError {
84
+ static code = "ERR_KEY_DERIVATION";
85
+ };
90
86
 
91
87
  // src/assert.ts
92
88
  var isAuraJoseError = (error) => {
@@ -102,6 +98,19 @@ var isInvalidPayload = (payload) => {
102
98
  return isFalsy(payload) || !isObject(payload) || typeof payload === "object" && payload !== null && !Array.isArray(payload) && Object.keys(payload).length === 0;
103
99
  };
104
100
 
101
+ // src/crypto.ts
102
+ var encoder = new TextEncoder();
103
+ var decoder = new TextDecoder();
104
+ var getRandomBytes = (size) => {
105
+ return globalThis.crypto.getRandomValues(new Uint8Array(size));
106
+ };
107
+ var getSubtleCrypto = () => {
108
+ if (globalThis.crypto?.subtle) {
109
+ return globalThis.crypto.subtle;
110
+ }
111
+ throw new Error("SubtleCrypto is not available in this runtime");
112
+ };
113
+
105
114
  // src/secret.ts
106
115
  var MIN_SECRET_ENTROPY_BITS = 4.5;
107
116
  var getEntropy = (secret) => {
@@ -123,7 +132,8 @@ var getEntropy = (secret) => {
123
132
  var createSecret = (secret, length = 32) => {
124
133
  if (!Boolean(secret)) throw new InvalidSecretError("Secret is required");
125
134
  if (typeof secret === "string") {
126
- const byteLength = new TextEncoder().encode(secret).byteLength;
135
+ const encoded = encoder.encode(secret);
136
+ const byteLength = encoded.byteLength;
127
137
  if (byteLength < length) {
128
138
  throw new InvalidSecretError(`Secret string must be at least ${length} bytes long`);
129
139
  }
@@ -133,9 +143,15 @@ var createSecret = (secret, length = 32) => {
133
143
  `Secret string must have an entropy of at least ${MIN_SECRET_ENTROPY_BITS} bits per character`
134
144
  );
135
145
  }
136
- return new Uint8Array(Buffer.from(secret, "utf-8"));
146
+ return encoded;
147
+ }
148
+ if (secret instanceof CryptoKey || secret instanceof Uint8Array) {
149
+ if (secret instanceof Uint8Array && secret.byteLength < length) {
150
+ throw new InvalidSecretError(`Secret must be at least ${length} bytes long`);
151
+ }
152
+ return secret;
137
153
  }
138
- return secret;
154
+ throw new InvalidSecretError("Secret must be a string, Uint8Array, or CryptoKey");
139
155
  };
140
156
  var getSecrets = (secret) => {
141
157
  const jwsSecret = isObject(secret) && "jws" in secret ? secret.jws : secret;
@@ -153,8 +169,8 @@ var signJWS = async (payload, secret) => {
153
169
  throw new InvalidPayloadError("The payload must be a non-empty object");
154
170
  }
155
171
  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);
172
+ const jti = import_jose.base64url.encode(getRandomBytes(32));
173
+ return await new import_jose.SignJWT(payload).setProtectedHeader({ alg: "HS256", typ: "JWT" }).setIssuedAt().setNotBefore(payload.nbf ?? "0s").setExpirationTime(payload.exp ?? "15d").setJti(jti).sign(secretKey);
158
174
  } catch (error) {
159
175
  if (isAuraJoseError(error)) {
160
176
  throw error;
@@ -185,7 +201,6 @@ var createJWS = (secret) => {
185
201
  };
186
202
 
187
203
  // src/encrypt.ts
188
- var import_crypto2 = __toESM(require("crypto"), 1);
189
204
  var import_jose2 = require("jose");
190
205
  var encryptJWE = async (payload, secret, options) => {
191
206
  try {
@@ -193,8 +208,8 @@ var encryptJWE = async (payload, secret, options) => {
193
208
  throw new InvalidPayloadError("The payload must be a non-empty string");
194
209
  }
195
210
  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);
211
+ const jti = import_jose2.base64url.encode(getRandomBytes(32));
212
+ return await 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
213
  } catch (error) {
199
214
  if (isAuraJoseError(error)) {
200
215
  throw error;
@@ -225,22 +240,35 @@ var createJWE = (secret) => {
225
240
  };
226
241
 
227
242
  // src/deriveKey.ts
228
- var import_crypto3 = require("crypto");
229
- var deriveKey = (secret, salt, info, length = 32) => {
243
+ var deriveKey = async (secret, salt, info, length = 32) => {
230
244
  try {
231
- const key = (0, import_crypto3.hkdfSync)("SHA256", secret, salt, info, length);
232
- const derivedKey = Buffer.from(key);
233
- return {
234
- key,
235
- derivedKey
236
- };
245
+ const subtle = getSubtleCrypto();
246
+ const secretBuffer = secret.buffer.slice(secret.byteOffset, secret.byteOffset + secret.byteLength);
247
+ const baseKey = await subtle.importKey("raw", secretBuffer, "HKDF", false, ["deriveBits"]);
248
+ const saltBuffer = typeof salt === "string" ? encoder.encode(salt) : salt;
249
+ const infoBuffer = typeof info === "string" ? encoder.encode(info) : info;
250
+ const derivedBits = await subtle.deriveBits(
251
+ {
252
+ name: "HKDF",
253
+ hash: "SHA-256",
254
+ salt: saltBuffer,
255
+ info: infoBuffer
256
+ },
257
+ baseKey,
258
+ length << 3
259
+ );
260
+ return new Uint8Array(derivedBits);
237
261
  } catch (error) {
238
- throw new Error("Failed to create a derived key (HKDF)", { cause: error });
262
+ throw new KeyDerivationError("Failed to create a derived key (HKDF)", { cause: error });
239
263
  }
240
264
  };
241
- var createDeriveKey = (secret, salt, info, length = 32) => {
265
+ var createDeriveKey = async (secret, salt, info, length = 32) => {
242
266
  const secretKey = createSecret(secret);
243
- return deriveKey(secretKey, salt ?? "Aura Jose secret salt", info ?? "Aura Jose secret derivation", length);
267
+ if (secretKey instanceof CryptoKey) {
268
+ throw new KeyDerivationError("Cannot derive key from CryptoKey. Use Uint8Array or string secret instead.");
269
+ }
270
+ const key = await deriveKey(secretKey, salt ?? "Aura Jose secret salt", info ?? "Aura Jose secret derivation", length);
271
+ return key;
244
272
  };
245
273
 
246
274
  // src/index.ts
@@ -274,8 +302,8 @@ var decodeJWT = async (token, secret, options) => {
274
302
  };
275
303
  var createJWT = (secret) => {
276
304
  return {
277
- encodeJWT: async (payload) => encodeJWT(payload, secret),
278
- decodeJWT: async (token) => decodeJWT(token, secret)
305
+ encodeJWT: async (payload) => await encodeJWT(payload, secret),
306
+ decodeJWT: async (token, options) => await decodeJWT(token, secret, options)
279
307
  };
280
308
  };
281
309
  // Annotate the CommonJS export names for ESM import in node:
@@ -287,12 +315,16 @@ var createJWT = (secret) => {
287
315
  createJWT,
288
316
  createSecret,
289
317
  decodeJWT,
318
+ decoder,
290
319
  decryptJWE,
291
320
  deriveKey,
292
321
  encodeJWT,
322
+ encoder,
293
323
  encryptJWE,
294
324
  getEntropy,
325
+ getRandomBytes,
295
326
  getSecrets,
327
+ getSubtleCrypto,
296
328
  signJWS,
297
329
  verifyJWS
298
330
  });
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
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';
2
+ export { D as DecodedJWTPayloadOptions, h as DerivedKeyInput, E as EncryptOptions, a as EncryptedPayload, M as MIN_SECRET_ENTROPY_BITS, P as Prettify, S as SecretInput, T as TypedJWTPayload, i as createDeriveKey, c as createJWE, createJWS, j as createJWT, b as createSecret, k as decodeJWT, d as decryptJWE, l as deriveKey, m as encodeJWT, e as encryptJWE, g as getEntropy, f as getSecrets, signJWS, verifyJWS } from './sign.js';
3
+ export { decoder, encoder, getRandomBytes, getSubtleCrypto } from './crypto.js';
package/dist/index.js CHANGED
@@ -1,30 +1,36 @@
1
+ import {
2
+ createJWS,
3
+ signJWS,
4
+ verifyJWS
5
+ } from "./chunk-WXGX6PJ5.js";
1
6
  import {
2
7
  createDeriveKey,
3
8
  deriveKey
4
- } from "./chunk-CXN54JNY.js";
9
+ } from "./chunk-OG4QRUXH.js";
5
10
  import {
6
11
  createJWE,
7
12
  decryptJWE,
8
13
  encryptJWE
9
- } from "./chunk-URDLFFH3.js";
10
- import {
11
- createJWS,
12
- signJWS,
13
- verifyJWS
14
- } from "./chunk-EX3NULRX.js";
14
+ } from "./chunk-Q2LAK6W2.js";
15
15
  import {
16
16
  MIN_SECRET_ENTROPY_BITS,
17
17
  createSecret,
18
18
  getEntropy,
19
19
  getSecrets
20
- } from "./chunk-SES6WQL3.js";
20
+ } from "./chunk-FCUM7BTG.js";
21
21
  import {
22
22
  isAuraJoseError
23
- } from "./chunk-ZHFHDRQH.js";
23
+ } from "./chunk-MWFJ4CA5.js";
24
+ import {
25
+ decoder,
26
+ encoder,
27
+ getRandomBytes,
28
+ getSubtleCrypto
29
+ } from "./chunk-RQFUZSWH.js";
24
30
  import {
25
31
  JWTDecodingError,
26
32
  JWTEncodingError
27
- } from "./chunk-BMXFAB6Q.js";
33
+ } from "./chunk-NGBYHSRN.js";
28
34
 
29
35
  // src/index.ts
30
36
  var encodeJWT = async (token, secret) => {
@@ -57,8 +63,8 @@ var decodeJWT = async (token, secret, options) => {
57
63
  };
58
64
  var createJWT = (secret) => {
59
65
  return {
60
- encodeJWT: async (payload) => encodeJWT(payload, secret),
61
- decodeJWT: async (token) => decodeJWT(token, secret)
66
+ encodeJWT: async (payload) => await encodeJWT(payload, secret),
67
+ decodeJWT: async (token, options) => await decodeJWT(token, secret, options)
62
68
  };
63
69
  };
64
70
  export {
@@ -69,12 +75,16 @@ export {
69
75
  createJWT,
70
76
  createSecret,
71
77
  decodeJWT,
78
+ decoder,
72
79
  decryptJWE,
73
80
  deriveKey,
74
81
  encodeJWT,
82
+ encoder,
75
83
  encryptJWE,
76
84
  getEntropy,
85
+ getRandomBytes,
77
86
  getSecrets,
87
+ getSubtleCrypto,
78
88
  signJWS,
79
89
  verifyJWS
80
90
  };
package/dist/secret.cjs CHANGED
@@ -47,6 +47,10 @@ var isObject = (value) => {
47
47
  return typeof value === "object" && value !== null && !Array.isArray(value);
48
48
  };
49
49
 
50
+ // src/crypto.ts
51
+ var encoder = new TextEncoder();
52
+ var decoder = new TextDecoder();
53
+
50
54
  // src/secret.ts
51
55
  var MIN_SECRET_ENTROPY_BITS = 4.5;
52
56
  var getEntropy = (secret) => {
@@ -68,7 +72,8 @@ var getEntropy = (secret) => {
68
72
  var createSecret = (secret, length = 32) => {
69
73
  if (!Boolean(secret)) throw new InvalidSecretError("Secret is required");
70
74
  if (typeof secret === "string") {
71
- const byteLength = new TextEncoder().encode(secret).byteLength;
75
+ const encoded = encoder.encode(secret);
76
+ const byteLength = encoded.byteLength;
72
77
  if (byteLength < length) {
73
78
  throw new InvalidSecretError(`Secret string must be at least ${length} bytes long`);
74
79
  }
@@ -78,9 +83,15 @@ var createSecret = (secret, length = 32) => {
78
83
  `Secret string must have an entropy of at least ${MIN_SECRET_ENTROPY_BITS} bits per character`
79
84
  );
80
85
  }
81
- return new Uint8Array(Buffer.from(secret, "utf-8"));
86
+ return encoded;
87
+ }
88
+ if (secret instanceof CryptoKey || secret instanceof Uint8Array) {
89
+ if (secret instanceof Uint8Array && secret.byteLength < length) {
90
+ throw new InvalidSecretError(`Secret must be at least ${length} bytes long`);
91
+ }
92
+ return secret;
82
93
  }
83
- return secret;
94
+ throw new InvalidSecretError("Secret must be a string, Uint8Array, or CryptoKey");
84
95
  };
85
96
  var getSecrets = (secret) => {
86
97
  const jwsSecret = isObject(secret) && "jws" in secret ? secret.jws : secret;
package/dist/secret.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import 'crypto';
2
1
  export { M as MIN_SECRET_ENTROPY_BITS, b as createSecret, g as getEntropy, f as getSecrets } from './sign.js';
3
2
  import 'jose';
3
+ import './crypto.js';
package/dist/secret.js CHANGED
@@ -3,9 +3,10 @@ import {
3
3
  createSecret,
4
4
  getEntropy,
5
5
  getSecrets
6
- } from "./chunk-SES6WQL3.js";
7
- import "./chunk-ZHFHDRQH.js";
8
- import "./chunk-BMXFAB6Q.js";
6
+ } from "./chunk-FCUM7BTG.js";
7
+ import "./chunk-MWFJ4CA5.js";
8
+ import "./chunk-RQFUZSWH.js";
9
+ import "./chunk-NGBYHSRN.js";
9
10
  export {
10
11
  MIN_SECRET_ENTROPY_BITS,
11
12
  createSecret,
package/dist/sign.cjs CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/sign.ts
@@ -35,7 +25,6 @@ __export(sign_exports, {
35
25
  verifyJWS: () => verifyJWS
36
26
  });
37
27
  module.exports = __toCommonJS(sign_exports);
38
- var import_crypto = __toESM(require("crypto"), 1);
39
28
  var import_jose = require("jose");
40
29
 
41
30
  // src/errors.ts
@@ -76,6 +65,13 @@ var isInvalidPayload = (payload) => {
76
65
  return isFalsy(payload) || !isObject(payload) || typeof payload === "object" && payload !== null && !Array.isArray(payload) && Object.keys(payload).length === 0;
77
66
  };
78
67
 
68
+ // src/crypto.ts
69
+ var encoder = new TextEncoder();
70
+ var decoder = new TextDecoder();
71
+ var getRandomBytes = (size) => {
72
+ return globalThis.crypto.getRandomValues(new Uint8Array(size));
73
+ };
74
+
79
75
  // src/secret.ts
80
76
  var MIN_SECRET_ENTROPY_BITS = 4.5;
81
77
  var getEntropy = (secret) => {
@@ -97,7 +93,8 @@ var getEntropy = (secret) => {
97
93
  var createSecret = (secret, length = 32) => {
98
94
  if (!Boolean(secret)) throw new InvalidSecretError("Secret is required");
99
95
  if (typeof secret === "string") {
100
- const byteLength = new TextEncoder().encode(secret).byteLength;
96
+ const encoded = encoder.encode(secret);
97
+ const byteLength = encoded.byteLength;
101
98
  if (byteLength < length) {
102
99
  throw new InvalidSecretError(`Secret string must be at least ${length} bytes long`);
103
100
  }
@@ -107,9 +104,15 @@ var createSecret = (secret, length = 32) => {
107
104
  `Secret string must have an entropy of at least ${MIN_SECRET_ENTROPY_BITS} bits per character`
108
105
  );
109
106
  }
110
- return new Uint8Array(Buffer.from(secret, "utf-8"));
107
+ return encoded;
108
+ }
109
+ if (secret instanceof CryptoKey || secret instanceof Uint8Array) {
110
+ if (secret instanceof Uint8Array && secret.byteLength < length) {
111
+ throw new InvalidSecretError(`Secret must be at least ${length} bytes long`);
112
+ }
113
+ return secret;
111
114
  }
112
- return secret;
115
+ throw new InvalidSecretError("Secret must be a string, Uint8Array, or CryptoKey");
113
116
  };
114
117
 
115
118
  // src/sign.ts
@@ -119,8 +122,8 @@ var signJWS = async (payload, secret) => {
119
122
  throw new InvalidPayloadError("The payload must be a non-empty object");
120
123
  }
121
124
  const secretKey = createSecret(secret);
122
- const jti = import_crypto.default.randomBytes(32).toString("base64url");
123
- return new import_jose.SignJWT(payload).setProtectedHeader({ alg: "HS256", typ: "JWT" }).setIssuedAt().setNotBefore(payload.nbf ?? "0s").setExpirationTime(payload.exp ?? "15d").setJti(jti).sign(secretKey);
125
+ const jti = import_jose.base64url.encode(getRandomBytes(32));
126
+ return await new import_jose.SignJWT(payload).setProtectedHeader({ alg: "HS256", typ: "JWT" }).setIssuedAt().setNotBefore(payload.nbf ?? "0s").setExpirationTime(payload.exp ?? "15d").setJti(jti).sign(secretKey);
124
127
  } catch (error) {
125
128
  if (isAuraJoseError(error)) {
126
129
  throw error;
package/dist/sign.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- import * as crypto from 'crypto';
2
- import { KeyObject, BinaryLike } from 'crypto';
3
1
  import { JWTPayload, JWTVerifyOptions, JWTDecryptOptions } from 'jose';
4
2
  export { JWTVerifyOptions } from 'jose';
3
+ import './crypto.js';
5
4
 
6
5
  /**
7
6
  * Sign a standard JWT token with the following claims:
@@ -16,7 +15,7 @@ export { JWTVerifyOptions } from 'jose';
16
15
  * @param secret - Secret key to sign the JWT (CryptoKey, KeyObject, string or Uint8Array)
17
16
  * @returns Signed JWT string
18
17
  */
19
- declare const signJWS: (payload: JWTPayload, secret: SecretInput) => Promise<string>;
18
+ declare const signJWS: <Payload extends JWTPayload>(payload: TypedJWTPayload<Partial<Payload>>, secret: SecretInput) => Promise<string>;
20
19
  /**
21
20
  * Verify the integrity of a JWT token and return the payload if valid, rejecting
22
21
  * tokens that use the "none" algorithm to prevent unsecured tokens.
@@ -27,7 +26,7 @@ declare const signJWS: (payload: JWTPayload, secret: SecretInput) => Promise<str
27
26
  * @param options - Additional JWT verification options
28
27
  * @returns verify and return the payload of the JWT
29
28
  */
30
- declare const verifyJWS: (token: string, secret: SecretInput, options?: JWTVerifyOptions) => Promise<JWTPayload>;
29
+ declare const verifyJWS: <Payload extends JWTPayload>(token: string, secret: SecretInput, options?: JWTVerifyOptions) => Promise<TypedJWTPayload<Payload>>;
31
30
  /**
32
31
  * Create a JWS (JSON Web Signature) signer and verifier. It implements the `signJWS`
33
32
  * and `verifyJWS` functions of the module.
@@ -35,9 +34,9 @@ declare const verifyJWS: (token: string, secret: SecretInput, options?: JWTVerif
35
34
  * @param secret - Secret key used for signing and verifying the JWS
36
35
  * @returns signJWS and verifyJWS functions
37
36
  */
38
- declare const createJWS: (secret: SecretInput) => {
39
- signJWS: (payload: JWTPayload) => Promise<string>;
40
- verifyJWS: (payload: string, options?: JWTVerifyOptions) => Promise<JWTPayload>;
37
+ declare const createJWS: <Payload extends JWTPayload>(secret: SecretInput) => {
38
+ signJWS: <SignPayload extends JWTPayload = Payload>(payload: TypedJWTPayload<Partial<SignPayload>>) => Promise<string>;
39
+ verifyJWS: <VerifyPayload extends JWTPayload = Payload>(payload: string, options?: JWTVerifyOptions) => Promise<TypedJWTPayload<VerifyPayload>>;
41
40
  };
42
41
 
43
42
  interface EncryptedPayload {
@@ -83,11 +82,12 @@ declare const MIN_SECRET_ENTROPY_BITS = 4.5;
83
82
  declare const getEntropy: (secret: string) => number;
84
83
  /**
85
84
  * Create a secret in Uint8Array format
85
+ * Uses the standard TextEncoder API for cross-runtime compatibility
86
86
  *
87
87
  * @param secret - The secret as a string or Uint8Array
88
88
  * @returns The secret in Uint8Array format
89
89
  */
90
- declare const createSecret: (secret: SecretInput, length?: number) => crypto.KeyObject | Uint8Array<ArrayBufferLike>;
90
+ declare const createSecret: (secret: SecretInput, length?: number) => Uint8Array<ArrayBufferLike> | CryptoKey;
91
91
  declare const getSecrets: (secret: SecretInput | DerivedKeyInput) => {
92
92
  jwsSecret: SecretInput;
93
93
  jweSecret: SecretInput;
@@ -97,7 +97,13 @@ declare const getSecrets: (secret: SecretInput | DerivedKeyInput) => {
97
97
  * @module @aura-stack/jose
98
98
  */
99
99
 
100
- type SecretInput = KeyObject | Uint8Array | string;
100
+ /**
101
+ * Secret input can be:
102
+ * - CryptoKey: W3C standard key object (works across all runtimes)
103
+ * - Uint8Array: Raw bytes
104
+ * - string: String that will be encoded to UTF-8
105
+ */
106
+ type SecretInput = Uint8Array | string | CryptoKey;
101
107
  type DerivedKeyInput = {
102
108
  jws: SecretInput;
103
109
  jwe: SecretInput;
@@ -106,6 +112,10 @@ type DecodedJWTPayloadOptions = {
106
112
  jws: JWTVerifyOptions;
107
113
  jwt: JWTDecryptOptions;
108
114
  };
115
+ type Prettify<T> = {
116
+ [K in keyof T]: T[K];
117
+ } & {};
118
+ type TypedJWTPayload<Payload extends JWTPayload> = JWTPayload & Payload;
109
119
  /**
110
120
  * Encode a JWT signed and encrypted token. The token first signed using JWS
111
121
  * and then encrypted using JWE to ensure both integrity and confidentiality.
@@ -120,7 +130,7 @@ type DecodedJWTPayloadOptions = {
120
130
  * @param secret - Secret key used for both signing and encrypting the JWT
121
131
  * @returns Promise resolving to the signed and encrypted JWT string
122
132
  */
123
- declare const encodeJWT: (token: JWTPayload, secret: SecretInput | DerivedKeyInput) => Promise<string>;
133
+ declare const encodeJWT: <Payload extends JWTPayload>(token: TypedJWTPayload<Partial<Payload>>, secret: SecretInput | DerivedKeyInput) => Promise<string>;
124
134
  /**
125
135
  * Decode a JWT signed and encrypted token. The token is first decrypted using JWE
126
136
  * and then verified using JWS to ensure both confidentiality and integrity. It
@@ -133,7 +143,7 @@ declare const encodeJWT: (token: JWTPayload, secret: SecretInput | DerivedKeyInp
133
143
  * @param secret
134
144
  * @returns
135
145
  */
136
- declare const decodeJWT: (token: string, secret: SecretInput | DerivedKeyInput, options?: DecodedJWTPayloadOptions) => Promise<JWTPayload>;
146
+ declare const decodeJWT: <Payload extends JWTPayload>(token: string, secret: SecretInput | DerivedKeyInput, options?: DecodedJWTPayloadOptions) => Promise<TypedJWTPayload<Payload>>;
137
147
  /**
138
148
  * Create a JWT handler with encode and decode methods to `signJWS/encryptJWE` and `verifyJWS/decryptJWE`
139
149
  * JWT tokens. The JWTs are signed and verified using JWS and encrypted and decrypted using JWE. It
@@ -142,33 +152,35 @@ declare const decodeJWT: (token: string, secret: SecretInput | DerivedKeyInput,
142
152
  * @param secret - Secret key used for signing, verifying, encrypting and decrypting the JWT
143
153
  * @returns JWT handler object with `signJWS/encryptJWE` and `verifyJWS/decryptJWE` methods
144
154
  */
145
- declare const createJWT: (secret: SecretInput | DerivedKeyInput) => {
146
- encodeJWT: (payload: JWTPayload) => Promise<string>;
147
- decodeJWT: (token: string) => Promise<JWTPayload>;
155
+ declare const createJWT: <Payload extends JWTPayload>(secret: SecretInput | DerivedKeyInput) => {
156
+ encodeJWT: <EncodePayload extends JWTPayload = Payload>(payload: TypedJWTPayload<Partial<EncodePayload>>) => Promise<string>;
157
+ decodeJWT: <DecodePayload extends JWTPayload = Payload>(token: string, options?: DecodedJWTPayloadOptions) => Promise<TypedJWTPayload<DecodePayload>>;
148
158
  };
149
159
 
150
160
  /**
151
161
  * Generate a derived key using HKDF (HMAC-based Extract-and-Expand Key Derivation Function)
162
+ * Uses the Web Crypto API for cross-runtime compatibility (Node.js, Deno, Bun, Browsers)
152
163
  *
153
164
  * @param secret Value used as the input keying material
154
165
  * @param salt Cryptographic salt
155
166
  * @param info Context and application specific information
156
167
  * @param length Size of the derived key in bytes (default is 32 bytes)
157
- * @returns Derived key as Uint8Array and base64 encoded string
168
+ * @returns Derived key as Uint8Array
158
169
  */
159
- declare const deriveKey: (secret: SecretInput, salt: BinaryLike, info: string, length?: number) => {
160
- key: ArrayBuffer;
161
- derivedKey: Buffer<ArrayBuffer>;
162
- };
170
+ declare const deriveKey: (secret: Uint8Array, salt: string | Uint8Array, info: string | Uint8Array, length?: number) => Promise<Uint8Array>;
163
171
  /**
164
172
  * Create a derived key from a given secret.
173
+ * This is an async function that works across all modern JavaScript runtimes.
174
+ *
175
+ * > [!NOTE]
176
+ * > If the secret is a CryptoKey, this function cannot derive keys from it.
165
177
  *
166
178
  * @param secret - The secret as a string or Uint8Array
167
- * @returns The secret in Uint8Array format
179
+ * @param salt - Optional cryptographic salt (defaults to "Aura Jose secret salt")
180
+ * @param info - Optional context information (defaults to "Aura Jose secret derivation")
181
+ * @param length - Size of the derived key in bytes (default is 32 bytes)
182
+ * @returns Promise resolving to the derived key as a Uint8Array
168
183
  */
169
- declare const createDeriveKey: (secret: SecretInput, salt?: BinaryLike, info?: string, length?: number) => {
170
- key: ArrayBuffer;
171
- derivedKey: Buffer<ArrayBuffer>;
172
- };
184
+ declare const createDeriveKey: (secret: SecretInput, salt?: string | Uint8Array, info?: string | Uint8Array, length?: number) => Promise<Uint8Array<ArrayBufferLike>>;
173
185
 
174
- export { type DerivedKeyInput as D, type EncryptedPayload as E, MIN_SECRET_ENTROPY_BITS as M, type SecretInput as S, type EncryptOptions as a, createSecret as b, createJWE as c, createJWS, decryptJWE as d, encryptJWE as e, getSecrets as f, getEntropy as g, type DecodedJWTPayloadOptions as h, encodeJWT as i, decodeJWT as j, createJWT as k, deriveKey as l, createDeriveKey as m, signJWS, verifyJWS };
186
+ export { type DecodedJWTPayloadOptions as D, type EncryptOptions as E, MIN_SECRET_ENTROPY_BITS as M, type Prettify as P, type SecretInput as S, type TypedJWTPayload as T, type EncryptedPayload as a, createSecret as b, createJWE as c, createJWS, decryptJWE as d, encryptJWE as e, getSecrets as f, getEntropy as g, type DerivedKeyInput as h, createDeriveKey as i, createJWT as j, decodeJWT as k, deriveKey as l, encodeJWT as m, signJWS, verifyJWS };
package/dist/sign.js CHANGED
@@ -2,10 +2,11 @@ import {
2
2
  createJWS,
3
3
  signJWS,
4
4
  verifyJWS
5
- } from "./chunk-EX3NULRX.js";
6
- import "./chunk-SES6WQL3.js";
7
- import "./chunk-ZHFHDRQH.js";
8
- import "./chunk-BMXFAB6Q.js";
5
+ } from "./chunk-WXGX6PJ5.js";
6
+ import "./chunk-FCUM7BTG.js";
7
+ import "./chunk-MWFJ4CA5.js";
8
+ import "./chunk-RQFUZSWH.js";
9
+ import "./chunk-NGBYHSRN.js";
9
10
  export {
10
11
  createJWS,
11
12
  signJWS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aura-stack/jose",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "JOSE utilities for @aura-stack/auth",
@@ -40,6 +40,11 @@
40
40
  "types": "./dist/deriveKey.d.ts",
41
41
  "require": "./dist/deriveKey.cjs",
42
42
  "import": "./dist/deriveKey.js"
43
+ },
44
+ "./crypto": {
45
+ "types": "./dist/crypto.d.ts",
46
+ "require": "./dist/crypto.cjs",
47
+ "import": "./dist/crypto.js"
43
48
  }
44
49
  },
45
50
  "keywords": [
@@ -57,7 +62,6 @@
57
62
  "jose": "^6.1.2"
58
63
  },
59
64
  "devDependencies": {
60
- "@types/node": "^24.9.2",
61
65
  "typescript": "^5.9.2",
62
66
  "@aura-stack/tsconfig": "0.0.0",
63
67
  "@aura-stack/tsup-config": "0.0.0"
@@ -1,27 +0,0 @@
1
- import {
2
- createSecret
3
- } from "./chunk-SES6WQL3.js";
4
-
5
- // src/deriveKey.ts
6
- import { hkdfSync } from "crypto";
7
- var deriveKey = (secret, salt, info, length = 32) => {
8
- try {
9
- const key = hkdfSync("SHA256", secret, salt, info, length);
10
- const derivedKey = Buffer.from(key);
11
- return {
12
- key,
13
- derivedKey
14
- };
15
- } catch (error) {
16
- throw new Error("Failed to create a derived key (HKDF)", { cause: error });
17
- }
18
- };
19
- var createDeriveKey = (secret, salt, info, length = 32) => {
20
- const secretKey = createSecret(secret);
21
- return deriveKey(secretKey, salt ?? "Aura Jose secret salt", info ?? "Aura Jose secret derivation", length);
22
- };
23
-
24
- export {
25
- deriveKey,
26
- createDeriveKey
27
- };