0

I am implementing refresh tokens with jwt in NodeJS, and storing the refresh token in a MongoDB collection (I'm using mongoose). I have an access token and refresh token being generated on a user's login, using the email as a payload. Both are being sent back to the user, and the refresh token is stored in the database. When the user makes a request for a page, I have middleware to check their access token. If it's still valid, all is well and they proceed to the page. If it's expired, then another method is called, which checks the refresh token against the database, which is where the list of 'logged on' users is. If it finds the refresh token in the list of logged in users, it generates a new access token and sends both the new access token and the same refresh token back to the user.

My problem is this. My function to check the access token is spotting the expired token. It then calls the function to check the refresh token. That function starts, then as soon as it hits the query line, the call returns to the access token function. It checks for the new access token, which at the moment is undefined, and returns an error. The call then returns to the second function, where the query is executed (by then it's too late). Here's the code:

    export async function checkAccessToken(req, res, next) {
    const authHeader = req.headers['accesstoken'];
    const token = authHeader && authHeader.split(" ")[1];
    const refToken = req.headers['refreshtoken'];
    const user = req.headers['uemail'];
    const email = user;

    if(token && refToken){
        console.log("Line 62 Token is: " + token);
        jwt.verify(token, ACCESSTOKEN_TEST_SECRET, async (err, tokenstring) => {
            console.log("Line 64 reached");
            if(err){
                console.error('before the refresh access token')
                const newAccessToken = await refreshAccessToken(refToken, email);
                console.log(newAccessToken)
                    if(newAccessToken){
                        console.log("Line 70 NewAccessToken: " + newAccessToken);
                        res.locals.accessT = newAccessToken;
                        res.locals.refreshT = refToken;
                        console.log("Line 73 The access token was refreshed: " + newAccessToken);
                        next();
                    } else{
                        console.log("Line 76 New Access Token is: " + newAccessToken);
                        return res.status(401).json({message: 'Authorization1 Failed'}); 
                    }
            } else{
                res.locals.accessT = token;
                res.locals.refreshT = refToken;
                next();//token is still valid, we can proceed
            }
        })
    } else{
        return res.status(401).json({message: 'Authorization Failed'});
    }
    }

    function refreshAccessToken(refreshToken, email) {
    console.log("Line 97 RefToken in refreshAccessToken method: " + refreshToken);
    console.log("Line 98 email: " + email);
    
    RefToken.findOne({token: refreshToken}, function (err, token){
        if(err){
            console.log("Line 102 Error in RefToken.findOne()");
            console.log(err);
            return null;
        }
        if(token){
            console.log("Line 107 DB contains refresh token");
            jwt.verify(refreshToken, REFRESHTOKEN_TEST_SECRET, (err, result) => {
                if(err) {
                    console.log("Line 111 Something happened in jwt.verify. refreshToken: " + refreshToken);
                    return null;
                } else {
                    console.log("Line 114 Token verified");
                    console.log(`Result: ${result}`)
                    const newAccessToken = jwt.sign({email: email}, ACCESSTOKEN_TEST_SECRET, {expiresIn: "2m"});
                    console.log("Line 117 New Access Token from refreshAccessToken: " + newAccessToken);
                    return newAccessToken;
                }
            });
        }   
    });
}

Now, I'll be the first to admit that I don't have a firm grasp on async await. My understanding was that calling 'await function' stops the code call in the bigger function until the awaited one is complete. I could be wrong though. But when I simply run everything synchronously, no await or async anywhere in the code at all, it does the same thing. Here is the output to the terminal:

  DB Connect was was a success!
 Server is running on http://localhost:4000
Line 62 Token is: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG5zbWl0aEBnbWFpbC5jb20iLCJpYXQiOjE2NDUwNTM1MzAsImV4cCI6MTY0NTA1MzY1MH0.fn0dMszNioidsLbSJzxgrTa0bCouHYRnj7H_k79rHX0
Line 64 reached
before the refresh access token
Line 97 RefToken in refreshAccessToken method: eyJhbGciOiJIUzI1NiJ9.am9obnNtaXRoQGdtYWlsLmNvbQ.beNdGuRcM6b29v3GgkxfTzXI7qXJkr7ntZoVLB0DOoU
Line 98 email: johnsmith@gmail.com
undefined
Line 76 New Access Token is: undefined
Line 130 DB contains refresh token
Line 137 Token verified
Result: johnsmith@gmail.com
Line 140 New Access Token from refreshAccessToken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG5zbWl0aEBnbWFpbC5jb20iLCJpYXQiOjE2NDUwNTc3NjIsImV4cCI6MTY0NTA1Nzg4Mn0.eyET-fN9gAr2Lp4rxk2Ne1VP_yekR6jtgV-CJZh53gA

I would greatly appreciate if someone could point out where I've gone wrong here.

  • Here's your first hint. `await` ONLY does anything useful when you're awaiting a promise that is resolved/rejected when your asynchronous operation is complete. And, you cannot be using plain callbacks for your asynchronous operations (as you are) because those are not connected to any promise. – jfriend00 Feb 17 '22 at 01:10
  • 1
    This is probably a case of you need to study [How to return the response from an asynchronous call](https://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call) and either implement a callback-based solution or a promise-based solution. Pick one model - do not mix them. Right now, you're trying to use promise features on plain callback asynchronous operations which does not work. Not not attempt to mix the models. – jfriend00 Feb 17 '22 at 01:11
  • FYI, the correct title would be `asynchronous function is acting asycnhronously` since there's really not much synchronous here. – jfriend00 Feb 17 '22 at 01:19

0 Answers0