Skip to content
Open
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 index.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,13 @@ function fastifyJwt (fastify, options, next) {
secretOrPrivateKey = secretOrPublicKey = secret
}

let hasStaticPrivateKey = false
let hasStaticPublicKey = false
let secretCallbackSign = secretOrPrivateKey
let secretCallbackVerify = secretOrPublicKey
if (typeof secretCallbackSign !== 'function') {
secretCallbackSign = wrapStaticSecretInCallback(secretCallbackSign)
hasStaticPrivateKey = true
}
if (typeof secretCallbackVerify !== 'function') {
secretCallbackVerify = wrapStaticSecretInCallback(secretCallbackVerify)
Expand Down Expand Up @@ -289,9 +291,11 @@ function fastifyJwt (fastify, options, next) {
return token
}

function mergeOptionsWithKey (options, useProvidedPrivateKey) {
function mergeOptionsWithKey (options, useProvidedPrivateKey, preferOptionsKey) {
if (useProvidedPrivateKey && (typeof useProvidedPrivateKey !== 'boolean')) {
return Object.assign({}, options, { key: options.key ?? useProvidedPrivateKey })
return preferOptionsKey && options.key
? Object.assign({ key: useProvidedPrivateKey }, options)
: Object.assign({}, options, { key: useProvidedPrivateKey })
} else {
const key = useProvidedPrivateKey ? secretOrPrivateKey : secretOrPublicKey
return Object.assign(!options.key ? { key } : {}, options)
Expand Down Expand Up @@ -409,7 +413,8 @@ function fastifyJwt (fastify, options, next) {
},
function sign (secretOrPrivateKey, callback) {
if (useLocalSigner) {
const signerOptions = mergeOptionsWithKey(options.sign || options, secretOrPrivateKey)
const localSignOptions = options.sign || options
const signerOptions = mergeOptionsWithKey(localSignOptions, secretOrPrivateKey, hasStaticPrivateKey)
const localSigner = createSigner(signerOptions)
const token = localSigner(payload)
callback(null, token)
Expand Down Expand Up @@ -467,7 +472,6 @@ function fastifyJwt (fastify, options, next) {
}

const useGlobalOptions = !options

if (typeof options === 'function') {
next = options
options = {}
Expand Down Expand Up @@ -508,7 +512,8 @@ function fastifyJwt (fastify, options, next) {
},
function verify (secretOrPublicKey, callback) {
try {
const verifierOptions = mergeOptionsWithKey(options.verify || options, secretOrPublicKey)
const localVerifyOptions = options.verify || options
const verifierOptions = mergeOptionsWithKey(localVerifyOptions, secretOrPublicKey, hasStaticPublicKey)
const localVerifier = getVerifier(verifierOptions, useGlobalOptions)
const verifyResult = localVerifier(token)
if (verifyResult && typeof verifyResult.then === 'function') {
Expand Down
51 changes: 50 additions & 1 deletion test/jwt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const { test } = require('node:test')
const Fastify = require('fastify')
const { createSigner } = require('fast-jwt')
const { createSigner, createVerifier } = require('fast-jwt')
const jwt = require('..')
const defaultExport = require('..').default
const { fastifyJwt: namedExport } = require('..')
Expand Down Expand Up @@ -3133,3 +3133,52 @@ test('local sign options should not overwrite global sign options', async functi

t.assert.strictEqual(fastify.jwt.options.sign.expiresIn, '15m')
})

test('reply.jwtSign should honor a per-request sign.key override', async function (t) {
t.plan(2)

const fastify = Fastify()
fastify.register(jwt, { secret: 'hunter2' })

fastify.post('/sign', async function (request, reply) {
return reply.jwtSign(request.body, { sign: { key: 'override' } })
})

await fastify.ready()

const response = await fastify.inject({
method: 'post',
url: '/sign',
payload: { foo: 'bar' }
})

t.assert.strictEqual(response.statusCode, 200)

const decoded = createVerifier({ key: 'override' })(response.payload)
t.assert.strictEqual(decoded.foo, 'bar')
})

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')
})