JWT: Why Access & Refresh Token - node.js

I'm making an app in Node.js & Mongoose which needs to have some way of authentication. I first thought of simple session but then came across JWT's. I read through many articles but I'm still unsure if I should use them. My questions are:
Let's say someone steals a short lived access token that expires in 15 minutes, wouldn't the refresh token be useless, as 15 minutes is a lot of time to do something?
Where & How should I store refresh & access tokens? I guess access in client side memory and refresh tokens in database? But what if a attacker hacked the database and got the refresh token? Does he have acccess then?
Are there any other secure and good ways of authenticate with Node.js?
Thanks in advance!

Short lived token is much better than non-expiring or longer life token so absolutely no to longer life. token loss/theft is a problem that needs dual solution to lock the client to server (ip lock is a bad idea given the ip spoofing) the real solution depends on how deep you want to go like going through a third service establishing trust among both. logout is always possible all depends on as soon the server stops recognising its issued token and client app can code the logic and server rejection.
storing token to persistent storage is not hacker proof unless there is a some sort of transformation like decryption or unwrapping in the server side application layer before storage (so that the token is not as is on client side as stored in the db.).
there are quite few answers present in JWT RFC https://datatracker.ietf.org/doc/html/rfc7519 so using it is reasonably secure for majority of applications. Remember security always demands double checking and two factors in each step but there is always a judgment call that applies.

Related

Having one backend manage authentication for a webapp and react native app

