I am creating a web server for a site with authentication using JWTs. Since this is going to be a publicly available system once ready, I would like to know if the following authentication flow using JWT access and refresh tokens could be considered secure. In this case it is assumed that one server serves both the auth API and resources
When the server starts, it will generate a "run ID" which is the current UNIX timestamp and random characters/UUID. This is stored in memory and any restart will generate a new one.
The user obtains an initial HttpOnly access and refresh tokens when logging in or registering. Access token has a short lifespan (~5 mins.) and refresh token has a longer lifespan (~2 hours).
The access token functions like normal and contains the userID. The refresh token has the userID, the server's run ID and its own unique "token ID" (similar to run ID, unique for each refresh token)
Instead of the user calling a token refresh endpoint, new access and refresh tokens are made when calling an endpoint that requires authorisation if the following criteria are met:
- The access token has expired
- The refresh token has not expired
- The run ID in the refresh token matches up with the current run ID
- The refresh token's token ID isn't blacklisted
In the event that there is a run ID mismatch or the token ID has been put on a blackist, the refresh token is instantly considered invalid. The token ID blacklist is stored in memory (like the run ID) as an array with the ID and expiration time. This allows a user to logout and blacklist that specific refresh token from being used. This also allows any system administrators to emergency invalidate all refresh tokens by restarting the server since the runID will change.
I would like to know if this can be considered a secure authentication flow
CodePudding user response:
It took me a while to understand what is going on with the tokens and your motivation around it. I believe what you did here is more complicated than reality requires and there should be little reason to introduce this level of complexity. Please also note, that security in its definition is a double edged sword. It's an eternal conflict between integrity and confidentiality VS availability. If for some reason we screw the systems availability then it will not be considered secure in the same sense, that turning a computer off is not considered a solution of security issues.
Having said that, let's look into your solution.
You intend to use access and refresh JWT tokens. How should a logout in such system look like? Well, you simply forget the token information on the client side or in case you want to hold tokens in cookies - which I believe you want to have based on "HttpOnly" flag - you can clean up the cookies. This is it. Once the information is gone from the client, the tokens can not be easily recreated. There is no need to blacklist the tokens on the server. It is in clients best interest to 'forget' the tokens he is not using and once the token is gone, there is no second copy to replace it.
We use token blacklisting in case we want to deal with a scenario like real-time user account locking. An expensive thing to implement if you ask me.
You can still try to blacklist refresh tokens, but assuming your authentication mechanism has access to the user pool, it can simply check in the database if the user is locked, no need to cache anything here.
Next thing I notice is that what you did here reassembles strongly simple Http Session handling including loosing the session once the server restarts. Why not forget the tokens and use a simple session instead?
I also wonder, why you intend to have only one instance of your system. In the High Availability age and playing with JWT tokens it would totally make sense to separate authentication module from logic and have more than one instance of both.
Please also note, that no one will be able to tell you, whether what you do is secure, until they can look into your code, configuration and ideally - working system. There are many small pieces that can break the solution. Ideally have a look into the OWASP ASVS (Application Security Verification Standard) available here to see, how deep the rabbit hole goes.