Handling expiry/"remember me" functionality with JWT
Conceptually, I really like JWT as it is in line with the statelessness of REST etc (no state saved server-side, all relevant data is contained in the token).
What I am unsure about: how would you handle token expiry when not connected (ie, a "remember me" functionality)?
There's an emerging coverage of JWT on the web, but I couldn't find anyone that answered the expiry question yet.
Clarification: I am not asking how to handle a token soon-to-expire, but what to do when a token has already expired (user closed website/app for a while). The simplest solution that comes to my mind is caching the user's credentials, which is rather insecure.
I am not so sure if I follow but I will write what I think.
Imagine the token as a hotel card, you pay in advance for 5 days (remember me set to expire on 5 days). I can enter the building, garage, room, etc. within those 5 days, after those 5 days, it won't work anymore.
What to do when token has already expired? Nothing at all.
Imagine I pay those 5 days and meh, I had an urgency and I go back home (with the card on the pocket). The hotel doesn't care at all, when the 5 days pass, the card is just an useless piece of plastic and if you try to use it on the hotel, it will do nothing.
So back to web development. If you offer a remember me service, you can put an expiry date to let's say 7 days. As long as the user has the token, he can access the service without any problem. If he loses the token, he needs to login again. If he uses the token and it have expired, he will need to login again too.
If he login, he gets a token for 7 days, if he doesn't use it anymore and after 20 days he comes again, he would need to login again, the server will just decline your petitions until you do so.
What I would do if you use something like angular on the frontend is to check the token validation on startup so you can have a nice user experience.
What I don't understand about your question is de caching thing though.
There isn't a black and white answer to the given problem of how to implement the remember-me functionality theoretical wise. Lots of theoretical arguments are given on why something should not be done, while at the same time there is no clear answer given to the problem as for how it should practically be done.
Remember-me implicitly comes with the problem that you need a longer time window of token expiration, there is just no way around this. The most secure way is to have the user login regularly given brief expiry; nobody practically likes this though, so a tradeoff is made where theoretical secure perfection is weighed against practical measures.
The way this tradeoff works is by patching the imperfections that come with having a long expiry for a token. But make no mistake about it, you will need a jwt / cookie with long expiry (whether you use two tokens, implement some secondary refreshing mechanism or whatever, at the end you run into the same problem)!
Based on articles I've read on how others did it, this is how it's done.
The way I will implement this is by offering a 3-month expiry on a jwt stored in an httpOnly / secure cookie when the user checks remember-me.
On logout just clear the cookie.
Obviously protect using https / CSRF measures on top.
If you don't agree with it, stop fussing and offer an alternative solution - which there clearly isn't from the infinite number of discussions I've read on it.
If there were a straightforward solution to the problem, there probably wouldn't be so many discussions about it in the first place.
Edit:
You can use a refresh token mechanism, but it only works if you verify the time intervals when the refresh token gets used. For example, depending on the lifetime of the access token, you can govern how often you allow a user to refresh the token. If the intervals show suspicious activity, you should revoke both the tokens for all clients.
The problem revolves around the idea that either access token or refresh token would theoretically be stolen. So merely having a refreshing mechanism without additional security is essentially useless. If you can steal an access token, you can steal a refresh token too.
In addition to @Jesus answer, you can think about implementing a refresh token system: https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/
In the hotel-example, your hotel-card (access-token) would be invalid after time X, but at the reception you can use your passport (refresh-token) to get a new hotel card again.
You could store the refresh token in the database with additional data about the device the user is using, allowing him to disable the device in case it gets stolen.
Example:
- first correct client login: Create a refresh token which is valid forever (until it gets deleted or invalidated)
- store refresh token in database
- return access token (JWT) with expiration time to client ( this token gets not stored in database)
for the next request, the client sends the access token
-
Now Check if the access token is expired:
5.1 Access Token not expired, all okay
5.2 Access Token expired, check if there is a refresh token in database
5.2.1 Refresh Token is in database, return new Access Token
5.2.2 No Refresh Token in database, return 401 / logout, User has to login again
Hope this helps.