I have been dealing with JWT for an auth API for my stateless app and I am really liking how JWT works but since storing JWT in local storage makes it vulnerable to XSS attacks, it kind of disappoints me. Though, I think if your app gets attacked by XSS, JWT tokens might be the last thing you would care about. On the other hand if the attacker decides to be sneaky and specifically aims to steal users' JWTs without having you noticed, it would be the worst case. I know each one of you guys have opinions about security of JWT but I am not here to discuss what's worst and what's best so far.
Instead, I will be talking about the new idea to make the best out of JWT for auth purposes, so to speak. By the way, I am not entirely sure if someone ever thought about this idea but I haven't read anything similar so far. If you have, I am sorry for the title and tell me who to give credits. Without further ado, let us begin.
First, I want you to know that we will be using long expiry time (for example 24 hours) for our tokens and will remain stateless but the problem with this is if your JWT ever gets stolen, anyone can use it, right? So, to prevent this issue we need to make the JWT unavailable for anyone other than the authentic user. We can achieve this by getting the user's IP address (and also user ID or what else you need) on login and storing it within the JWT payload. Then, to validate if the JWT is in the safe hands, we will check if the IP in the JWT payload matches with the IP which makes the request. If match, we pull the user ID from JWT payload then load user data into our global auth state. So, even if you somehow get your JWT stolen, they can't use it with another IP and that makes your JWT IP-specific. Also if you want to implement a real logout feature, you can use Redis to remain stateless while being able to revoke JWTs.
In a nut shell
- Login user with credentials
- Get the IP which makes the request
- Put the IP within the JWT payload (and also user ID or what else you need)
- Return the JWT and store it in local storage
Auto login with JWT;
- Check if JWT exists in local storage
- If exists, check if the IP which makes the request matches with the IP that is in the JWT payload
- If match, pull the user ID from JWT payload to load user data into the global auth state
- Done!