Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: refresh token for jwt #28

Open
aichbauer opened this issue Oct 23, 2018 · 8 comments
Open

Feat: refresh token for jwt #28

aichbauer opened this issue Oct 23, 2018 · 8 comments

Comments

@aichbauer
Copy link
Owner

aichbauer commented Oct 23, 2018

Currently the access token is valid as long as the expiration time is set to and than the user has to re-authenticate. This means if the token is valid for a long time, and the token gets compromised by a third party this means that this third party can have access as long as they want to a service, unless we change our secret on for the jwt for our service. There are other ways like: blacklisting compromised tokens, but this is only possible if we can check that it is not the real user, that is using this token to get access to our service. So we need to be sure, which is only possible if a user tells us explicitly that this is not him, or we try to create a pattern a for a user, e.g. storing information on IP, Location, OS, browserinfo, etc. but this would need additional db request every time a user makes a request.

If we used a refresh token, we would send a access token, and a refresh token to the client (maybe as a http only cookie?) and store a relation for the refresh token and a user that uses this refresh token. E.g. in the database or in another mutable store on the server.

EDIT: Do not think that http only cookies, or cookies should be set as default. There could be problems with mobile apps when this serves as backend. This could be a opt-in or maybe we could check if a mobile app or a web browser accesses the app, but this is not a problem that this project solves rather a problem a individual user has to decide.

The access token expires fast e.g 1 minute, 7 minutes, or longer (depending on the service, security risks, etc). This means there is no additional db call within the time this token is valid, as soon as it expires, we check the refresh token and check if its the same that we stored for our user. if so create a new jwt and refresh token and send it to a user, if not clear the refresh token in the store and the user has to re-authenticate e.g. login with credentials or similar.

something similar like

// this is just pseudo code, e.g. accessToken === valid
const auth = (req, res, next) => {
  const accessToken = req.cookies.accessToken;
  const refreshToken = req.cookies.refreshToken;

  if(accessToken && refreshToken) {
    if(accessToken === valid) {
      return next();
    }
    if(refreshToken === valid) {
      const {
        accessToken,
        refreshToken,
      } = createNewToken(); // clear old refreshToken for user, save new refreshToken

       res.cookie('accessToken', accessToken, cookieOptions);
       res.cookie('refreshToken', refreshToken, cookieOptions);

      return next();
    }
  }

  // possible attack
  return res.status(401).json({ msg: 'Unauthorized' });
};
@krzepah
Copy link
Contributor

krzepah commented Jul 12, 2019

I've never really understood the concept of sending a refreshToken ; it always reminded me of a super JWT that could get compromised just as well but never had any kind of depreciation.

I've read that solution just so many times tough that I cannot say if it's good or bad.

I'm going to PR you that in a few because I feel like that what's actually happening.

If you have any more intel since then (issue is almost a year old) let me know !

@krzepah
Copy link
Contributor

krzepah commented Jul 12, 2019

https://tools.ietf.org/html/rfc6749#section-6 That should make everything clear

edit: that's the oAuth rfc 🔫 :')

Here's a proposal PR using a refresh endpoint instead of sending it over & over again. Let me know if you prefer a middleware solution where the refresh_token is sent alongside the access_token.

@krzepah
Copy link
Contributor

krzepah commented Jul 13, 2019

What do you think of a solution alike to passport or even node-oidc-provider ?

@aichbauer
Copy link
Owner Author

@krzepah thanks for your contribution... I will take a look at it within the next week...

@aichbauer
Copy link
Owner Author

@krzepah Thanks... Yeah, you are right about that being some kind of super token... The thing that makes this a bit more secure is:

  • People likes to be logged in to the application and do not want to login over and over again every couple of miniutes.
  • so we have multple options to handle that (here are two): 1.) let the jwt expire in far future, which means if a jwt gets compromised, the attacker can use the application as long as the jwt is working, which means we need a way to disable compromised jwts, 2.) let the jwt expire in near future and add refreshtokens (every couple of minutes) so if a attacker gets a jwt without a accesstoken, the attacker can only use it couple of mins. If an attacker gets a jwt and an refreshtoken, the attacker can use it as long as the user does not log in again. So if the user tries to access the application with an expired jwt and an old refreshtoken, the user is not able to use the application, thus has to login again, which disables the refreshtoken of attacker, so the attacker has no access to the application any more.

this are not perfect solutions, but better than a long living jwt.

I worked with passport, but stopped using it (no specific reason)...
I never worked with node-oidc-provider...

@krzepah
Copy link
Contributor

krzepah commented Jul 21, 2019

Hi,

They are not meant login again, it is up to the client to request the token Refresh. Also, it is not meant to be used again with username and password but with the refreshToken.

I didn't want to send it over and over again trough the network uselessly but only when required. That's why I didn't change the Auth.Service because all endpoints are not meant to work as refreshers. The more "difficult" point is understanding when these refreshToken should be completely revoked to not let any "super token" hanging.

That proposal reflects more of my "dev tastes" but I understand that you would prefer a service. I'm looking at node-oidc / passport as libs that have made most of the "classic" decisions them selves ; leading into doing less tricky stuff ;

Node-oidc-provider requires some custom stuff tough, but I'm definitely getting more into it when I'll get the time.

Thanks for your time !

@aichbauer
Copy link
Owner Author

Alright, I see... that sounds great, everything that can be spared from a request is good... I'll take a closer look on this one...

@krzepah
Copy link
Contributor

krzepah commented Jul 21, 2019

Thanks a lot, if you think it's not such a great idea at all (for whatever reason), i'll implement it just the way you asked o7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants