jose 5.3.0 → 5.4.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.
@@ -9,7 +9,7 @@ function isCloudflareWorkers() {
9
9
  let USER_AGENT;
10
10
  if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
11
11
  const NAME = 'jose';
12
- const VERSION = 'v5.3.0';
12
+ const VERSION = 'v5.4.1';
13
13
  USER_AGENT = `${NAME}/${VERSION}`;
14
14
  }
15
15
  class RemoteJWKSet {
@@ -6,14 +6,14 @@ export async function jwtDecrypt(jwt, key, options) {
6
6
  const payload = jwtPayload(decrypted.protectedHeader, decrypted.plaintext, options);
7
7
  const { protectedHeader } = decrypted;
8
8
  if (protectedHeader.iss !== undefined && protectedHeader.iss !== payload.iss) {
9
- throw new JWTClaimValidationFailed('replicated "iss" claim header parameter mismatch', 'iss', 'mismatch');
9
+ throw new JWTClaimValidationFailed('replicated "iss" claim header parameter mismatch', payload, 'iss', 'mismatch');
10
10
  }
11
11
  if (protectedHeader.sub !== undefined && protectedHeader.sub !== payload.sub) {
12
- throw new JWTClaimValidationFailed('replicated "sub" claim header parameter mismatch', 'sub', 'mismatch');
12
+ throw new JWTClaimValidationFailed('replicated "sub" claim header parameter mismatch', payload, 'sub', 'mismatch');
13
13
  }
14
14
  if (protectedHeader.aud !== undefined &&
15
15
  JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud)) {
16
- throw new JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', 'aud', 'mismatch');
16
+ throw new JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', payload, 'aud', 'mismatch');
17
17
  }
18
18
  const result = { payload, protectedHeader };
19
19
  if (typeof key === 'function') {
@@ -14,12 +14,6 @@ const checkAudiencePresence = (audPayload, audOption) => {
14
14
  return false;
15
15
  };
16
16
  export default (protectedHeader, encodedPayload, options = {}) => {
17
- const { typ } = options;
18
- if (typ &&
19
- (typeof protectedHeader.typ !== 'string' ||
20
- normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
21
- throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', 'typ', 'check_failed');
22
- }
23
17
  let payload;
24
18
  try {
25
19
  payload = JSON.parse(decoder.decode(encodedPayload));
@@ -29,6 +23,12 @@ export default (protectedHeader, encodedPayload, options = {}) => {
29
23
  if (!isObject(payload)) {
30
24
  throw new JWTInvalid('JWT Claims Set must be a top-level JSON object');
31
25
  }
26
+ const { typ } = options;
27
+ if (typ &&
28
+ (typeof protectedHeader.typ !== 'string' ||
29
+ normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
30
+ throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, 'typ', 'check_failed');
31
+ }
32
32
  const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
33
33
  const presenceCheck = [...requiredClaims];
34
34
  if (maxTokenAge !== undefined)
@@ -41,18 +41,18 @@ export default (protectedHeader, encodedPayload, options = {}) => {
41
41
  presenceCheck.push('iss');
42
42
  for (const claim of new Set(presenceCheck.reverse())) {
43
43
  if (!(claim in payload)) {
44
- throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, claim, 'missing');
44
+ throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, 'missing');
45
45
  }
46
46
  }
47
47
  if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
48
- throw new JWTClaimValidationFailed('unexpected "iss" claim value', 'iss', 'check_failed');
48
+ throw new JWTClaimValidationFailed('unexpected "iss" claim value', payload, 'iss', 'check_failed');
49
49
  }
50
50
  if (subject && payload.sub !== subject) {
51
- throw new JWTClaimValidationFailed('unexpected "sub" claim value', 'sub', 'check_failed');
51
+ throw new JWTClaimValidationFailed('unexpected "sub" claim value', payload, 'sub', 'check_failed');
52
52
  }
53
53
  if (audience &&
54
54
  !checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience)) {
55
- throw new JWTClaimValidationFailed('unexpected "aud" claim value', 'aud', 'check_failed');
55
+ throw new JWTClaimValidationFailed('unexpected "aud" claim value', payload, 'aud', 'check_failed');
56
56
  }
57
57
  let tolerance;
58
58
  switch (typeof options.clockTolerance) {
@@ -71,32 +71,32 @@ export default (protectedHeader, encodedPayload, options = {}) => {
71
71
  const { currentDate } = options;
72
72
  const now = epoch(currentDate || new Date());
73
73
  if ((payload.iat !== undefined || maxTokenAge) && typeof payload.iat !== 'number') {
74
- throw new JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid');
74
+ throw new JWTClaimValidationFailed('"iat" claim must be a number', payload, 'iat', 'invalid');
75
75
  }
76
76
  if (payload.nbf !== undefined) {
77
77
  if (typeof payload.nbf !== 'number') {
78
- throw new JWTClaimValidationFailed('"nbf" claim must be a number', 'nbf', 'invalid');
78
+ throw new JWTClaimValidationFailed('"nbf" claim must be a number', payload, 'nbf', 'invalid');
79
79
  }
80
80
  if (payload.nbf > now + tolerance) {
81
- throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', 'nbf', 'check_failed');
81
+ throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, 'nbf', 'check_failed');
82
82
  }
83
83
  }
84
84
  if (payload.exp !== undefined) {
85
85
  if (typeof payload.exp !== 'number') {
86
- throw new JWTClaimValidationFailed('"exp" claim must be a number', 'exp', 'invalid');
86
+ throw new JWTClaimValidationFailed('"exp" claim must be a number', payload, 'exp', 'invalid');
87
87
  }
88
88
  if (payload.exp <= now - tolerance) {
89
- throw new JWTExpired('"exp" claim timestamp check failed', 'exp', 'check_failed');
89
+ throw new JWTExpired('"exp" claim timestamp check failed', payload, 'exp', 'check_failed');
90
90
  }
91
91
  }
92
92
  if (maxTokenAge) {
93
93
  const age = now - payload.iat;
94
94
  const max = typeof maxTokenAge === 'number' ? maxTokenAge : secs(maxTokenAge);
95
95
  if (age - tolerance > max) {
96
- throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', 'iat', 'check_failed');
96
+ throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, 'iat', 'check_failed');
97
97
  }
98
98
  if (age < 0 - tolerance) {
99
- throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed');
99
+ throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, 'iat', 'check_failed');
100
100
  }
101
101
  }
102
102
  return payload;
@@ -13,22 +13,24 @@ export class JWTClaimValidationFailed extends JOSEError {
13
13
  static get code() {
14
14
  return 'ERR_JWT_CLAIM_VALIDATION_FAILED';
15
15
  }
16
- constructor(message, claim = 'unspecified', reason = 'unspecified') {
16
+ constructor(message, payload, claim = 'unspecified', reason = 'unspecified') {
17
17
  super(message);
18
18
  this.code = 'ERR_JWT_CLAIM_VALIDATION_FAILED';
19
19
  this.claim = claim;
20
20
  this.reason = reason;
21
+ this.payload = payload;
21
22
  }
22
23
  }
23
24
  export class JWTExpired extends JOSEError {
24
25
  static get code() {
25
26
  return 'ERR_JWT_EXPIRED';
26
27
  }
27
- constructor(message, claim = 'unspecified', reason = 'unspecified') {
28
+ constructor(message, payload, claim = 'unspecified', reason = 'unspecified') {
28
29
  super(message);
29
30
  this.code = 'ERR_JWT_EXPIRED';
30
31
  this.claim = claim;
31
32
  this.reason = reason;
33
+ this.payload = payload;
32
34
  }
33
35
  }
34
36
  export class JOSEAlgNotAllowed extends JOSEError {
@@ -12,7 +12,7 @@ function isCloudflareWorkers() {
12
12
  let USER_AGENT;
13
13
  if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
14
14
  const NAME = 'jose';
15
- const VERSION = 'v5.3.0';
15
+ const VERSION = 'v5.4.1';
16
16
  USER_AGENT = `${NAME}/${VERSION}`;
17
17
  }
18
18
  class RemoteJWKSet {
@@ -9,14 +9,14 @@ async function jwtDecrypt(jwt, key, options) {
9
9
  const payload = (0, jwt_claims_set_js_1.default)(decrypted.protectedHeader, decrypted.plaintext, options);
10
10
  const { protectedHeader } = decrypted;
11
11
  if (protectedHeader.iss !== undefined && protectedHeader.iss !== payload.iss) {
12
- throw new errors_js_1.JWTClaimValidationFailed('replicated "iss" claim header parameter mismatch', 'iss', 'mismatch');
12
+ throw new errors_js_1.JWTClaimValidationFailed('replicated "iss" claim header parameter mismatch', payload, 'iss', 'mismatch');
13
13
  }
14
14
  if (protectedHeader.sub !== undefined && protectedHeader.sub !== payload.sub) {
15
- throw new errors_js_1.JWTClaimValidationFailed('replicated "sub" claim header parameter mismatch', 'sub', 'mismatch');
15
+ throw new errors_js_1.JWTClaimValidationFailed('replicated "sub" claim header parameter mismatch', payload, 'sub', 'mismatch');
16
16
  }
17
17
  if (protectedHeader.aud !== undefined &&
18
18
  JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud)) {
19
- throw new errors_js_1.JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', 'aud', 'mismatch');
19
+ throw new errors_js_1.JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', payload, 'aud', 'mismatch');
20
20
  }
21
21
  const result = { payload, protectedHeader };
22
22
  if (typeof key === 'function') {
@@ -16,12 +16,6 @@ const checkAudiencePresence = (audPayload, audOption) => {
16
16
  return false;
17
17
  };
18
18
  exports.default = (protectedHeader, encodedPayload, options = {}) => {
19
- const { typ } = options;
20
- if (typ &&
21
- (typeof protectedHeader.typ !== 'string' ||
22
- normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
23
- throw new errors_js_1.JWTClaimValidationFailed('unexpected "typ" JWT header value', 'typ', 'check_failed');
24
- }
25
19
  let payload;
26
20
  try {
27
21
  payload = JSON.parse(buffer_utils_js_1.decoder.decode(encodedPayload));
@@ -31,6 +25,12 @@ exports.default = (protectedHeader, encodedPayload, options = {}) => {
31
25
  if (!(0, is_object_js_1.default)(payload)) {
32
26
  throw new errors_js_1.JWTInvalid('JWT Claims Set must be a top-level JSON object');
33
27
  }
28
+ const { typ } = options;
29
+ if (typ &&
30
+ (typeof protectedHeader.typ !== 'string' ||
31
+ normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
32
+ throw new errors_js_1.JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, 'typ', 'check_failed');
33
+ }
34
34
  const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
35
35
  const presenceCheck = [...requiredClaims];
36
36
  if (maxTokenAge !== undefined)
@@ -43,18 +43,18 @@ exports.default = (protectedHeader, encodedPayload, options = {}) => {
43
43
  presenceCheck.push('iss');
44
44
  for (const claim of new Set(presenceCheck.reverse())) {
45
45
  if (!(claim in payload)) {
46
- throw new errors_js_1.JWTClaimValidationFailed(`missing required "${claim}" claim`, claim, 'missing');
46
+ throw new errors_js_1.JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, 'missing');
47
47
  }
48
48
  }
49
49
  if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
50
- throw new errors_js_1.JWTClaimValidationFailed('unexpected "iss" claim value', 'iss', 'check_failed');
50
+ throw new errors_js_1.JWTClaimValidationFailed('unexpected "iss" claim value', payload, 'iss', 'check_failed');
51
51
  }
52
52
  if (subject && payload.sub !== subject) {
53
- throw new errors_js_1.JWTClaimValidationFailed('unexpected "sub" claim value', 'sub', 'check_failed');
53
+ throw new errors_js_1.JWTClaimValidationFailed('unexpected "sub" claim value', payload, 'sub', 'check_failed');
54
54
  }
55
55
  if (audience &&
56
56
  !checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience)) {
57
- throw new errors_js_1.JWTClaimValidationFailed('unexpected "aud" claim value', 'aud', 'check_failed');
57
+ throw new errors_js_1.JWTClaimValidationFailed('unexpected "aud" claim value', payload, 'aud', 'check_failed');
58
58
  }
59
59
  let tolerance;
60
60
  switch (typeof options.clockTolerance) {
@@ -73,32 +73,32 @@ exports.default = (protectedHeader, encodedPayload, options = {}) => {
73
73
  const { currentDate } = options;
74
74
  const now = (0, epoch_js_1.default)(currentDate || new Date());
75
75
  if ((payload.iat !== undefined || maxTokenAge) && typeof payload.iat !== 'number') {
76
- throw new errors_js_1.JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid');
76
+ throw new errors_js_1.JWTClaimValidationFailed('"iat" claim must be a number', payload, 'iat', 'invalid');
77
77
  }
78
78
  if (payload.nbf !== undefined) {
79
79
  if (typeof payload.nbf !== 'number') {
80
- throw new errors_js_1.JWTClaimValidationFailed('"nbf" claim must be a number', 'nbf', 'invalid');
80
+ throw new errors_js_1.JWTClaimValidationFailed('"nbf" claim must be a number', payload, 'nbf', 'invalid');
81
81
  }
82
82
  if (payload.nbf > now + tolerance) {
83
- throw new errors_js_1.JWTClaimValidationFailed('"nbf" claim timestamp check failed', 'nbf', 'check_failed');
83
+ throw new errors_js_1.JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, 'nbf', 'check_failed');
84
84
  }
85
85
  }
86
86
  if (payload.exp !== undefined) {
87
87
  if (typeof payload.exp !== 'number') {
88
- throw new errors_js_1.JWTClaimValidationFailed('"exp" claim must be a number', 'exp', 'invalid');
88
+ throw new errors_js_1.JWTClaimValidationFailed('"exp" claim must be a number', payload, 'exp', 'invalid');
89
89
  }
90
90
  if (payload.exp <= now - tolerance) {
91
- throw new errors_js_1.JWTExpired('"exp" claim timestamp check failed', 'exp', 'check_failed');
91
+ throw new errors_js_1.JWTExpired('"exp" claim timestamp check failed', payload, 'exp', 'check_failed');
92
92
  }
93
93
  }
94
94
  if (maxTokenAge) {
95
95
  const age = now - payload.iat;
96
96
  const max = typeof maxTokenAge === 'number' ? maxTokenAge : (0, secs_js_1.default)(maxTokenAge);
97
97
  if (age - tolerance > max) {
98
- throw new errors_js_1.JWTExpired('"iat" claim timestamp check failed (too far in the past)', 'iat', 'check_failed');
98
+ throw new errors_js_1.JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, 'iat', 'check_failed');
99
99
  }
100
100
  if (age < 0 - tolerance) {
101
- throw new errors_js_1.JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed');
101
+ throw new errors_js_1.JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, 'iat', 'check_failed');
102
102
  }
103
103
  }
104
104
  return payload;
@@ -20,10 +20,12 @@ class JWTClaimValidationFailed extends JOSEError {
20
20
  code = 'ERR_JWT_CLAIM_VALIDATION_FAILED';
21
21
  claim;
22
22
  reason;
23
- constructor(message, claim = 'unspecified', reason = 'unspecified') {
23
+ payload;
24
+ constructor(message, payload, claim = 'unspecified', reason = 'unspecified') {
24
25
  super(message);
25
26
  this.claim = claim;
26
27
  this.reason = reason;
28
+ this.payload = payload;
27
29
  }
28
30
  }
29
31
  exports.JWTClaimValidationFailed = JWTClaimValidationFailed;
@@ -34,10 +36,12 @@ class JWTExpired extends JOSEError {
34
36
  code = 'ERR_JWT_EXPIRED';
35
37
  claim;
36
38
  reason;
37
- constructor(message, claim = 'unspecified', reason = 'unspecified') {
39
+ payload;
40
+ constructor(message, payload, claim = 'unspecified', reason = 'unspecified') {
38
41
  super(message);
39
42
  this.claim = claim;
40
43
  this.reason = reason;
44
+ this.payload = payload;
41
45
  }
42
46
  }
43
47
  exports.JWTExpired = JWTExpired;
@@ -9,7 +9,7 @@ function isCloudflareWorkers() {
9
9
  let USER_AGENT;
10
10
  if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
11
11
  const NAME = 'jose';
12
- const VERSION = 'v5.3.0';
12
+ const VERSION = 'v5.4.1';
13
13
  USER_AGENT = `${NAME}/${VERSION}`;
14
14
  }
15
15
  class RemoteJWKSet {
@@ -6,14 +6,14 @@ export async function jwtDecrypt(jwt, key, options) {
6
6
  const payload = jwtPayload(decrypted.protectedHeader, decrypted.plaintext, options);
7
7
  const { protectedHeader } = decrypted;
8
8
  if (protectedHeader.iss !== undefined && protectedHeader.iss !== payload.iss) {
9
- throw new JWTClaimValidationFailed('replicated "iss" claim header parameter mismatch', 'iss', 'mismatch');
9
+ throw new JWTClaimValidationFailed('replicated "iss" claim header parameter mismatch', payload, 'iss', 'mismatch');
10
10
  }
11
11
  if (protectedHeader.sub !== undefined && protectedHeader.sub !== payload.sub) {
12
- throw new JWTClaimValidationFailed('replicated "sub" claim header parameter mismatch', 'sub', 'mismatch');
12
+ throw new JWTClaimValidationFailed('replicated "sub" claim header parameter mismatch', payload, 'sub', 'mismatch');
13
13
  }
14
14
  if (protectedHeader.aud !== undefined &&
15
15
  JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud)) {
16
- throw new JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', 'aud', 'mismatch');
16
+ throw new JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', payload, 'aud', 'mismatch');
17
17
  }
18
18
  const result = { payload, protectedHeader };
19
19
  if (typeof key === 'function') {
@@ -14,12 +14,6 @@ const checkAudiencePresence = (audPayload, audOption) => {
14
14
  return false;
15
15
  };
16
16
  export default (protectedHeader, encodedPayload, options = {}) => {
17
- const { typ } = options;
18
- if (typ &&
19
- (typeof protectedHeader.typ !== 'string' ||
20
- normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
21
- throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', 'typ', 'check_failed');
22
- }
23
17
  let payload;
24
18
  try {
25
19
  payload = JSON.parse(decoder.decode(encodedPayload));
@@ -29,6 +23,12 @@ export default (protectedHeader, encodedPayload, options = {}) => {
29
23
  if (!isObject(payload)) {
30
24
  throw new JWTInvalid('JWT Claims Set must be a top-level JSON object');
31
25
  }
26
+ const { typ } = options;
27
+ if (typ &&
28
+ (typeof protectedHeader.typ !== 'string' ||
29
+ normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
30
+ throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, 'typ', 'check_failed');
31
+ }
32
32
  const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
33
33
  const presenceCheck = [...requiredClaims];
34
34
  if (maxTokenAge !== undefined)
@@ -41,18 +41,18 @@ export default (protectedHeader, encodedPayload, options = {}) => {
41
41
  presenceCheck.push('iss');
42
42
  for (const claim of new Set(presenceCheck.reverse())) {
43
43
  if (!(claim in payload)) {
44
- throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, claim, 'missing');
44
+ throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, 'missing');
45
45
  }
46
46
  }
47
47
  if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
48
- throw new JWTClaimValidationFailed('unexpected "iss" claim value', 'iss', 'check_failed');
48
+ throw new JWTClaimValidationFailed('unexpected "iss" claim value', payload, 'iss', 'check_failed');
49
49
  }
50
50
  if (subject && payload.sub !== subject) {
51
- throw new JWTClaimValidationFailed('unexpected "sub" claim value', 'sub', 'check_failed');
51
+ throw new JWTClaimValidationFailed('unexpected "sub" claim value', payload, 'sub', 'check_failed');
52
52
  }
53
53
  if (audience &&
54
54
  !checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience)) {
55
- throw new JWTClaimValidationFailed('unexpected "aud" claim value', 'aud', 'check_failed');
55
+ throw new JWTClaimValidationFailed('unexpected "aud" claim value', payload, 'aud', 'check_failed');
56
56
  }
57
57
  let tolerance;
58
58
  switch (typeof options.clockTolerance) {
@@ -71,32 +71,32 @@ export default (protectedHeader, encodedPayload, options = {}) => {
71
71
  const { currentDate } = options;
72
72
  const now = epoch(currentDate || new Date());
73
73
  if ((payload.iat !== undefined || maxTokenAge) && typeof payload.iat !== 'number') {
74
- throw new JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid');
74
+ throw new JWTClaimValidationFailed('"iat" claim must be a number', payload, 'iat', 'invalid');
75
75
  }
76
76
  if (payload.nbf !== undefined) {
77
77
  if (typeof payload.nbf !== 'number') {
78
- throw new JWTClaimValidationFailed('"nbf" claim must be a number', 'nbf', 'invalid');
78
+ throw new JWTClaimValidationFailed('"nbf" claim must be a number', payload, 'nbf', 'invalid');
79
79
  }
80
80
  if (payload.nbf > now + tolerance) {
81
- throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', 'nbf', 'check_failed');
81
+ throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, 'nbf', 'check_failed');
82
82
  }
83
83
  }
84
84
  if (payload.exp !== undefined) {
85
85
  if (typeof payload.exp !== 'number') {
86
- throw new JWTClaimValidationFailed('"exp" claim must be a number', 'exp', 'invalid');
86
+ throw new JWTClaimValidationFailed('"exp" claim must be a number', payload, 'exp', 'invalid');
87
87
  }
88
88
  if (payload.exp <= now - tolerance) {
89
- throw new JWTExpired('"exp" claim timestamp check failed', 'exp', 'check_failed');
89
+ throw new JWTExpired('"exp" claim timestamp check failed', payload, 'exp', 'check_failed');
90
90
  }
91
91
  }
92
92
  if (maxTokenAge) {
93
93
  const age = now - payload.iat;
94
94
  const max = typeof maxTokenAge === 'number' ? maxTokenAge : secs(maxTokenAge);
95
95
  if (age - tolerance > max) {
96
- throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', 'iat', 'check_failed');
96
+ throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, 'iat', 'check_failed');
97
97
  }
98
98
  if (age < 0 - tolerance) {
99
- throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed');
99
+ throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, 'iat', 'check_failed');
100
100
  }
101
101
  }
102
102
  return payload;
@@ -16,10 +16,12 @@ export class JWTClaimValidationFailed extends JOSEError {
16
16
  code = 'ERR_JWT_CLAIM_VALIDATION_FAILED';
17
17
  claim;
18
18
  reason;
19
- constructor(message, claim = 'unspecified', reason = 'unspecified') {
19
+ payload;
20
+ constructor(message, payload, claim = 'unspecified', reason = 'unspecified') {
20
21
  super(message);
21
22
  this.claim = claim;
22
23
  this.reason = reason;
24
+ this.payload = payload;
23
25
  }
24
26
  }
25
27
  export class JWTExpired extends JOSEError {
@@ -29,10 +31,12 @@ export class JWTExpired extends JOSEError {
29
31
  code = 'ERR_JWT_EXPIRED';
30
32
  claim;
31
33
  reason;
32
- constructor(message, claim = 'unspecified', reason = 'unspecified') {
34
+ payload;
35
+ constructor(message, payload, claim = 'unspecified', reason = 'unspecified') {
33
36
  super(message);
34
37
  this.claim = claim;
35
38
  this.reason = reason;
39
+ this.payload = payload;
36
40
  }
37
41
  }
38
42
  export class JOSEAlgNotAllowed extends JOSEError {
@@ -1,4 +1,4 @@
1
- import type { KeyLike } from '../types';
1
+ import type { JWTPayload, KeyLike } from '../types';
2
2
  /**
3
3
  * A generic Error that all other JOSE specific Error subclasses extend.
4
4
  *
@@ -27,8 +27,15 @@ export declare class JWTClaimValidationFailed extends JOSEError {
27
27
  claim: string;
28
28
  /** Reason code for the validation failure. */
29
29
  reason: string;
30
+ /**
31
+ * The parsed JWT Claims Set (aka payload). Other JWT claims may or may not have been verified at
32
+ * this point. The JSON Web Signature (JWS) or a JSON Web Encryption (JWE) structures' integrity
33
+ * has however been verified. Claims Set verification happens after the JWS Signature or JWE
34
+ * Decryption processes.
35
+ */
36
+ payload: JWTPayload;
30
37
  /** @ignore */
31
- constructor(message: string, claim?: string, reason?: string);
38
+ constructor(message: string, payload: JWTPayload, claim?: string, reason?: string);
32
39
  }
33
40
  /**
34
41
  * An error subclass thrown when a JWT is expired.
@@ -42,8 +49,15 @@ export declare class JWTExpired extends JOSEError implements JWTClaimValidationF
42
49
  claim: string;
43
50
  /** Reason code for the validation failure. */
44
51
  reason: string;
52
+ /**
53
+ * The parsed JWT Claims Set (aka payload). Other JWT claims may or may not have been verified at
54
+ * this point. The JSON Web Signature (JWS) or a JSON Web Encryption (JWE) structures' integrity
55
+ * has however been verified. Claims Set verification happens after the JWS Signature or JWE
56
+ * Decryption processes.
57
+ */
58
+ payload: JWTPayload;
45
59
  /** @ignore */
46
- constructor(message: string, claim?: string, reason?: string);
60
+ constructor(message: string, payload: JWTPayload, claim?: string, reason?: string);
47
61
  }
48
62
  /**
49
63
  * An error subclass thrown when a JOSE Algorithm is not allowed per developer preference.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jose",
3
- "version": "5.3.0",
3
+ "version": "5.4.1",
4
4
  "description": "JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes",
5
5
  "keywords": [
6
6
  "browser",