Let’s start with explaining what JWT stands for, however the main focus of this post is not about how JWT can increase security, but how it harms it.
JWT is a standard that is used to create access tokens. This token is usually created on the server ( not a must ) and sent to the client and ensures that the information signed by the server is not modified by anyone else.
As JWT is signed with server private key on the time of creation, no one can modify this information without this key. Let’s say the JWT token holds the information “username=evrenbal” and “userId=1”. If the server receives back this token later, it doesn’t need to query the database for the Id and can safely use the id provided by the client by only validating the token.
What JWT is not?
Contrary to popular belief, JWT is not reliable if it is not applied consciously and may not be used for authentication in critical operations.
What if “evrenbal” discovers that his password has been stolen, or he has not logged out on a public computer he used recently. Probably, he will immediately login his account and change his password and assume that he has solved the problem. The problem is, as the developer you are not checking the password but only if the token is valid or not and changing the password does not invalidate the token on that public computer.
JWT’nin geçerlilik süresini kısa tutup (Örneğin bir kaç saat), daha uzun süreli (Örneğin bir kaç ay) bir It would be a good option to keep the validity period of the JWT short (for example, a few hours) and to create a “refresh token” with a longer duration (for example, a few months).
BöIn this way, while ensuring that an “access token” becomes ineffective after a few hours, you can automatically create a new access token without forcing the user for re-logging after 1 day. There is a handicap with this approach, in order to validate the long-term refresh token, you need to store it in the database.
If the refresh token sent is still valid and is the same with the one in the database, you can create an access token without hassling the user. So if the user has changed his password, you can simply modify the refresh token in the database and ensure the tokens you created before are invalid. We can even ask the user if he want to logout other devices when changing their password.
We have found an excellent solution! Did we? Unfortunately not! Because during the validity period of the access token we have no chance to find out that the person using the token must be unauthorized. We can only invalidate the user whenever the access token expires and needs to be renewed.
As a solution, you may use access tokens that expires after a few minutes, not after long hours. In this case, you will still experience a few minutes of delay, and in fact, you will not be using the JWT the way you think by constantly querying the database.
Then how to use JWT?
Let’s try to think of safer solutions for the example above. Whether our user has his account password stolen or left his account open without logging out of the internet cafe we may apply one of the following solutions.
Short Fix:
Let’s check out the creation date of JWT against the last password change date stored in database/redis etc. and deny the request if the password is younger than the JWT.
Result: We secured evrenbal’s account as soon as the password is changed, but he will be logged out from all other devices even they are his valid secure devices.
Longer but more effective solution:
Let’s create a unique ID for the device that the user logs in every time he logs in. For example, let this ID be “ABCDE”. You may store “ABCDE” in a session variable (will be stateful), in the database or for better performance in a solution such as memory or Redis. Along with the unique ID, you can optionally store some additional information about the device. (For example, IP, operating system, user agent etc.)
You saved the ID on your server, but you also need to store the “ABCDE” ID in the JWT you are going to send the client. Every time you got the token, check it against the ID you stored on the server.
Result: When the user changes his password; we can simply delete all previously logged in devices from the server/database so all previously served JWTs will become invalid. Better than that, we can simply list the logged in the devices on users settings page and allow him/her to logout any previously used devices, so he/she can simply logout a specific device without changing his/her password.
Is this all necessary?
Is JWT really necessary if we are only going to store the device information ABCDE in it? We still store the ID, we still need to query the database, and manage validity of the tokens. Most of the time Using simply a small cookie with much smaller size and without the need of an extra JWT library can be a better solution.
Yes, JWT is an exciting technology and you want to do everything using JWT especially when you first learn it. However before integrating JWT in a project, simply pause for a while and ask yourself whether you really need to use JWT and if a simple but still reliable alternative exists or not.
Please share your thoughts using the comment form below.