As I understand it, the typical (and simplified) usage of JWT refresh tokens is as follows:
- User logs into the system. User is granted a refresh token and a short lived (e.g: 10 minute expiry) access token. The refresh token is stored in the database of the "authentication server" for revocation purposes. Any requests made to the app ("resource server") will use the short lived access token.
- When the user's 10 minutes are up, the client will send a request to the auth server for a new access token using the refresh token.
- When the user changes their password or revokes access to a specific signin (in the case of theft, a lost device, etc), the refresh token is removed from the auth server database and rendered invalid.
Thus, when a user accidentally leaks his password out or loses his device, he can simply change his password, which would cause all previously issued refresh tokens to become invalidated.
However, the obvious security hole here is that the short lived access token is still perfectly valid for the next 10 minutes. And 10 minutes, no matter how short a time, is still plenty of time for a malicious user to cause some damage.
The only possible solutions I can think of are to:
maintain a blacklist or whitelist of access tokens. This makes the usage of refresh tokens seem pretty redundant. If we're going to hit the database on every request or to keep a cached list of blacklisted access tokens, then what's the point of having a refresh token?
make the expiry of the access token shorter (e.g: every 1 minute instead of every 10 minute). This doesn't solve the problem perse, it just does some damage control, since it shortens the window of time a malicious user has to do damage. And hitting the database for a new access token every minute doesn't seem much better than hitting the database on every request.