unjwt 0.5.5 → 0.5.6
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/README.md +10 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/jws.d.mts +1 -1
- package/dist/jws.d.ts +1 -1
- package/dist/jws.mjs +1 -1
- package/dist/shared/{unjwt.BY2vKT86.mjs → unjwt.DQNXDqfd.mjs} +40 -8
- package/dist/shared/{unjwt.CGkRbYL2.d.mts → unjwt.D_Mabhgz.d.mts} +8 -2
- package/dist/shared/{unjwt.RZpKLLLg.d.ts → unjwt.w-IAnI15.d.ts} +8 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,6 +97,8 @@ import {
|
|
|
97
97
|
} from "https://esm.sh/unjwt/utils";
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
+
---
|
|
101
|
+
|
|
100
102
|
### JWS (JSON Web Signature, [RFC 7515](https://datatracker.ietf.org/doc/html/rfc7515))
|
|
101
103
|
|
|
102
104
|
Functions to sign and verify data according to the JWS specification.
|
|
@@ -110,6 +112,8 @@ Creates a JWS token.
|
|
|
110
112
|
- `options`:
|
|
111
113
|
- `alg`: (Required) The JWS algorithm (e.g., `"HS256"`, `"RS256"`, `"ES256"`, `"PS256"`).
|
|
112
114
|
- `protectedHeader`: An object for additional JWS Protected Header parameters (e.g., `kid`, `typ`, `cty`, `crit`, `b64`). If `payload` is an object and `typ` is not set, it defaults to `"JWT"`. The `b64` parameter ([RFC7797 section-3](https://datatracker.ietf.org/doc/html/rfc7797#section-3)) controls payload encoding (defaults to `true`, meaning Base64URL encoded).
|
|
115
|
+
- `expiresIn`: Sets an expiration time in seconds (e.g., `3600` for 1 hour). If `iat` is missing it will be set to the current time. If `exp` is missing it will be set to `iat + expiresIn`. This is only applied if `payload` is a JWT.
|
|
116
|
+
- `currentDate`: The current date for computing `expiresIn` option. Defaults to `new Date()`.
|
|
113
117
|
|
|
114
118
|
Returns a `Promise<string>` resolving to the JWS token in Compact Serialization format.
|
|
115
119
|
|
|
@@ -191,6 +195,8 @@ const { payload } = await verify(token, keyLookup, { algorithms: ["RS256"] });
|
|
|
191
195
|
console.log(payload); // { userId: 123, permissions: ["read"] }
|
|
192
196
|
```
|
|
193
197
|
|
|
198
|
+
---
|
|
199
|
+
|
|
194
200
|
### JWE (JSON Web Encryption, [RFC 7516](https://datatracker.ietf.org/doc/html/rfc7516))
|
|
195
201
|
|
|
196
202
|
Functions to encrypt and decrypt data according to the JWE specification.
|
|
@@ -293,6 +299,8 @@ async function decryptData(jweToken: string, kek: CryptoKey) {
|
|
|
293
299
|
}
|
|
294
300
|
```
|
|
295
301
|
|
|
302
|
+
---
|
|
303
|
+
|
|
296
304
|
### JWK (JSON Web Key, [RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517))
|
|
297
305
|
|
|
298
306
|
Utilities for working with JSON Web Keys.
|
|
@@ -591,6 +599,8 @@ console.log(rsaPublicSpki);
|
|
|
591
599
|
// -----END PUBLIC KEY-----
|
|
592
600
|
```
|
|
593
601
|
|
|
602
|
+
---
|
|
603
|
+
|
|
594
604
|
### Utility Functions
|
|
595
605
|
|
|
596
606
|
`unjwt/utils` exports several helpful functions:
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { C as CompositeKey, d as ContentEncryptionAlgorithm, D as DeriveKeyOptions, c as DeriveKeyReturn, G as GenerateKeyAlgorithm, a as GenerateKeyOptions, b as GenerateKeyReturn, m as JWK, E as JWKAlgorithm, F as JWKPEMAlgorithm, J as JWKParameters, n as JWKSet, v as JWK_AES_CBC_HMAC, w as JWK_AES_GCM, u as JWK_AES_GCM_KW, t as JWK_AES_KW, B as JWK_Asymmetric_Algorithm, h as JWK_EC, y as JWK_ECDH_ES, r as JWK_ECDSA, g as JWK_EC_Private, f as JWK_EC_Public, z as JWK_ED, o as JWK_HMAC, x as JWK_PBES2, k as JWK_RSA, s as JWK_RSA_ENC, q as JWK_RSA_PSS, j as JWK_RSA_Private, i as JWK_RSA_Public, p as JWK_RSA_SIGN, A as JWK_Symmetric_Algorithm, l as JWK_oct, K as KeyManagementAlgorithm, U as UnwrapKeyOptions, W as WrapKeyOptions, e as WrapKeyResult } from './shared/unjwt.D9da8HQF.mjs';
|
|
2
2
|
export { b as JWT, a as JWTClaims, J as JoseHeaderParameters } from './shared/unjwt.BvIkEGGz.mjs';
|
|
3
|
-
export { J as JWSAlgorithm, a as JWSHeaderParameters, f as JWSKeyLookupFunction, b as JWSProtectedHeader, c as JWSSignOptions, e as JWSVerifyOptions, d as JWSVerifyResult, j as jws } from './shared/unjwt.
|
|
3
|
+
export { J as JWSAlgorithm, a as JWSHeaderParameters, f as JWSKeyLookupFunction, b as JWSProtectedHeader, c as JWSSignOptions, e as JWSVerifyOptions, d as JWSVerifyResult, j as jws } from './shared/unjwt.D_Mabhgz.mjs';
|
|
4
4
|
export { d as JWEDecryptOptions, e as JWEDecryptResult, b as JWEEncryptOptions, J as JWEHeaderParameters, c as JWEKeyLookupFunction, a as JWEKeyManagementHeaderParameters, j as jwe } from './shared/unjwt.8w7jp2aw.mjs';
|
|
5
5
|
export { i as utils } from './shared/unjwt.CbvzYE-m.mjs';
|
|
6
6
|
export { j as jwk } from './shared/unjwt.DH1p_WL8.mjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { C as CompositeKey, d as ContentEncryptionAlgorithm, D as DeriveKeyOptions, c as DeriveKeyReturn, G as GenerateKeyAlgorithm, a as GenerateKeyOptions, b as GenerateKeyReturn, m as JWK, E as JWKAlgorithm, F as JWKPEMAlgorithm, J as JWKParameters, n as JWKSet, v as JWK_AES_CBC_HMAC, w as JWK_AES_GCM, u as JWK_AES_GCM_KW, t as JWK_AES_KW, B as JWK_Asymmetric_Algorithm, h as JWK_EC, y as JWK_ECDH_ES, r as JWK_ECDSA, g as JWK_EC_Private, f as JWK_EC_Public, z as JWK_ED, o as JWK_HMAC, x as JWK_PBES2, k as JWK_RSA, s as JWK_RSA_ENC, q as JWK_RSA_PSS, j as JWK_RSA_Private, i as JWK_RSA_Public, p as JWK_RSA_SIGN, A as JWK_Symmetric_Algorithm, l as JWK_oct, K as KeyManagementAlgorithm, U as UnwrapKeyOptions, W as WrapKeyOptions, e as WrapKeyResult } from './shared/unjwt.D9da8HQF.js';
|
|
2
2
|
export { b as JWT, a as JWTClaims, J as JoseHeaderParameters } from './shared/unjwt.c10n3uM8.js';
|
|
3
|
-
export { J as JWSAlgorithm, a as JWSHeaderParameters, f as JWSKeyLookupFunction, b as JWSProtectedHeader, c as JWSSignOptions, e as JWSVerifyOptions, d as JWSVerifyResult, j as jws } from './shared/unjwt.
|
|
3
|
+
export { J as JWSAlgorithm, a as JWSHeaderParameters, f as JWSKeyLookupFunction, b as JWSProtectedHeader, c as JWSSignOptions, e as JWSVerifyOptions, d as JWSVerifyResult, j as jws } from './shared/unjwt.w-IAnI15.js';
|
|
4
4
|
export { d as JWEDecryptOptions, e as JWEDecryptResult, b as JWEEncryptOptions, J as JWEHeaderParameters, c as JWEKeyLookupFunction, a as JWEKeyManagementHeaderParameters, j as jwe } from './shared/unjwt.CoSilGqk.js';
|
|
5
5
|
export { i as utils } from './shared/unjwt.D4DUiNeM.js';
|
|
6
6
|
export { j as jwk } from './shared/unjwt.CrcUJklb.js';
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { i as utils } from './shared/unjwt.BHpknTpg.mjs';
|
|
2
2
|
export { j as jwe } from './shared/unjwt.B2olxeGL.mjs';
|
|
3
3
|
export { j as jwk } from './shared/unjwt.DRUXIabl.mjs';
|
|
4
|
-
export { j as jws } from './shared/unjwt.
|
|
4
|
+
export { j as jws } from './shared/unjwt.DQNXDqfd.mjs';
|
|
5
5
|
import './shared/unjwt.Ca03jPX3.mjs';
|
package/dist/jws.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import './shared/unjwt.D9da8HQF.mjs';
|
|
2
2
|
import './shared/unjwt.BvIkEGGz.mjs';
|
|
3
|
-
export { J as JWSAlgorithm, a as JWSHeaderParameters, f as JWSKeyLookupFunction, b as JWSProtectedHeader, c as JWSSignOptions, e as JWSVerifyOptions, d as JWSVerifyResult, s as sign, v as verify } from './shared/unjwt.
|
|
3
|
+
export { J as JWSAlgorithm, a as JWSHeaderParameters, f as JWSKeyLookupFunction, b as JWSProtectedHeader, c as JWSSignOptions, e as JWSVerifyOptions, d as JWSVerifyResult, s as sign, v as verify } from './shared/unjwt.D_Mabhgz.mjs';
|
package/dist/jws.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import './shared/unjwt.D9da8HQF.js';
|
|
2
2
|
import './shared/unjwt.c10n3uM8.js';
|
|
3
|
-
export { J as JWSAlgorithm, a as JWSHeaderParameters, f as JWSKeyLookupFunction, b as JWSProtectedHeader, c as JWSSignOptions, e as JWSVerifyOptions, d as JWSVerifyResult, s as sign, v as verify } from './shared/unjwt.
|
|
3
|
+
export { J as JWSAlgorithm, a as JWSHeaderParameters, f as JWSKeyLookupFunction, b as JWSProtectedHeader, c as JWSSignOptions, e as JWSVerifyOptions, d as JWSVerifyResult, s as sign, v as verify } from './shared/unjwt.w-IAnI15.js';
|
package/dist/jws.mjs
CHANGED
|
@@ -12,6 +12,7 @@ async function sign(payload, key, options = {}) {
|
|
|
12
12
|
throw new TypeError('JWS "alg" (Algorithm) must be provided in options');
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
validateKeyLength(key, alg);
|
|
15
16
|
const signingKey = await importKey(key, alg);
|
|
16
17
|
const protectedHeader = {
|
|
17
18
|
...additionalProtectedHeader,
|
|
@@ -26,6 +27,16 @@ async function sign(payload, key, options = {}) {
|
|
|
26
27
|
if (protectedHeader.b64 === true) {
|
|
27
28
|
delete protectedHeader.b64;
|
|
28
29
|
}
|
|
30
|
+
let computedPayload = void 0;
|
|
31
|
+
if (options.expiresIn !== void 0 && protectedHeader.typ === "JWT" && typeof payload === "object" && !(payload instanceof Uint8Array) && !payload.exp) {
|
|
32
|
+
computedPayload = { ...payload };
|
|
33
|
+
const currentTime = Math.round(
|
|
34
|
+
(options.currentDate ?? /* @__PURE__ */ new Date()).getTime() / 1e3
|
|
35
|
+
);
|
|
36
|
+
const iat = typeof payload.iat === "number" ? payload.iat : currentTime;
|
|
37
|
+
computedPayload.iat = iat;
|
|
38
|
+
computedPayload.exp = iat + options.expiresIn;
|
|
39
|
+
}
|
|
29
40
|
const protectedHeaderString = JSON.stringify(protectedHeader);
|
|
30
41
|
const protectedHeaderEncoded = base64UrlEncode(protectedHeaderString);
|
|
31
42
|
let payloadBytes;
|
|
@@ -34,7 +45,9 @@ async function sign(payload, key, options = {}) {
|
|
|
34
45
|
} else if (typeof payload === "string") {
|
|
35
46
|
payloadBytes = textEncoder.encode(payload);
|
|
36
47
|
} else if (typeof payload === "object" && payload !== null) {
|
|
37
|
-
payloadBytes = textEncoder.encode(
|
|
48
|
+
payloadBytes = textEncoder.encode(
|
|
49
|
+
JSON.stringify(computedPayload || payload)
|
|
50
|
+
);
|
|
38
51
|
} else {
|
|
39
52
|
throw new TypeError(
|
|
40
53
|
"Payload must be a string, Uint8Array, or a JSON-serializable object."
|
|
@@ -162,9 +175,10 @@ async function verify(jws, key, options = {}) {
|
|
|
162
175
|
}
|
|
163
176
|
if (payload && typeof payload === "object" && !options.forceUint8Array) {
|
|
164
177
|
const jwtClaims = payload;
|
|
165
|
-
const clockTolerance =
|
|
166
|
-
const
|
|
167
|
-
|
|
178
|
+
const clockTolerance = options.clockTolerance ?? 0;
|
|
179
|
+
const currentTime = Math.round(
|
|
180
|
+
(options.currentDate ?? /* @__PURE__ */ new Date()).getTime() / 1e3
|
|
181
|
+
);
|
|
168
182
|
const allRequiredClaims = new Set(options.requiredClaims || []);
|
|
169
183
|
const missingClaims = /* @__PURE__ */ new Set();
|
|
170
184
|
if (options.issuer) allRequiredClaims.add("iss");
|
|
@@ -203,12 +217,12 @@ async function verify(jws, key, options = {}) {
|
|
|
203
217
|
);
|
|
204
218
|
}
|
|
205
219
|
}
|
|
206
|
-
if (typeof jwtClaims.nbf === "number" && jwtClaims.nbf
|
|
220
|
+
if (typeof jwtClaims.nbf === "number" && jwtClaims.nbf > currentTime + clockTolerance) {
|
|
207
221
|
throw new Error(
|
|
208
222
|
`JWT "nbf" (Not Before) Claim validation failed: Token is not yet valid (nbf: ${new Date(jwtClaims.nbf * 1e3).toISOString()})`
|
|
209
223
|
);
|
|
210
224
|
}
|
|
211
|
-
if (typeof jwtClaims.exp === "number" && jwtClaims.exp
|
|
225
|
+
if (typeof jwtClaims.exp === "number" && jwtClaims.exp <= currentTime - clockTolerance) {
|
|
212
226
|
throw new Error(
|
|
213
227
|
`JWT "exp" (Expiration Time) Claim validation failed: Token has expired (exp: ${new Date(jwtClaims.exp * 1e3).toISOString()})`
|
|
214
228
|
);
|
|
@@ -219,12 +233,12 @@ async function verify(jws, key, options = {}) {
|
|
|
219
233
|
'JWT "iat" (Issued At) Claim must be a number when maxTokenAge is set.'
|
|
220
234
|
);
|
|
221
235
|
}
|
|
222
|
-
if (jwtClaims.iat
|
|
236
|
+
if (jwtClaims.iat > currentTime + clockTolerance) {
|
|
223
237
|
throw new Error(
|
|
224
238
|
`JWT "iat" (Issued At) Claim validation failed: Token was issued in the future (iat: ${new Date(jwtClaims.iat * 1e3).toISOString()})`
|
|
225
239
|
);
|
|
226
240
|
}
|
|
227
|
-
if (jwtClaims.iat
|
|
241
|
+
if (jwtClaims.iat < currentTime - options.maxTokenAge - clockTolerance) {
|
|
228
242
|
throw new Error(
|
|
229
243
|
`JWT "iat" (Issued At) Claim validation failed: Token is too old (maxTokenAge: ${options.maxTokenAge}s, iat: ${new Date(jwtClaims.iat * 1e3).toISOString()})`
|
|
230
244
|
);
|
|
@@ -236,6 +250,24 @@ async function verify(jws, key, options = {}) {
|
|
|
236
250
|
protectedHeader
|
|
237
251
|
};
|
|
238
252
|
}
|
|
253
|
+
function validateKeyLength(key, alg) {
|
|
254
|
+
if (!alg || isJWK(key)) return;
|
|
255
|
+
if (alg.startsWith("HS") && key instanceof Uint8Array) {
|
|
256
|
+
const algLength = Number.parseInt(alg.slice(2)) / 8;
|
|
257
|
+
if (key.length < algLength) {
|
|
258
|
+
throw new TypeError(
|
|
259
|
+
`${alg} requires key length to be ${algLength} bytes or larger`
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
} else if ((alg.startsWith("RS") || alg.startsWith("PS")) && key instanceof CryptoKey) {
|
|
263
|
+
const { modulusLength } = key.algorithm;
|
|
264
|
+
if (typeof modulusLength !== "number" || modulusLength < 2048) {
|
|
265
|
+
throw new TypeError(
|
|
266
|
+
`${alg} requires key modulusLength to be 2048 bits or larger`
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
239
271
|
|
|
240
272
|
const jws = {
|
|
241
273
|
__proto__: null,
|
|
@@ -31,6 +31,12 @@ interface JWSSignOptions {
|
|
|
31
31
|
* `typ` defaults to "JWT" if not provided.
|
|
32
32
|
*/
|
|
33
33
|
protectedHeader?: JWSHeaderParameters;
|
|
34
|
+
/** Date to use when comparing NumericDate claims, defaults to `new Date()`. */
|
|
35
|
+
currentDate?: Date;
|
|
36
|
+
/**
|
|
37
|
+
* Time at which the JWS should expire, if no `exp` was already provided.
|
|
38
|
+
*/
|
|
39
|
+
expiresIn?: number;
|
|
34
40
|
}
|
|
35
41
|
/** Result of JWS verification */
|
|
36
42
|
interface JWSVerifyResult<T extends JWTClaims | Uint8Array | string = JWTClaims | Uint8Array | string> {
|
|
@@ -45,8 +51,6 @@ interface JWSVerifyOptions {
|
|
|
45
51
|
algorithms?: JWSAlgorithm[];
|
|
46
52
|
/** If true, forces the payload to be returned as a Uint8Array, otherwise type is inferred. */
|
|
47
53
|
forceUint8Array?: boolean;
|
|
48
|
-
/** List of critical header parameters that must be understood and processed. */
|
|
49
|
-
requiredHeaders?: string[];
|
|
50
54
|
/**
|
|
51
55
|
* Expected JWT "aud" (Audience) Claim value(s).
|
|
52
56
|
*
|
|
@@ -86,6 +90,8 @@ interface JWSVerifyOptions {
|
|
|
86
90
|
typ?: string;
|
|
87
91
|
/** Date to use when comparing NumericDate claims, defaults to `new Date()`. */
|
|
88
92
|
currentDate?: Date;
|
|
93
|
+
/** List of critical header parameters that must be understood and processed. */
|
|
94
|
+
requiredHeaders?: string[];
|
|
89
95
|
/**
|
|
90
96
|
* Array of required Claim Names that must be present in the JWT Claims Set. Default is that: if
|
|
91
97
|
* the {@link issuer `issuer` option} is set, then JWT "iss" (Issuer) Claim must be present; if the
|
|
@@ -31,6 +31,12 @@ interface JWSSignOptions {
|
|
|
31
31
|
* `typ` defaults to "JWT" if not provided.
|
|
32
32
|
*/
|
|
33
33
|
protectedHeader?: JWSHeaderParameters;
|
|
34
|
+
/** Date to use when comparing NumericDate claims, defaults to `new Date()`. */
|
|
35
|
+
currentDate?: Date;
|
|
36
|
+
/**
|
|
37
|
+
* Time at which the JWS should expire, if no `exp` was already provided.
|
|
38
|
+
*/
|
|
39
|
+
expiresIn?: number;
|
|
34
40
|
}
|
|
35
41
|
/** Result of JWS verification */
|
|
36
42
|
interface JWSVerifyResult<T extends JWTClaims | Uint8Array | string = JWTClaims | Uint8Array | string> {
|
|
@@ -45,8 +51,6 @@ interface JWSVerifyOptions {
|
|
|
45
51
|
algorithms?: JWSAlgorithm[];
|
|
46
52
|
/** If true, forces the payload to be returned as a Uint8Array, otherwise type is inferred. */
|
|
47
53
|
forceUint8Array?: boolean;
|
|
48
|
-
/** List of critical header parameters that must be understood and processed. */
|
|
49
|
-
requiredHeaders?: string[];
|
|
50
54
|
/**
|
|
51
55
|
* Expected JWT "aud" (Audience) Claim value(s).
|
|
52
56
|
*
|
|
@@ -86,6 +90,8 @@ interface JWSVerifyOptions {
|
|
|
86
90
|
typ?: string;
|
|
87
91
|
/** Date to use when comparing NumericDate claims, defaults to `new Date()`. */
|
|
88
92
|
currentDate?: Date;
|
|
93
|
+
/** List of critical header parameters that must be understood and processed. */
|
|
94
|
+
requiredHeaders?: string[];
|
|
89
95
|
/**
|
|
90
96
|
* Array of required Claim Names that must be present in the JWT Claims Set. Default is that: if
|
|
91
97
|
* the {@link issuer `issuer` option} is set, then JWT "iss" (Issuer) Claim must be present; if the
|