jose 4.13.2 → 4.14.1
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.
|
@@ -29,15 +29,26 @@ export default (protectedHeader, encodedPayload, options = {}) => {
|
|
|
29
29
|
if (!isObject(payload)) {
|
|
30
30
|
throw new JWTInvalid('JWT Claims Set must be a top-level JSON object');
|
|
31
31
|
}
|
|
32
|
-
const { issuer } = options;
|
|
32
|
+
const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
|
|
33
|
+
if (maxTokenAge !== undefined)
|
|
34
|
+
requiredClaims.push('iat');
|
|
35
|
+
if (audience !== undefined)
|
|
36
|
+
requiredClaims.push('aud');
|
|
37
|
+
if (subject !== undefined)
|
|
38
|
+
requiredClaims.push('sub');
|
|
39
|
+
if (issuer !== undefined)
|
|
40
|
+
requiredClaims.push('iss');
|
|
41
|
+
for (const claim of new Set(requiredClaims.reverse())) {
|
|
42
|
+
if (!(claim in payload)) {
|
|
43
|
+
throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, claim, 'missing');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
33
46
|
if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
|
|
34
47
|
throw new JWTClaimValidationFailed('unexpected "iss" claim value', 'iss', 'check_failed');
|
|
35
48
|
}
|
|
36
|
-
const { subject } = options;
|
|
37
49
|
if (subject && payload.sub !== subject) {
|
|
38
50
|
throw new JWTClaimValidationFailed('unexpected "sub" claim value', 'sub', 'check_failed');
|
|
39
51
|
}
|
|
40
|
-
const { audience } = options;
|
|
41
52
|
if (audience &&
|
|
42
53
|
!checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience)) {
|
|
43
54
|
throw new JWTClaimValidationFailed('unexpected "aud" claim value', 'aud', 'check_failed');
|
|
@@ -58,7 +69,7 @@ export default (protectedHeader, encodedPayload, options = {}) => {
|
|
|
58
69
|
}
|
|
59
70
|
const { currentDate } = options;
|
|
60
71
|
const now = epoch(currentDate || new Date());
|
|
61
|
-
if ((payload.iat !== undefined ||
|
|
72
|
+
if ((payload.iat !== undefined || maxTokenAge) && typeof payload.iat !== 'number') {
|
|
62
73
|
throw new JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid');
|
|
63
74
|
}
|
|
64
75
|
if (payload.nbf !== undefined) {
|
|
@@ -77,9 +88,9 @@ export default (protectedHeader, encodedPayload, options = {}) => {
|
|
|
77
88
|
throw new JWTExpired('"exp" claim timestamp check failed', 'exp', 'check_failed');
|
|
78
89
|
}
|
|
79
90
|
}
|
|
80
|
-
if (
|
|
91
|
+
if (maxTokenAge) {
|
|
81
92
|
const age = now - payload.iat;
|
|
82
|
-
const max = typeof
|
|
93
|
+
const max = typeof maxTokenAge === 'number' ? maxTokenAge : secs(maxTokenAge);
|
|
83
94
|
if (age - tolerance > max) {
|
|
84
95
|
throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', 'iat', 'check_failed');
|
|
85
96
|
}
|
|
@@ -31,15 +31,26 @@ exports.default = (protectedHeader, encodedPayload, options = {}) => {
|
|
|
31
31
|
if (!(0, is_object_js_1.default)(payload)) {
|
|
32
32
|
throw new errors_js_1.JWTInvalid('JWT Claims Set must be a top-level JSON object');
|
|
33
33
|
}
|
|
34
|
-
const { issuer } = options;
|
|
34
|
+
const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
|
|
35
|
+
if (maxTokenAge !== undefined)
|
|
36
|
+
requiredClaims.push('iat');
|
|
37
|
+
if (audience !== undefined)
|
|
38
|
+
requiredClaims.push('aud');
|
|
39
|
+
if (subject !== undefined)
|
|
40
|
+
requiredClaims.push('sub');
|
|
41
|
+
if (issuer !== undefined)
|
|
42
|
+
requiredClaims.push('iss');
|
|
43
|
+
for (const claim of new Set(requiredClaims.reverse())) {
|
|
44
|
+
if (!(claim in payload)) {
|
|
45
|
+
throw new errors_js_1.JWTClaimValidationFailed(`missing required "${claim}" claim`, claim, 'missing');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
35
48
|
if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
|
|
36
49
|
throw new errors_js_1.JWTClaimValidationFailed('unexpected "iss" claim value', 'iss', 'check_failed');
|
|
37
50
|
}
|
|
38
|
-
const { subject } = options;
|
|
39
51
|
if (subject && payload.sub !== subject) {
|
|
40
52
|
throw new errors_js_1.JWTClaimValidationFailed('unexpected "sub" claim value', 'sub', 'check_failed');
|
|
41
53
|
}
|
|
42
|
-
const { audience } = options;
|
|
43
54
|
if (audience &&
|
|
44
55
|
!checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience)) {
|
|
45
56
|
throw new errors_js_1.JWTClaimValidationFailed('unexpected "aud" claim value', 'aud', 'check_failed');
|
|
@@ -60,7 +71,7 @@ exports.default = (protectedHeader, encodedPayload, options = {}) => {
|
|
|
60
71
|
}
|
|
61
72
|
const { currentDate } = options;
|
|
62
73
|
const now = (0, epoch_js_1.default)(currentDate || new Date());
|
|
63
|
-
if ((payload.iat !== undefined ||
|
|
74
|
+
if ((payload.iat !== undefined || maxTokenAge) && typeof payload.iat !== 'number') {
|
|
64
75
|
throw new errors_js_1.JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid');
|
|
65
76
|
}
|
|
66
77
|
if (payload.nbf !== undefined) {
|
|
@@ -79,9 +90,9 @@ exports.default = (protectedHeader, encodedPayload, options = {}) => {
|
|
|
79
90
|
throw new errors_js_1.JWTExpired('"exp" claim timestamp check failed', 'exp', 'check_failed');
|
|
80
91
|
}
|
|
81
92
|
}
|
|
82
|
-
if (
|
|
93
|
+
if (maxTokenAge) {
|
|
83
94
|
const age = now - payload.iat;
|
|
84
|
-
const max = typeof
|
|
95
|
+
const max = typeof maxTokenAge === 'number' ? maxTokenAge : (0, secs_js_1.default)(maxTokenAge);
|
|
85
96
|
if (age - tolerance > max) {
|
|
86
97
|
throw new errors_js_1.JWTExpired('"iat" claim timestamp check failed (too far in the past)', 'iat', 'check_failed');
|
|
87
98
|
}
|
|
@@ -29,15 +29,26 @@ export default (protectedHeader, encodedPayload, options = {}) => {
|
|
|
29
29
|
if (!isObject(payload)) {
|
|
30
30
|
throw new JWTInvalid('JWT Claims Set must be a top-level JSON object');
|
|
31
31
|
}
|
|
32
|
-
const { issuer } = options;
|
|
32
|
+
const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
|
|
33
|
+
if (maxTokenAge !== undefined)
|
|
34
|
+
requiredClaims.push('iat');
|
|
35
|
+
if (audience !== undefined)
|
|
36
|
+
requiredClaims.push('aud');
|
|
37
|
+
if (subject !== undefined)
|
|
38
|
+
requiredClaims.push('sub');
|
|
39
|
+
if (issuer !== undefined)
|
|
40
|
+
requiredClaims.push('iss');
|
|
41
|
+
for (const claim of new Set(requiredClaims.reverse())) {
|
|
42
|
+
if (!(claim in payload)) {
|
|
43
|
+
throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, claim, 'missing');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
33
46
|
if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
|
|
34
47
|
throw new JWTClaimValidationFailed('unexpected "iss" claim value', 'iss', 'check_failed');
|
|
35
48
|
}
|
|
36
|
-
const { subject } = options;
|
|
37
49
|
if (subject && payload.sub !== subject) {
|
|
38
50
|
throw new JWTClaimValidationFailed('unexpected "sub" claim value', 'sub', 'check_failed');
|
|
39
51
|
}
|
|
40
|
-
const { audience } = options;
|
|
41
52
|
if (audience &&
|
|
42
53
|
!checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience)) {
|
|
43
54
|
throw new JWTClaimValidationFailed('unexpected "aud" claim value', 'aud', 'check_failed');
|
|
@@ -58,7 +69,7 @@ export default (protectedHeader, encodedPayload, options = {}) => {
|
|
|
58
69
|
}
|
|
59
70
|
const { currentDate } = options;
|
|
60
71
|
const now = epoch(currentDate || new Date());
|
|
61
|
-
if ((payload.iat !== undefined ||
|
|
72
|
+
if ((payload.iat !== undefined || maxTokenAge) && typeof payload.iat !== 'number') {
|
|
62
73
|
throw new JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid');
|
|
63
74
|
}
|
|
64
75
|
if (payload.nbf !== undefined) {
|
|
@@ -77,9 +88,9 @@ export default (protectedHeader, encodedPayload, options = {}) => {
|
|
|
77
88
|
throw new JWTExpired('"exp" claim timestamp check failed', 'exp', 'check_failed');
|
|
78
89
|
}
|
|
79
90
|
}
|
|
80
|
-
if (
|
|
91
|
+
if (maxTokenAge) {
|
|
81
92
|
const age = now - payload.iat;
|
|
82
|
-
const max = typeof
|
|
93
|
+
const max = typeof maxTokenAge === 'number' ? maxTokenAge : secs(maxTokenAge);
|
|
83
94
|
if (age - tolerance > max) {
|
|
84
95
|
throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', 'iat', 'check_failed');
|
|
85
96
|
}
|
package/dist/types/types.d.ts
CHANGED
|
@@ -294,7 +294,13 @@ export interface JWEHeaderParameters extends JoseHeaderParameters {
|
|
|
294
294
|
/** JWE "crit" (Critical) Header Parameter. */
|
|
295
295
|
crit?: string[]
|
|
296
296
|
|
|
297
|
-
/**
|
|
297
|
+
/**
|
|
298
|
+
* JWE "zip" (Compression Algorithm) Header Parameter.
|
|
299
|
+
*
|
|
300
|
+
* @deprecated Compression of data SHOULD NOT be done before encryption, because such compressed
|
|
301
|
+
* data often reveals information about the plaintext.
|
|
302
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc8725#name-avoid-compression-of-encryp Avoid Compression of Encryption Inputs}
|
|
303
|
+
*/
|
|
298
304
|
zip?: string
|
|
299
305
|
|
|
300
306
|
/** Any other JWE Header member. */
|
|
@@ -395,6 +401,16 @@ export interface JWTClaimVerificationOptions {
|
|
|
395
401
|
|
|
396
402
|
/** Date to use when comparing NumericDate claims, defaults to `new Date()`. */
|
|
397
403
|
currentDate?: Date
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Array of required Claim Names that must be present in the JWT Claims Set. Default is that: if
|
|
407
|
+
* the {@link JWTClaimVerificationOptions.issuer issuer option} is set, then "iss" must be present;
|
|
408
|
+
* if the {@link JWTClaimVerificationOptions.audience audience option} is set, then "aud" must be
|
|
409
|
+
* present; if the {@link JWTClaimVerificationOptions.subject subject option} is set, then "sub"
|
|
410
|
+
* must be present; if the {@link JWTClaimVerificationOptions.maxTokenAge maxTokenAge option} is
|
|
411
|
+
* set, then "iat" must be present.
|
|
412
|
+
*/
|
|
413
|
+
requiredClaims?: string[]
|
|
398
414
|
}
|
|
399
415
|
|
|
400
416
|
/** JWS Verification options. */
|
|
@@ -468,6 +484,10 @@ export interface JWTPayload {
|
|
|
468
484
|
/**
|
|
469
485
|
* Deflate Raw implementation, e.g. promisified
|
|
470
486
|
* {@link https://nodejs.org/api/zlib.html#zlibdeflaterawbuffer-options-callback zlib.deflateRaw}.
|
|
487
|
+
*
|
|
488
|
+
* @deprecated Compression of data SHOULD NOT be done before encryption, because such compressed
|
|
489
|
+
* data often reveals information about the plaintext.
|
|
490
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc8725#name-avoid-compression-of-encryp Avoid Compression of Encryption Inputs}
|
|
471
491
|
*/
|
|
472
492
|
export interface DeflateFunction {
|
|
473
493
|
(input: Uint8Array): Promise<Uint8Array>
|
|
@@ -476,6 +496,10 @@ export interface DeflateFunction {
|
|
|
476
496
|
/**
|
|
477
497
|
* Inflate Raw implementation, e.g. promisified
|
|
478
498
|
* {@link https://nodejs.org/api/zlib.html#zlibinflaterawbuffer-options-callback zlib.inflateRaw}.
|
|
499
|
+
*
|
|
500
|
+
* @deprecated Compression of data SHOULD NOT be done before encryption, because such compressed
|
|
501
|
+
* data often reveals information about the plaintext.
|
|
502
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc8725#name-avoid-compression-of-encryp Avoid Compression of Encryption Inputs}
|
|
479
503
|
*/
|
|
480
504
|
export interface InflateFunction {
|
|
481
505
|
(input: Uint8Array): Promise<Uint8Array>
|
package/package.json
CHANGED