I've been thinking about the same problem lately and would like to know if there are any major pitfalls to my token solution:
- Set expiration to a low value (~15 minutes)
- Every generated JWT also gets added to an "issuedTokens" collection/table for each user
During JWT validation, if the expiration has passed, an "Expired" response would be returned from the server (ex. 401 w/ "Expired" in body). When the client receives this status, it should initiate a refresh process which trades an expired token for a new one.
The refresh endpoint on the server should take an expired token and perform the following:
- Validate token (except expiration)
- Retrieve user ID and check if token is in its issuedTokens collection
- Issue a new JWT
- Remove the expired token from the collection and add the new one
Upon failure of any of these steps, an Unauthorized error should be sent to client which then requires logging in again.
To prevent a never-ending build-up of issued tokens, we can set a TTL on the tokens in the issuedTokens collection. Set the TTL value to the amount of time that a login should be active for before requiring logging in again.
This approach doesn't hit the database unless you keep trying to refresh an expired token. In which case you can make use of a cached blacklist of failed tokens. This can reside next to the application itself if treated as a cache layer.
This is definitely just a work-in-progress solution that I'm about to test out. Let me know your thoughts on it.