unjwt 0.5.5 → 0.5.7
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.CGkRbYL2.d.mts → unjwt.D_Mabhgz.d.mts} +8 -2
- package/dist/shared/{unjwt.BY2vKT86.mjs → unjwt.DqUOpdA-.mjs} +38 -9
- 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.DqUOpdA-.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
|
@@ -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
|
|
@@ -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,13 @@ 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 iat = typeof payload.iat === "number" ? payload.iat : Math.round((options.currentDate ?? /* @__PURE__ */ new Date()).getTime() / 1e3);
|
|
34
|
+
computedPayload.iat = iat;
|
|
35
|
+
computedPayload.exp = iat + options.expiresIn;
|
|
36
|
+
}
|
|
29
37
|
const protectedHeaderString = JSON.stringify(protectedHeader);
|
|
30
38
|
const protectedHeaderEncoded = base64UrlEncode(protectedHeaderString);
|
|
31
39
|
let payloadBytes;
|
|
@@ -34,7 +42,9 @@ async function sign(payload, key, options = {}) {
|
|
|
34
42
|
} else if (typeof payload === "string") {
|
|
35
43
|
payloadBytes = textEncoder.encode(payload);
|
|
36
44
|
} else if (typeof payload === "object" && payload !== null) {
|
|
37
|
-
payloadBytes = textEncoder.encode(
|
|
45
|
+
payloadBytes = textEncoder.encode(
|
|
46
|
+
JSON.stringify(computedPayload || payload)
|
|
47
|
+
);
|
|
38
48
|
} else {
|
|
39
49
|
throw new TypeError(
|
|
40
50
|
"Payload must be a string, Uint8Array, or a JSON-serializable object."
|
|
@@ -160,11 +170,12 @@ async function verify(jws, key, options = {}) {
|
|
|
160
170
|
);
|
|
161
171
|
}
|
|
162
172
|
}
|
|
163
|
-
if (payload && typeof payload === "object" && !options.forceUint8Array) {
|
|
173
|
+
if (payload && typeof payload === "object" && protectedHeader.typ === "JWT" && !options.forceUint8Array) {
|
|
164
174
|
const jwtClaims = payload;
|
|
165
|
-
const clockTolerance =
|
|
166
|
-
const
|
|
167
|
-
|
|
175
|
+
const clockTolerance = options.clockTolerance ?? 0;
|
|
176
|
+
const currentTime = Math.round(
|
|
177
|
+
(options.currentDate ?? /* @__PURE__ */ new Date()).getTime() / 1e3
|
|
178
|
+
);
|
|
168
179
|
const allRequiredClaims = new Set(options.requiredClaims || []);
|
|
169
180
|
const missingClaims = /* @__PURE__ */ new Set();
|
|
170
181
|
if (options.issuer) allRequiredClaims.add("iss");
|
|
@@ -203,12 +214,12 @@ async function verify(jws, key, options = {}) {
|
|
|
203
214
|
);
|
|
204
215
|
}
|
|
205
216
|
}
|
|
206
|
-
if (typeof jwtClaims.nbf === "number" && jwtClaims.nbf
|
|
217
|
+
if (typeof jwtClaims.nbf === "number" && jwtClaims.nbf > currentTime + clockTolerance) {
|
|
207
218
|
throw new Error(
|
|
208
219
|
`JWT "nbf" (Not Before) Claim validation failed: Token is not yet valid (nbf: ${new Date(jwtClaims.nbf * 1e3).toISOString()})`
|
|
209
220
|
);
|
|
210
221
|
}
|
|
211
|
-
if (typeof jwtClaims.exp === "number" && jwtClaims.exp
|
|
222
|
+
if (typeof jwtClaims.exp === "number" && jwtClaims.exp <= currentTime - clockTolerance) {
|
|
212
223
|
throw new Error(
|
|
213
224
|
`JWT "exp" (Expiration Time) Claim validation failed: Token has expired (exp: ${new Date(jwtClaims.exp * 1e3).toISOString()})`
|
|
214
225
|
);
|
|
@@ -219,12 +230,12 @@ async function verify(jws, key, options = {}) {
|
|
|
219
230
|
'JWT "iat" (Issued At) Claim must be a number when maxTokenAge is set.'
|
|
220
231
|
);
|
|
221
232
|
}
|
|
222
|
-
if (jwtClaims.iat
|
|
233
|
+
if (jwtClaims.iat > currentTime + clockTolerance) {
|
|
223
234
|
throw new Error(
|
|
224
235
|
`JWT "iat" (Issued At) Claim validation failed: Token was issued in the future (iat: ${new Date(jwtClaims.iat * 1e3).toISOString()})`
|
|
225
236
|
);
|
|
226
237
|
}
|
|
227
|
-
if (jwtClaims.iat
|
|
238
|
+
if (jwtClaims.iat < currentTime - options.maxTokenAge - clockTolerance) {
|
|
228
239
|
throw new Error(
|
|
229
240
|
`JWT "iat" (Issued At) Claim validation failed: Token is too old (maxTokenAge: ${options.maxTokenAge}s, iat: ${new Date(jwtClaims.iat * 1e3).toISOString()})`
|
|
230
241
|
);
|
|
@@ -236,6 +247,24 @@ async function verify(jws, key, options = {}) {
|
|
|
236
247
|
protectedHeader
|
|
237
248
|
};
|
|
238
249
|
}
|
|
250
|
+
function validateKeyLength(key, alg) {
|
|
251
|
+
if (!alg || isJWK(key)) return;
|
|
252
|
+
if (alg.startsWith("HS") && key instanceof Uint8Array) {
|
|
253
|
+
const algLength = Number.parseInt(alg.slice(2)) / 8;
|
|
254
|
+
if (key.length < algLength) {
|
|
255
|
+
throw new TypeError(
|
|
256
|
+
`${alg} requires key length to be ${algLength} bytes or larger`
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
} else if ((alg.startsWith("RS") || alg.startsWith("PS")) && key instanceof CryptoKey) {
|
|
260
|
+
const { modulusLength } = key.algorithm;
|
|
261
|
+
if (typeof modulusLength !== "number" || modulusLength < 2048) {
|
|
262
|
+
throw new TypeError(
|
|
263
|
+
`${alg} requires key modulusLength to be 2048 bits or larger`
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
239
268
|
|
|
240
269
|
const jws = {
|
|
241
270
|
__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
|