I have an async function:
const jwtDecode = async (token) => {
//return jsonwebtoken.verify(token, TOKEN_SECRET)
console.log("jwt decode, token: " + token)
try {
const { payload } = await jose.jwtVerify(token, new TextEncoder().encode(TOKEN_SECRET))
return payload
}
catch (e) {
console.log("Caught error jwt decode")
console.error(e.message, e.stack)
return {}
}
}
That function is wrapped by a few other async functions, where await is used.
const foo = async (token) => {
const {userId} = await jwtDecode(token)
return userId
}
const foo2 = async (token) => {
const userId = await foo(token)
return userId
}
const userId = await foo2(token)
When an exception is thrown in jwtDecode, then the whole chain seems to forget about await and executes as if it didn't exist. On top of that, the call to foo2 returns a Promise instead of 'undefined'
I know there is a logical explanation to this. Could someone explain and provide the solution? Thanks
UPDATE:
Here is the full code:
This first call happens in my _middleware.js (I am using Next.js)
export async function middleware(req, ev) {
...
...
...
const userId = await serverUtils.authorizeRequest(req)
...
...
...
const authorizeRequest = async (req) => {
const accessToken = req.cookies.PictosAT
let { userId } = await jwtDecode(accessToken)
if (!userId) {
userId = null
}
console.log("Authorize request userId is " + userId)
return userId
}
const jwtDecode = async (token) => {
console.log("jwt decode, token: " + token)
try {
const { payload } = await jose.jwtVerify(token, new TextEncoder().encode(TOKEN_SECRET))
return payload
}
catch (e) {
console.log("Caught error jwt decode")
console.error(e.message, e.stack)
return {}
}
}
You're not catching at the proper place. You need the consumers of jwtDecode to be able to determine if the function succeeded or not. With your current approach, return {} means that at the top of the chain, const userId = await foo2(token) will assign undefined to userId. If you catch inside jwtDecode, that means that its consumers can't see that there was an error.
Figure out where the error can be meaningfully caught. If you want this line:
const userId = await foo2(token)
to not run at all if there's a problem, then either omit the catch entirely so the error is caught even higher up the chain, or re-throw the error inside jwtDecode so other functions can see that it failed.
Another option is to catch at the point of assignment to userId, then check if it's truthy or not.
const jwtDecode = async (token) => {
const { payload } = await jose.jwtVerify(token, new TextEncoder().encode(TOKEN_SECRET))
return payload
}
const foo = async (token) => {
const {userId} = await jwtDecode(token)
return userId
}
const foo2 = async (token) => {
return foo(token);
}
// resolve to undefined if there was an error:
const userId = await foo2(token).catch(() => {});
if (!userId) {
// put your desired error handling here...
return;
}
// continue on with code that depends on the populated userId here