diff --git a/index.js b/index.js index 3b7c973..32b8f1f 100644 --- a/index.js +++ b/index.js @@ -383,6 +383,10 @@ function fastifyJwt (fastify, options, next) { }) } + // Capture any per-request `key` before merging, so it can take precedence + // over the resolved secret (as documented for the `sign.key` option). + const requestSignKey = options.sign ? options.sign.key : options.key + if (options.sign) { const localSignOptions = convertTemporalProps(options.sign) // New supported contract, options supports sign and can expand @@ -409,7 +413,11 @@ function fastifyJwt (fastify, options, next) { }, function sign (secretOrPrivateKey, callback) { if (useLocalSigner) { - const signerOptions = mergeOptionsWithKey(options.sign || options, secretOrPrivateKey) + const localSignOptions = options.sign || options + // A per-request `key` overrides the resolved secret; otherwise the resolved secret is used. + const signerOptions = requestSignKey + ? localSignOptions + : mergeOptionsWithKey(localSignOptions, secretOrPrivateKey) const localSigner = createSigner(signerOptions) const token = localSigner(payload) callback(null, token) @@ -477,6 +485,10 @@ function fastifyJwt (fastify, options, next) { options = {} } + // Capture any per-request `key` before merging, so it can take precedence + // over the resolved secret (as documented for the `verify.key` option). + const requestVerifyKey = options.verify ? options.verify.key : options.key + if (options.decode || options.verify) { const localVerifyOptions = convertTemporalProps(options.verify, true) // New supported contract, options supports both decode and verify @@ -508,7 +520,11 @@ function fastifyJwt (fastify, options, next) { }, function verify (secretOrPublicKey, callback) { try { - const verifierOptions = mergeOptionsWithKey(options.verify || options, secretOrPublicKey) + const localVerifyOptions = options.verify || options + // A per-request `key` overrides the resolved secret; otherwise the resolved secret is used. + const verifierOptions = requestVerifyKey + ? localVerifyOptions + : mergeOptionsWithKey(localVerifyOptions, secretOrPublicKey) const localVerifier = getVerifier(verifierOptions, useGlobalOptions) const verifyResult = localVerifier(token) if (verifyResult && typeof verifyResult.then === 'function') { diff --git a/test/jwt.test.js b/test/jwt.test.js index c9a6823..1f6842b 100644 --- a/test/jwt.test.js +++ b/test/jwt.test.js @@ -3036,3 +3036,28 @@ test('local sign options should not overwrite global sign options', async functi t.assert.strictEqual(fastify.jwt.options.sign.expiresIn, '15m') }) + +test('request.jwtVerify should honor a per-request verify.key override', async function (t) { + t.plan(2) + + const fastify = Fastify() + fastify.register(jwt, { secret: 'hunter2' }) + + fastify.get('/verify', async function (request) { + return request.jwtVerify({ verify: { key: 'override' } }) + }) + + await fastify.ready() + + // Token signed with the override key, not the registration secret. + const token = createSigner({ key: 'override' })({ foo: 'bar' }) + + const response = await fastify.inject({ + method: 'get', + url: '/verify', + headers: { authorization: `Bearer ${token}` } + }) + + t.assert.strictEqual(response.statusCode, 200) + t.assert.strictEqual(JSON.parse(response.payload).foo, 'bar') +})