Json (JSON Web Token)自动延长过期

I would like to implement JWT-based authentication to our new REST API. But since the expiration is set in the token, is it possible to automatically prolong it? I don't want users to need to sign in after every X minutes if they were actively using the application in that period. That would be a huge UX fail.

But prolonging the expiration creates a new token (and the old one is still valid until it expires). And generating a new token after each request sounds silly to me. Sounds like a security issue when more than one token is valid at the same time. Of course I could invalidate the old used one using a blacklist but I would need to store the tokens. And one of the benefits of JWT is no storage.

I found how Auth0 solved it. They use not only JWT token but also a refresh token: https://docs.auth0.com/refresh-token

But again, to implement this (without Auth0) I'd need to store refresh tokens and maintain their expiration. What is the real benefit then? Why not have only one token (not JWT) and keep the expiration on the server?

Are there other options? Is using JWT not suited for this scenario?

转载于:https://stackoverflow.com/questions/26739167/jwt-json-web-token-automatic-prolongation-of-expiration

I was tinkering around when moving our applications to HTML5 with RESTful apis in the backend. The solution that I came up with was:

  1. Client is issued with a token with a session time of 30 mins (or whatever the usual server side session time) upon successful login.
  2. A client-side timer is created to call a service to renew the token before its expiring time. The new token will replace the existing in future calls.

As you can see, this reduces the frequent refresh token requests. If user closes the browser/app before the renew token call is triggered, the previous token will expire in time and user will have to re-login.

A more complicated strategy can be implemented to cater for user inactivity (e.g. neglected an opened browser tab). In that case, the renew token call should include the expected expiring time which should not exceed the defined session time. The application will have to keep track of the last user interaction accordingly.

I don't like the idea of setting long expiration hence this approach may not work well with native applications requiring less frequent authentication.

How about this approach:

  • For every client request, the server compares the expirationTime of the token with (currentTime - lastAccessTime)
  • If expirationTime < (currentTime - lastAccessedTime), it changes the last lastAccessedTime to currentTime.
  • In case of inactivity on the browser for a time duration exceeding expirationTime or in case the browser window was closed and the expirationTime > (currentTime - lastAccessedTime), and then the server can expire the token and ask the user to login again.

We don't require additional end point for refreshing the token in this case. Would appreciate any feedack.

Good question- and there is wealth of information in the question itself.

The article Refresh Tokens: When to Use Them and How They Interact with JWTs gives a good idea for this scenario. Some points are:-

  • Refresh tokens carry the information necessary to get a new access token.
  • Refresh tokens can also expire but are rather long-lived.
  • Refresh tokens are usually subject to strict storage requirements to ensure they are not leaked.
  • They can also be blacklisted by the authorization server.

Also take a look at auth0/angular-jwt angularjs

For Web API. read Enable OAuth Refresh Tokens in AngularJS App using ASP .NET Web API 2, and Owin

I actually implemented this in PHP using the Guzzle client to make a client library for the api, but the concept should work for other platforms.

Basically, I issue two tokens, a short (5 minute) one and a long one that expires after a week. The client library uses middleware to attempt one refresh of the short token if it receives a 401 response to some request. It will then try the original request again and if it was able to refresh gets the correct response, transparently to the user. If it failed, it will just send the 401 up to the user.

If the short token is expired, but still authentic and the long token is valid and authentic, it will refresh the short token using a special endpoint on the service that the long token authenticates (this is the only thing it can be used for). It will then use the short token to get a new long token, thereby extending it another week every time it refreshes the short token.

This approach also allows us to revoke access within at most 5 minutes, which is acceptable for our use without having to store a blacklist of tokens.

Late edit: Re-reading this months after it was fresh in my head, I should point out that you can revoke access when refreshing the short token because it gives an opportunity for more expensive calls (e.g. call to the database to see if the user has been banned) without paying for it on every single call to your service.

An alternative solution for invalidating JWTs, without any additional secure storage on the backend, is to implement a new jwt_version integer column on the users table. If the user wishes to log out or expire existing tokens, they simply increment the jwt_version field.

When generating a new JWT, encode the jwt_version into the JWT payload, optionally incrementing the value beforehand if the new JWT should replace all others.

When validating the JWT, the jwt_version field is compared alongside the user_id and authorisation is granted only if it matches.

I solved this problem by adding a variable in the token data:

softexp - I set this to 5 mins (300 seconds)

I set expiresIn option to my desired time before the user will be forced to login again. Mine is set to 30 minutes. This must be greater than the value of softexp.

When my client side app sends request to the server API (where token is required, eg. customer list page), the server checks whether the token submitted is still valid or not based on its original expiration (expiresIn) value. If it's not valid, server will respond with a status particular for this error, eg. INVALID_TOKEN.

If the token is still valid based on expiredIn value, but it already exceeded the softexp value, the server will respond with a separate status for this error, eg. EXPIRED_TOKEN:

(Math.floor(Date.now() / 1000) > decoded.softexp)

On the client side, if it received EXPIRED_TOKEN response, it should renew the token automatically by sending a renewal request to the server. This is transparent to the user and automatically being taken care of the client app.

The renewal method in the server must check if the token is still valid:

jwt.verify(token, secret, (err, decoded) => {})

The server will refuse to renew tokens if it failed the above method.