Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Ensure required claims applies to custom claims #423

Merged
merged 1 commit into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions src/verifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,18 +210,23 @@ function verifyToken(
// Verify the payload
const now = clockTimestamp || Date.now()

if (requiredClaims) {
for (const claim of requiredClaims) {
if (!(claim in payload)) {
throw new TokenError(TokenError.codes.missingRequiredClaim, `The ${claim} claim is required.`)
}
}
}

for (const validator of validators) {
const { type, claim, allowed, array, modifier, greater, errorCode, errorVerb } = validator
const value = payload[claim]
const arrayValue = Array.isArray(value)
const values = arrayValue ? value : [value]

// Check if the claim is marked as required before skipping it
// We have already checked above that all required claims are present
// Therefore we can skip this validator if the claim is not present
if (!(claim in payload)) {
if (requiredClaims && requiredClaims.includes(claim)) {
throw new TokenError(TokenError.codes.missingRequiredClaim, `The ${claim} claim is required.`)
}

continue
}

Expand Down
43 changes: 35 additions & 8 deletions test/verifier.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,11 @@ function verify(token, options, callback) {
test('it gets the correct decoded jwt token as argument on the key callback', async t => {
verify('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoxfQ.57TF7smP9XDhIexBqPC-F1toZReYZLWb_YRU5tv0sxM', {
key: async decoded => {
t.strictSame(
decoded,
{
header: { typ: 'JWT', alg: 'HS256' },
payload: { a: 1 },
signature: '57TF7smP9XDhIexBqPC-F1toZReYZLWb_YRU5tv0sxM'
}
)
t.strictSame(decoded, {
header: { typ: 'JWT', alg: 'HS256' },
payload: { a: 1 },
signature: '57TF7smP9XDhIexBqPC-F1toZReYZLWb_YRU5tv0sxM'
})

return Buffer.from('secret', 'utf-8')
},
Expand Down Expand Up @@ -957,6 +954,36 @@ test('it validates whether a required claim is present in the payload or not', t
t.end()
})

test('it validates whether a required custom claim is present in the payload or not', t => {
// Token payload: {"iss": "ISS", "custom": "custom", "iat": 1708023956}
const token =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJJU1MiLCJjdXN0b20iOiJjdXN0b20iLCJpYXQiOjE3MDgwMjQxMTh9.rD9GaHxuSB7mPkVQ2shj4yqPsvEuXWByMDNhMoch0xY'

t.strictSame(verify(token, { requiredClaims: ['iss', 'custom'] }), {
iss: 'ISS',
custom: 'custom',
iat: 1708024118
})

// Standard claim not covered by other validators
t.throws(
() => {
return verify(token, { requiredClaims: ['kid'] })
},
{ message: 'The kid claim is required.' }
)

// Custom claim
t.throws(
() => {
return verify(token, { requiredClaims: ['customTwo'] })
},
{ message: 'The customTwo claim is required.' }
)

t.end()
})

test("it skips validation when an allowed claim isn't present in the payload", t => {
// Token payload: { "iss": "ISS"}
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJJU1MifQ.FKjJd2A-T8ufN7Y0LpjMR23P7CwEQ3Y-LBIYd2Vh_Rs'
Expand Down
Loading