Im planning on making an application that has two parts two it:
React native mobile app
Browser web-app for desktop users
I'm trying to plan out how im going to manage the backend authentication for this (Node.js, passport.js). Ideally, I can just have one backend manage it, regardless of which type of client.
Lets say im going to ONLY have google auth (for simplicity). I don't need to hit googles API's for any information (like profile, contacts, etc), I just want them to login with a google account. My understanding so far is that theres two main ways (especially since im using passport.js).
jwt based approach
session based approach
For either approach, my issue arises when it comes to the react native app. Since I'm not able to use the HttpOnly cookie, im not sure how to safely store data. e.g
In the jwt approach, if the server administers an access token and a refresh token, the react native client can just store them both in the same place e.g https://github.com/mcodex/react-native-sensitive-info. Which means the refresh token is just as susceptible as the access token, which defeats the point of a refresh token, so might as well just have the access token be long lived.
In the session based approach, react native can just store the session id some where (like react-native-sensitive-info above), and the same problem arises
My current thoughts on what should be done:
It seems like theres no way of getting around the security issue of storing information in react native, so as of now I feel like im just going to follow the JWT approach, and store the access + refresh token in react-native-sensitive-info. However, this does mean that the login endpoint is going to return the access + refresh token in the body of the request when the User-agent is mobile. When the user agent is web then we should be able to set an httponly cookie. The only thing that I can think of is if there is a malicious request that masks the user agent (is this possible?), and then can receive the access + refresh token in the body and will be able to do whatever with that.
Performance Aside
A session based storage approach seems much simpler overall. Yes it does store state on the backend, but if we did the JWT approach we would have to store peoples refresh tokens somewhere on the backend anyway (If theres ever a scenario where we need to invalidate peoples refresh tokens, e.g on logout or damage prevention).
This way, say we have a sessions table, when a user logs out, or if we want to invalidate sessions, all we have to do is delete rows from that table. In the JWT method, if we want to invalidate a refresh token, we have to have a blocklist table (which will only keep growing in size, since refresh tokens shouldn't expire, but I guess they can be dropped after a long period of time). However, if you have LOTS of users, the sessions table could get large, which could cause performance issues (but you could probably just drop sessions over a certain age)
/Aside
Questions:
Ive noticed mobile applications have NEVER asked me to relogin with OAuth. Does that mean they're constantly using their refresh token whenever the access token expires? If theres no clear way to store that in a secure way in mobile, do they just have super long lasting access tokens?
Is all of this thinking overkill? Is it fine to just store a super long-lasting access-token in react native and just use that all the time? Then when the user presses 'logout' we can drop that from local storage?
Would a third party auth system like auth0 manage all of this for me?
I'll try to share my experiencies in different kinds of app, this way things may get more clear.
Authentication Method
On most of the mobile applications (with web applications) I've worked with long term access tokens on the mobile side, most of applications don't require the user to login each time you open the app. Usually we store the token in a Secure Storage.
In some cases I've worked with a memory database (Redis) to put the user's session it's really fast and you don't need to query your main database each request (this was used for a high availability system, it may be overkill for most usecases)
Some very specific solutions may require more security, this will depend on your product (like banks, and transactions apps or apps the keep sensitive data) in these cases I would recommend you to login the user every time he closes the app or stays inactive for to long. (this kind of solution usually relies on fingerprint/faceId libs)
My personal opinion on this matter is to go with jwt, it's easy to maintain on the server side if you need to change backends and has a more defined pattern to follow, but that's my opinion and if you have high demand or some specific usecase this may change.
Storage
Talking about the storage options, there are some good suggestions on where to save data like tokens in a secure way on the react native docs,a good option I've used sometime would be:
https://github.com/emeraldsanto/react-native-encrypted-storage
but you can see more options and it advantages here:
https://reactnative.dev/docs/security#secure-storage
Third party libs
They usually helps with the basics if your projects has the budget and not a lot of customization on the authentication process, usually if it's a brand new project (on the back and front end) they work well.
Most of them will handle most of the hurdle for you like token renovation but you should mind the price scalability for these kind of approach
Wish success on your project.

Is using JWT Tokens actually a secure way to work around user sessions?

I am trying to build a registration/login system using the PERN stack (Postgres, Express, React & Node) for a client website.
I was doing some researching and came across HTTP Cookie and JWT token authorizations (many more but apparently those two are the dominant).
I noticed alot apps and tutorials that uses Node JS seems to use JWT alot, and store these in localstorage. But I'm doubtful about the security because I feel like a developer can basically go into localstorage and get the JWT token which o
Is there a better way to secure user authentications with this stack or is using localstorage the rule of thumb? If so, why is that?
Thank you for your time.
One limiting medium to the security of both session IDs and JWTs is network transmission. In this case, both are only as secure as the network itself. But most likely, your application would be using something like HTTPS or SSL, in which case any data being sent across the network would be reasonably secure.
Regarding your other edge case of someone trying to sniff at a JWT in local storage, there are a few options you may consider:
First, the nature of the JWT is that it is generally tamper-proof. A JWT contains inside of it a checksum, which is a unique hash based on the actual contents of the JWT. Let's says that some malicious user sniffed local storage, and then tried to change e.g. the claims section of the JWT. In doing so, this would also change the checksum (which that user would not be able to figure out, lacking the server key). Then, the next time the compromised JWT is sent to the server, the server would reject it, because the computed checksum would not match with the value contained in the JWT.
Second, in the event the above be deemed not secure enough, it is possible to pass around encrypted JWT. If you go with this option, both the server and client would encrypt/decrypt before sending a JWT, which adds an extra layer of protection.
Security of network transmission is just one case of whole solution in web applications.
Im currently in the research of the same topic and as you said a lot of tutorials, blogs, youtube and other sources gives an excellent examples of using JWT tokens for handling user data. Unfortunately hardly anyone go deepest in handling and processing user sessions from administration point of view - where the real problems starts.
Logging the user in and sends JTW token in response to the client is not a problem at all. The problem begin when you as administrator want to invalidate a user.
Refer to this sources:
http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/
Logout/invalidate a JWT
The session cookie with session data stored in server-side is currently the best option for web application.

JWT - What is the best way to use jsonwebtoken ? I'm lost

I’m learning to code for one year now. I mainly learned how to deal with a rest API (Node/Express on back-end and Vue on front-end).
I get to the point where I want to develop the ideas I have for app.
For this, I first wanted to develop the backend to have a authentification process that I could use as a boilerplate for other project I would have.
But now I’m completely lost with Jsonwebtoken and how to exactly use it in order to make something secure as well as user-friendly.
So far I understand that a rest API should be stateless (I.e. nothing should be store server-side and should therefore not have DB calls -as for sessions- to grant access to data).
In this respect, I’ve noted different strategies :
Short-lived JWT : (+) this is very secure since you theoretically have to log in every time you want to access the server (-) very bad user experience
Long-lived JWT : (+) user-friendly (persistent login) (-) very insecure (no way to check if JWT was stolen)
Short-lived JWT with Long-lived Refresh Token…
That’s where I get confused…
From every articles/tutorials I’ve read, the refresh token should be linked somehow with a DB (e.g. to store the refresh token key or the blacklisted token…). I’ve also seen a tutorial that partly linked the secret key (to verify the token) with the hashed password stored in the DB. This is kind of smart since previous token will automatically be considered as invalid as of the moment the user changes his password… But this once again mean a DB call…
My point is that I’m coming to the conclusion that
(1) there’s no perfect way to handle authentification process in secure and user-friendly way…
(2) DB calls cannot be avoided to have something a bit secure...
And considering that conclusion, I definitely can’t understand the use of refresh token…
If refresh tokens required DB calls, you could get to the same result with only one main token…
You could for instance store a JWT ID in the token and in the DB… If those two id match upon validation of the token, you issue a new token with a new id that overwrites the previous one… Now if you use an old one, it will never be validated… Then, since you have called the DB to validate the token (most certainly the USER table), you could check in the sametime if, for example, the user is an admin or not (no need to store it in the JWT)… Finally, you could use the « hashed password » trick described above to enhance security…
So… What am I missing ? What is the best strategy ?
I’ll be happy to have your comments on this (or a link to a very good article - I’ve a lot of these though…)
Thank you very much for your help
PS: and I’m not even talking about how to send the token to the server (with cookie but risk of CSRF attach or with header but subject to XSS attack if token is stored client-side)… In this respect I’ve seen multiple tutorial that use JWT through cookie with cerf key stored client side as well as inside the jet => both should be send.
PS2: I hope I'm clear since I'm french-speaking native :-)
So you have asked quite a few questions in this one question. It will be quite difficult for anyone to give a thoughtful answer here, but I shall try. Before that, full disclaimer, that I am the author of a new library called SuperTokens that I believe would provide you the best solution for session management. It's possible that you may have already read our blog: https://hackernoon.com/all-you-need-to-know-about-user-session-security-ee5245e6bdad. It's best if we can chat about this so that I can give you a full detailed explanation about everything you have asked (I would love to help out). Join our discord: https://discord.gg/zVcVeev
Now to answer your question(s):
You should always only use short lived JWTs
Doing a database call for authentication is not a problem, but as everything else, we try and optimise things, so doing fewer db calls, is better. If you go with JWT access tokens and Opaque Refresh tokens, then for most APIs, you do not need to do a db call. However, if you link the secret key of the JWT with the hashed password, then you would have to a db call for every API - which is OK, but I feel unnecessary since you are going to use short lived JWTs anyways (a few hours to a day max)
You mentioned token theft - this is a tricky issue, but according to RFC 6819, you can use the concept of rotating refresh token to detect theft. Of course, actually doing so can be tricky as you have to take care of many race conditions and network failure issues - see https://hackernoon.com/the-best-way-to-securely-manage-user-sessions-91f27eeef460
About why we need refresh tokens: Say you do not have a refresh token, then you would have just one token that you could treat as both, an access and a refresh token. You could still make it short lived (when it's an access token), and then after it expires, treat it as a refresh token - which also has some lifetime. The problem with this is that it's not very clean (point of expiring a token is that it is useless afterwards), and that you are exposing the refresh token over the network every single API call - reducing security. I know you can have HTTPS, but there are HTTPS MITM attacks as well - see the blog post, part 1.
In terms of storage, one neat trick could be to split the access token into two - one to store in secure, httponly cookie, and one to store in localstorage. For every API call, send both to the server (cookies will be sent automatically anyways), and then the server would combine the two and go about authenticating. This would prevent both, CSRF and XSS attacks on sessions!
Now, you could either implement this whole thing on your own, or then use our library that does all these things out of the box: https://github.com/supertokens/supertokens-node-mysql-ref-jwt.
To discuss this more, or any other questions you have, join our discord server.
PS: I know I used this for advertising my lib, but I hope I did answer your question. It is genuinely difficult to give a good explanation to your questions without having a conversation.

Where jsonwebtoken stored in server nodejs . How to expire JWT once user gets logout

I am storing Tokens on Session/Local storage on the client side.The problem I am facing is once a user copies that token and uses it for other logged-in session services it works but it should return invalid token on JWT.varify.
Is there any way to Blacklist/Delete/Expire currently used token once a user has logged out?
There a a few ways to set up a blacklist for that purpose:
1) (Blacklist users in the database) Add a database column isTokenExpired for users and set it to false on a successful login, and true when you want to expire the token (for example when the user changes their password, logs out, or enough time has expired).
The above method will achieve your purpose, but I feel it is an insult to programming. I assume you are using JWT so that the user doesn't have to log in every time, and that you have only 1 server which is doing the authentication and all other server functions. Although JWT was not designed for "sessions", using JWT for this purpose can take load off the database. But if you are then setting and checking another database flag on every user action, you are adding that load again, and you still have all the load associated with the JWT etc, so you might as well just re-auth on every user action.
2) (Blacklist a user/the token in server RAM) When I researched this problem for myself (how to invalidate individual tokens), I found some solutions where the server maintains either a whitelist or blacklist in RAM, so without adding database or file load. This may be a somewhat better solution, but I can't remember the names of any of the libraries that facilitate this. Maybe someone else can mention some of them.
3) Set token to a very short expiry time (For example 60 seconds or 5 minutes) and set up the client to automatically request a new token every (~55 seconds or ~4 minutes 50 seconds). The server would then check and validate the token in the same way I assume you are doing it now, without accessing the database, and would then generate a new token with the same values for all the other fields, but with a new "expiry time" value, and send that token back to the client where it would replace its JWT with this new JWT, and re-start its 5-minute timer. This is a good balance between the other choices, and maintains some of the benefits of using the JWT, but does add some small cost. I think this is a pretty good solution for many applications, but it definitely depends on the specific application, but it is somewhat hacky and definitely not "the right way" to do it.
4) Use JWT + Sessions This is "the right way" to do it. After all my research a long time ago, I realized that JWT's are not designed to be used for maintaining sessions: JWT is only a secure way of representing a claim. Imagine having a large system with tens of millions of users, and you require many servers around the world. You may have 3 authentication servers (in USA, Australia, UK). The user will then send its username and password to an authentication server, where the details will be checked in the database, and if valid it will be sent a JWT. You may then also have 10+ regular servers which handle your API. The client will then make each request to an API server with its JWT. The API server will have a copy of the secret key that was used by the authentication server to generate the JWT, and will validate your claim. Your claim is "I am authenticated". This API server will then generate a session and the client will be "logged in". The JWT may be set to expire after 5 minutes. If the user does not log in within this 5 minutes, they will not be able to log in. If they do, they will be logged in until the API server kicks them out. Whenever something happens that would cause you to want to kick the user, the API server can close the session. Even for a single-server application this is still the right way to do it. JWT are not for sessions, and you (exactly as I did) are starting to notice these seemingly unsolvable problems because you are using JWT for sessions.
Anyway, I recommend 3 or 4, both of these options have a net-positive value for many applications.
1 and 2 seem to make more problems than the benefits they provide.
But of course, it always depends on the application. If you're just making some website on fiverr for $5 then just do whatever, you know what I mean?
If there's a better solution I'd be interested to know too! Just remember that JWT represents a claim, and consider exactly what claim your client is representing.
Answering your first question (where is JWT stored in server Node.js)
JWT tokens are not stored on server side. It is a signature(by a secret key, RFC 7519 ) based authentication system.
So server just verifies the token and if it's verified then it gives access to the user and hence any user having your token can act as you.
For example - you can copy cookies/storage of a logged in facebook user and then go to another browser and set those cookies/storage. You will be logged in as that user for a few.
FYI #safebookverified 3rd way is mostly used. thanks.

See any security risks with this approach?

I'm working on a RESTful(ish) API that has the following authentication style:
A client calls an "authenticate" API method and passes a username and password over HTTPS POST. This method returns basic account information and a "client token", which is stored on the user account in the database.
All further API calls (all over HTTPS POST) require a client token. If the system can't find the requester by client token, the call is rejected.
My open questions are:
1) Does anyone see a major security problem with this?
2) Is there any good reason why I should have client tokens expire over time or change? Right now I assign a random one to every user. If the user does a logout or forgot password, I generate a new one.
I'd love to know everyone's thoughts on this approach. I'm not going for innovation, I'm just making I'm aware of the risks on this approach.
What you've described is functionally equivalent to a session cookie, only reimplemented in your application, and therefore subject to a number of pitfalls that have likely already been dealt with by most web frameworks.
Ensure your tokens have enough bits of entropy. If the tokens are simple 32-bit integers, wild guesses might be enough to hit on one in use by someone else.
If you're generating these tokens randomly, ensure you use a cryptographically-strong source of random numbers, or the next token might be guessable based on previous tokens.
If these POST requests are coming from scripts and such embedded in web pages, passing the token around as an explicit parameter instead of as a cookie declared secure and httponly makes token-stealing by cross-site scripts much easier.

Resources