Prerequisites
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 true
const 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.
Prerequisites
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:
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#L518So, this config should call
key: fnonce, but withrequest.jwtVerify()it'sno-cachepolicy.Expected Behavior
So, correct usage is:
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
keythis test fails.If
keyisasyncthenverifier(token) => Promise<result>const user = formatUser ? formatUser(result) : result // Promise<result>request[decoratorName] = user // Promise<result>And
keyshould beasyncbecause it shouldn't be called under TTL.For example, I use
AWS KMS, and the library should not dokms.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.