I am implementing a JWT refresh token and have developed the following way of refreshing tokens. The following is the program flow:
- When server retrieves login information, it checks against password database and creates JWT token with a refresh token as one of its claims in the payload. (random characters). It will store the refresh token in a database.
- Upon login, server returned login:true and the JWT access token
- Since the refresh token is inside the JWT, two tokens do not need to be sent
- If the client sends an access token that has expired, the server will check the refresh token in the claims and see if it is inside the db. If it is, it will generate a new token with a new refresh token, and replace the old refresh token in the db with the new one.
- If client wants to log out of all devices, they can simply revoke all of their refresh tokens and they will be logged out when all their tokens expire (15 minute JWT tokens).
The advantages I see to this implementation are:
- No need to send two tokens. The refresh is embedded inside the JWT and cannot be modified because that would invalidate the signature.
- No need to encrypt the refresh token in the database because if an attacker got a hold of the refresh token, they cannot do anything with it because it is inside the JWT and cannot be modified. (In other implementations with separate tokens we should assume an attacker gets a hold of both anyways)
The problems I see with this are:
- JWTs always contain the refresh token, so the attacker will ALWAYS be able to perform a refresh and use the refresh token until it expires, unless the client revokes it by logging out (of all devices).
- The client can run the login call in a loop and fill up the database because every time they log in, a new access token is created and a new refresh token is stored into the database.
Is this method secure? If so, I'm primarily concerned with someone filling up the database with new refresh tokens and filling up the disk. How do I avoid that from happening?