How to log out when using JWT
One does not simply log out when using JWT
The wonder of JSON Web Tokens
JSON Web Tokens (JWT) is a way of statelessly handling user authentication. What does it mean? Well, JWT helps to organize authentication without storing the authentication state in any storage be it a session or a database. Thus, when checking user’s authentication status you do not need to access the session or perform a database query. Instead, you generate a token based on the user payload of your choice and use it in requests from client side to identify the user on the server. 🛂
So, basically, whenever a token is created, it can be used forever, or until it is expired. JWT generator can get an option to invalidate the token after a specified time.
But what to do if you want to invalidate an existing token? What you actually need to do when the user opts to log out or let’s say change password? 🤔
Let’s log out
Okay, so usually, when using JWT authentication, the client side stores the token somewhere and attaches it to every request that needs authentication. So, the first thing to do when logging out is just to delete the token you stored on the client (e.i. browser local storage). In that case, the client won’t have a token to put in the request, thus causing unauthorized response status. But is that enough? Well, that specific client (browser, app) won’t be authenticated anymore, but the token still exists somewhere and it is still valid! If someone has copied the token from the request before, he/she would still be able to perform requests on behalf of the user! 👾 You can easily try this out on your own.
“Okay, so let’s log out the user from the backend!” you would say. But hold down the horses. It’s not that simple with JWT. You cannot delete the session or cookie and get going.
Actually, JWT serves a different purpose than a session and it is not possible to forcefully delete or invalidate an existing token.
Expiring a token?
Yes, the tokens can be expired. No, you cannot do it on demand.
When signing a user payload for a JWT you are allowed to pass an expiration time to it. You can provide it as a field called
exp in the payload like this:
The expiration field takes a number of milliseconds since the start of Unix epoch. As the
iat field here stands for “issued at”, this token is set to expire 5 seconds after it was issued. ⏰
Note: If you are using one of the JWT libraries listed here, most likely you can also pass an expiration time in the signing method options.
If you don’t want to have forever valid tokens, you should always set a reasonable expiration time on you JWT. The amount of time really depends on your application. We’ll go with one-day tokens here and generate them in our login action. For a NodeJS app the code should look something like this:
So, when the token expires, the validator will return an error and you backend will respond with an unauthorized response status as soon as it gets a request that needs authorization. Usually, you will unset the token from the client side and redirect the user to the login page. So, with this example, all users will be automatically logged out after 1 day of using your app.
“Cool, but I still want to log out!” ➡️
As already said, you cannot manually expire a token after it has been created. Thus, you cannot actually log out with JWT on the server side like you do with sessions 🙀Or, unless, you can…
It is said that using JWT should be stateless, meaning that you should store everything you need in the payload and skip performing a DB query on every request. But if you plan to have a strict log out functionality, that cannot wait for the token auto-expiration, even though you have cleaned the token from the client side, then you might need to neglect the stateless logic and do some queries.
An implementation would probably be, to store a so-called “blacklist” of all the tokens that are valid no more and have not expired yet. You can use a DB that has TTL option on documents which would be set to the amount of time left until the token is expired. Redis is a good option for this, that will allow fast in memory access to the list. Then, in a middleware of some kind that runs on every authorized request, you should check if provided token is in The Blacklist. 🕵️ If it is you should throw an unauthorized error. And if it is not, let it go and the JWT verification will handle it and identify if it is expired or still active.
As it seems, creating a clean log-out flow when using JSON Web Tokens is not so straightforward. You should either let a token be active until it is expired by itself or opt to use a storage for logged out tokens if you want to restrict the usage of a token when a user logs out. To sum it all up, simply follow this 4 bullet points:
- Set a reasonable expiration time on tokens
- Delete the stored token from client side upon log out
- Have DB of no longer active tokens that still have some time to live
- Query provided token against The Blacklist on every authorized request
Want more on JWT?
Here is my article on how to use JWT with Passport.js 😉