JWT authentication: How to implement logout?
I don't think there is a best practice here. I guess it depends on the application you're building and it's requirements.
The benefit of JWT is that they're stateless. You don't need to query the database to validate the token. This is good when you wish to reduce the load on your database but bad when you want to invalidate an existing non-expired token.
Possible solutions:
- Store JWT in the database. You can check which tokens are valid and which ones are revoked but this defeats the purpose of using JWT at all in my opinion.
- Delete token from the client. This would stop the client from being able to make authenticated requests but if the token is still valid and somebody else has access to it, the token could still be used. This leads me to my next point.
- Short token lifetime. Let the tokens expire quickly. Depending on the application, it could be several minutes or half an hour. When the client deletes its token, there's a short window of time where it can still be used. Deleting the token from the client and having short token lifetimes would not require major modifications on the back-end. But short token lifetimes would mean that the user is constantly being logged out because the token has expired.
- Rotate tokens. Maybe introduce a concept of refresh tokens. When the user logs in, provide them with a JWT and a refresh token. Store the refresh token in a database. For authenticated requests, the client can use the JWT but when the token expires (or is about to expire), let the client make a request with the refresh token in exchange for a new JWT. This way you would only have to hit the database when a user logs in or asks for a new JWT. When the user logs out, you would need to invalidate the stored refresh token. Otherwise somebody listening in on the connection could still get new JWTs even though the user had logged out.
- Create a JWT blacklist. Depending on the expiration time, when the client deletes its token, it might still be valid for some time. If the token lifetime is short, it might not be an issue, but if you still wish that the token is invalidated immediately, you could create a token blacklist. When the back-end receives a logout request, take the JWT from the request and store it in an in-memory database. For each authenticated request you would need to check your in-memory database to see if the token has been invalidated. To keep the search space small, you could remove tokens from the blacklist which have already expired.
I don't know what's best practice, but in a system whose internals I have seen, there is a central authentication manager which knows all the currently valid authentication tokens, so logging out would simply consist of removing the token from the collection of valid tokens.
So, next time the authentication manager is asked whether the token is valid, it would respond with a "no".