From 1bf9cec024a4d01d989e15bb6e4b54e3940b4458 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Mon, 27 Nov 2023 22:20:46 +0100 Subject: [PATCH] fix: do not mutate JWTVerifyOptions.requiredClaims fixes #610 --- src/lib/jwt_claims_set.ts | 12 +++++++----- test/jwt/verify.test.mjs | 17 +++++++++-------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/lib/jwt_claims_set.ts b/src/lib/jwt_claims_set.ts index 205d37b6d4..ebc7a821e5 100644 --- a/src/lib/jwt_claims_set.ts +++ b/src/lib/jwt_claims_set.ts @@ -53,12 +53,14 @@ export default ( const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options - if (maxTokenAge !== undefined) requiredClaims.push('iat') - if (audience !== undefined) requiredClaims.push('aud') - if (subject !== undefined) requiredClaims.push('sub') - if (issuer !== undefined) requiredClaims.push('iss') + const presenceCheck = [...requiredClaims] - for (const claim of new Set(requiredClaims.reverse())) { + if (maxTokenAge !== undefined) presenceCheck.push('iat') + if (audience !== undefined) presenceCheck.push('aud') + if (subject !== undefined) presenceCheck.push('sub') + if (issuer !== undefined) presenceCheck.push('iss') + + for (const claim of new Set(presenceCheck.reverse())) { if (!(claim in payload)) { throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, claim, 'missing') } diff --git a/test/jwt/verify.test.mjs b/test/jwt/verify.test.mjs index e65ca3290e..82e11df519 100644 --- a/test/jwt/verify.test.mjs +++ b/test/jwt/verify.test.mjs @@ -418,6 +418,8 @@ test('requiredClaims claims check', async (t) => { .setProtectedHeader({ alg: 'HS256' }) .sign(t.context.secret) + const requiredClaims = ['nbf'] + for (const [claim, option] of [ ['iss', 'issuer'], ['aud', 'audience'], @@ -428,16 +430,15 @@ test('requiredClaims claims check', async (t) => { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: `missing required "${claim}" claim`, }) - await t.throwsAsync( - jwtVerify(jwt, t.context.secret, { [option]: 'foo', requiredClaims: ['nbf'] }), - { - code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', - message: `missing required "${claim}" claim`, - }, - ) + await t.throwsAsync(jwtVerify(jwt, t.context.secret, { [option]: 'foo', requiredClaims }), { + code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', + message: `missing required "${claim}" claim`, + }) } - await t.throwsAsync(jwtVerify(jwt, t.context.secret, { requiredClaims: ['nbf'] }), { + await t.throwsAsync(jwtVerify(jwt, t.context.secret, { requiredClaims }), { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: `missing required "nbf" claim`, }) + + t.deepEqual(requiredClaims, ['nbf']) })