Recently I needed to build a simple REST API and I read different articles on best practices to reduce as far as possible the vulnerabilities of my web app. Searching online I found different tutorials on how to implement JWT tokens, every one different in some aspects, and I couldn't find a well throttled "common approach". In the end, I achieved the solution that seemed most reasonable to me but I wanted to confirm that this is the most efficient way to handle this type of authentication.
Before starting:
#STEP 1: Generating tokens after authentication:
#STEP 2: Authorizing requests
To authorize requests, I only use the access token that is sent in a field in the header of the requests. Requests are allowed only if the token is valid.
#STEP 3: Refreshing access token
To refresh the token I send a refresh request to the server. The server:
MORE INFORMATION on the refresh process
Refresh is called:
FURTHER PRECAUTIONS: CRITICAL OPERATIONS
Refresh tokens have two expiration times. The first, for non-critical operations, is refreshed every time a new token is issued. In this way, if the user continues to use the app, he/she can stay logged potentially forever. The second (that lasts 3 hours), for critical operations, is "absolute". This means that, at every refresh, the "timer" for critical operations isn't refreshed.
//To make it simpler:
nextToken.criticalExpiration=previousToken.criticalExpiration
When the refresh request is called after the expiration of the "critical" timer, the access token generated has a field to false that symbolize the option to perform critical operations. If false, critical operations are not allowed (and so users have to re-authenticate to perform these requests)
Summary:
I'd like to understand if this process is executed correctly or if it generates vulnerabilities. I understand that vulnerabilities can be always possible in other parts of the app and/or in external libraries, however, I'd like to minimize the possibility of leaving something that can be exploited.
There are two critical steps in using JWT securely in a web application: 1) send them over an encrypted channel, and 2) verify the signature immediately upon receiving it. The asymmetric nature of public key cryptography makes JWT signature verification possible.
To keep them secure, you should always store JWTs inside an httpOnly cookie. This is a special kind of cookie that's only sent in HTTP requests to the server. It's never accessible (both for reading or writing) from JavaScript running in the browser.
Figure 1 shows that a JWT consists of three parts: a header, payload, and signature.
You have to create controllers, middlewares for login, generating the jwt token and also for the refresh token. See: https://stackabuse.com/authentication-and-authorization-with-jwts-in-express-js/ for more detail.
I dont understand why you have 2 expiration times for refresh token. I think one is enough, just make sure you use refresh token rotation.
User login and get access token (AT1) and refresh token (RT1). If AT1 expires and the user use RT1, you need to invalidate the refresh token, then give new refresh token to the user, lets say RT2.
I save RT1 in redis (list of invalidated refresh token)
If someone steal RT1 and use it, the server can check and know that RT1 already in redis.
So you need to invalidates RT2 and all access tokens that belongs to RT 1 and RT2.
By doing this, the user need to login again.
See: https://auth0.com/docs/tokens/refresh-tokens/refresh-token-rotation
Refresh is called:
- Before the expiration of the access token
I agree, or maybe you can use axios interceptor, when the response 401 (unauthorized) you can send refresh token.
I agree with
Auth0 recommends storing tokens in browser memory as the most secure option. Using Web Workers to handle the transmission and storage of tokens is the best way to protect the tokens, as Web Workers run in a separate global scope than the rest of the application. Use Auth0 SPA SDK whose default storage option is in-memory storage leveraging Web Workers.
From here: https://auth0.com/docs/security/data-security/token-storage#browser-in-memory-scenarios
Note that any values stored in memory are still vulnerable to XSS attacks, it just more hard for someone to get the token.
See https://community.auth0.com/t/why-is-storing-tokens-in-memory-recommended/17742/4
Another good read: https://indepth.dev/posts/1382/localstorage-vs-cookies
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With