I have an application developed using React in the front-end and ASP.Net Web API in the backend. I am using JWT for authorization. The process is
- When a user logs in and is authenticated, 2 tokens are sent to the front-end, access token and refresh token. An access token is the JWT and a refreshes token is a random string and a refresh token is stored in a database.
- For every subsequent call to APIs access token is attached in the header, I have an authentication filter that validates the access token.
- Once the access token is expired, a 401 status is thrown with the error message TokenExpired.
- Once the front-end receives 401, it calls the refresh token API to get the refresh token
The question I have is that I cannot have an authentication filter to validate the access token of refresh tokens API as it will throw 401 due to the expired access token, so I need to make the refresh token API to be anonymous so it does not hit authentication filter. If I make anonymous I am making a call to the database to get the refresh token stored for the user and compare it with the one I received from the front-end. So is it safe to make the refresh token API anonymous, if not what's the best way?
CodePudding user response:
At Auth0, Created a set of features that mitigate the risks associated with using refresh tokens by imposing safeguards and controls on their lifecycle. Our identity platform offers refresh token rotation, which also comes with automatic reuse detection.
Please read the following topic.
Refresh Token Automatic Reuse Detection
CodePudding user response:
The JWT is signed using preshared secret key. Since it’s REST API in the backend and stateless, jwt is used for authorization and construct principal object
As you say, the access token represent authorisation in your application, if the refresh token is exposed then the refresh token can be presented by a bad actor to obtain an access token they can use for the same authorisation.
Using a 'preshared secret' indicates the JWT is a HMAC only variant of JWT, i.e. there is no encryption as that would indicate private and public key pair opposed to a 'preshared secret'. So the JWT is essentially a signature for the puposes of security characteristics we are ensuring integrity that the claims of the JWT are well-formed and have not been changed since signed. It also means same secret is used for signing on one end as was used to verify on the other end, the same secret has to be used because verifying a signature requires that both ends generate the signature and both of the signature match. So no data is being encrypted, so not data in the JWT is sensitive and needs to be protected.
Given this context, both the refresh and access token are a simple JWT that can only be generated by the holder of the secret - if they are exposed they can be used to make malicious requests as long as they remain valid (nbf
claim).
Essentially this type of JWT can be misused if exposed to impersonate the identity the secret that signed the JWT represents, without actually knowing the secret itself, until the nbf
claim expires the token - and a refresh token is the mechanism to extend the nbf
claim without having the secret (which would result in a new signature, because the nbf
claim would change when used).
There is one protection from access token reuse, it is the nonce claim. If you do not currently use a nonce claim you can read about how OIDC have implemented and do he same in your app. But as you say, your app is stateless but hopefully the backend has a form of state to ensure no nonce reuse and prevent JWT signature reuse. For every nonce the JWT signature changes, therefore the access token changes and can be used only 1-time. So if stolen it is a race condition who uses the token first, which greatly minimises the risk but not a perfect solution.