JWT Token Auto Renew in FeathersJS
Adam C. |

Photo by: ZSun Fu

Here are how we implement authentication using feathers in DNA.

We first login user using username and password with a "local" strategy, like:

{
   "strategy": "local",
   "email": "adam@deniapps.com",
   "password": "adam123$"
}

Then, we save the returned access token in local storage, and then we check if the token is expired or not when the user loads the page (the logic is in layout.js.) The user does not need to re-login until the token is expired. But our jwt token is set to expire in 1 day, so it causes some issues on the post editing page. Says we logged in yesterday at 10 am and started writing a post at 9:40 am today, so we have only 20 mins left before the jwt token is expired. While we are writing, the jwt token could be expired already, then when we click on the Publish button at 10:10 am, for example, we go the "NotAuthenticated" error.

Updated: We don't save JWT in the localStorage anymore, instead, we use httpOnly cookie. Check it out.

So how to fix this? Somehow we need to auto-renew the jwt token, but when? Our editing page has an auto-save function, which is called every time user inputs something, so we can add the jwt renewal logic there:

onAutSave = () => {
// if jwt expires?
// yes, show alert popup -> logout
// else, will jwt expires in 5 mins?
// yes, renew it
// continue;
}

We do cover the case that users may be idle for a long time, but when they come back, and input something, it will trigger onAutoSave, and they will see the logout alert. So it's not bad, isn't it? If we really need, we could add idle checking as well to logout the user or extend the session. 

Then back to another issue, the feathers JWT authentication method does not support auto-renewal out of the box, when we call the authentication function using the jwt strategy and current access token, it will return the same access token if the token is not expired. Good thing is that we can have a custom JW strategy function to regenerate the token.


const { JWTStrategy } = require("@feathersjs/authentication");

module.exports = class CustomJWTStrategy extends JWTStrategy {
  async authenticate(authentication, params) {
    // run all of the original authentication logic, e.g. checking
    // if the token is there, is valid, is not expired, etc.
    const res = await super.authenticate(authentication, params);

	// and now the key trick - by deleting the accessToken here
    // we will get Feathers AuthenticationStrategy.create()
    // to generate us a new token.
    delete res.accessToken;
    return res;
  }
};

The above code is borrowed from kn8.it. Karolis provided the solution to dynamic extend the JWT token session length, but In our case, the JWTStrategy is solely used to renew access token, so no need to check oat (original issuing timestamp), etc. 

The solution here could be an issue if someone got our token, which is supposedly expired in 1 day, but now they can call the authentication function with it before it's expired to get an unlimited access token. But I think the security behind the JWT token is assuming the bad guy won't see our token, otherwise, it's already big damage. What do you think?