Description
Prerequisites
- I have written a descriptive issue title
- I have searched existing issues to ensure the bug has not already been reported
Fastify version
4.26.1
Plugin version
8.0.0
Node.js version
20
Operating system
macOS
Operating system version (i.e. 20.04, 11.3, 10)
m1
Description
An example from the documentation looks like this:
fastify.decorate("authenticate", async function(request, reply) {
try {
await request.jwtVerify()
} catch (err) {
reply.send(err)
}
})
Steps to Reproduce
But this example creates a new verifier instance and a new cache instance for each request:
request.jwtVerify(next=undefined)
function requestVerify (options, next=undefined)
options = {}
if (next === undefined) {
request[jwtVerifyName](options, function (err, val) {
function requestVerify (options={...}, next=function)
function verify (secretOrPublicKey, callback)
if (useLocalVerifier) {
and useLocalVerifier is trueconst localVerifier = createVerifier(verifierOptions)
cache: createCache(cacheSize),
src/verifier.js#L518
So, this config should call key: fn
once, but with request.jwtVerify()
it's no-cache
policy.
{
secret: {
public: async (_1, _2, callback) => {
console.log("on request: false");
return false;
}
},
// namespace: "-",
verify: {
algorithms: ["ES512"],
cache: true,
maxAge: "2d",
cacheTTL: 100000000000,
key: ((x: unknown, cb: (err: unknown, currentKey: unknown) => void) => {
console.log("fetching public key", "should be cached and called once");
return Promise.resolve("external kms key");
}) as unknown as string,
},
}
Expected Behavior
So, correct usage is:
server.decorate("authenticate", async (request, reply) => {
try {
await new Promise((resolve, reject) => {
request.jwtVerify((err, payload) => {
if (err) {
reject(err);
return;
}
resolve(payload);
});
});
} catch (err) {
await reply.send(err);
}
});
Maybe this is how it should work, but I spent a lot of time trying to figure out why the cache doesn't work.
I used a test with namespaces from your library. And when using asynchronous key
this test fails.
If key
is async
then
verifier(token) => Promise<result>
const user = formatUser ? formatUser(result) : result // Promise<result>
request[decoratorName] = user // Promise<result>
And key
should be async
because it shouldn't be called under TTL.
For example, I use AWS KMS
, and the library should not do kms.fetchPublicKey()
for every incoming request. I can of course use my own cache for public keys, but this is supported out of the box in fast-jwt.