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 wa
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.
Ref - Refresh Expired JWT Example
Another alternative is that once the JWT has expired, the user/system will make a call to another url suppose /refreshtoken. Also along with this request the expired JWT should be passed. The Server will then return a new JWT which can be used by the user/system.
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.
I work at Auth0 and I was involved in the design of the refresh token feature.
It all depends on the type of application and here is our recommended approach.
A good pattern is to refresh the token before it expires.
Set the token expiration to one week and refresh the token every time the user opens the web application and every one hour. If a user doesn't open the application for more than a week, they will have to login again and this is acceptable web application UX.
To refresh the token, your API needs a new endpoint that receives a valid, not expired JWT and returns the same signed JWT with the new expiration field. Then the web application will store the token somewhere.
Most native applications do login once and only once.
The idea is that the refresh token never expires and it can be exchanged always for a valid JWT.
The problem with a token that never expires is that never means never. What do you do if you lose your phone? So, it needs to be identifiable by the user somehow and the application needs to provide a way to revoke access. We decided to use the device's name, e.g. "maryo's iPad". Then the user can go to the application and revoke access to "maryo's iPad".
Another approach is to revoke the refresh token on specific events. An interesting event is changing the password.
We believe that JWT is not useful for these use cases, so we use a random generated string and we store it on our side.
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.
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:-
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