Session vs JWT Token in nodejs with large payload - session

I am working on a nodejs project and coming from a PHP background. I am pretty impressed with frontend and backend development separately and communicating with API calls.
# Issue: I need to authenticate the user and store some data of the user (which is always needed in the server), this user data which results in increased jwt payload size and jwt token will be large.
So I used JWT token mechanism, generated a token after successful login and send it to the client, then the client add that token as the header with every API call - then verifies token in server and gets the decoded payload data.
This is the process. But I have some user data that is needed always in nodejs, so the JWT payload size increases and JWT token size also large size. So client always sends with large size token everytime.
I was using sessions in php to maintain user data.
If I use sessions for authentication, it will be stateful, right?
# Doubts:
Is there any way to maintain the logged in user data in the server?
How to reduce the length of JWT token if I use large payload?
Updated:
Also if I am using sessions, it makes use of the database to store sessions So a DB call is needed.
What if I use small payload token (eg: userid) for authentication and after authentication make a DB call with userid to get details?
In both methods DB call is needed? Which method seems better?

Using sessions would introduce server state, but lets you keep user data and session data on the server. Only the session id has to be shared with the client.
You cannot reduce the length of the JWT token. Larger payload means a larger token. In theory you could use some kind of compression, but that would be a very high technical overhead and probably not worth it.
Saving sessions on the server would solve your problems.
It also gives the server complete control over the sessions. When the user logs out, the server can delete the session. When the client deletes his JWT token, you cannot be absolutely sure that the user is logged out. The token itself is still valid.
Using JWT as a sessions container is generally a bad idea. This just introduces several security issues, that you have to handle yourself. You have to make sure that 3rd party JavaScript does not read the token, just to name one issue. There are many blog posts, which explain these issues in detail (search for "Stop using JWT for sessions"), but I can only advise not to use JWT for sessions. Sessions are not a bad thing!

Related

Custom JWT token in springboot microservices

We have an application that loads information(user specific) from the external system upon successful authentication, to avoid round trips to the external system for each api call, we are planning create a custom JWT token with user specific information for the first time user authenticated, then the token is send to user in each response header using http interceptor and in the front-end we are including the custom token in every request along with authorization token. Is this correct approach? Do you have any alternative suggestions?
I have looked into other distributed caching techniques like redis but not so appealing for a small usecase. Our payload length does not exceed 4 to 5K hence inclined towards the JWT option
it is ok to include user information that allows you to handle the user authorization inside the access token. Just beware of the privacy implication and perhaps not include personal information like social security number or date-of-birth or other identifiable information.
Also, make sure the token size does not get to big. The other option is to lookup and cache the user information in the API's when it receives a new access token.
Some systems including ASP.NET Core do store the token inside the session cookie in an encrypted form, so that the end user can't see or access the stored tokens.
If you are developing a SPA application, the using the BFF pattern is one approach.

Spring Boot JWT - How to implement Refresh Token and Logout REST-API

We decided to switch from Basic-Auth to JWT because of the session-ids that were stored in the memory and which leads sometimes to over-memory consumption in shoot-down of our Spring-Boot server that serves an Android mobile app like Twitter.
But we have some questions about JWT for our mobile use-case:
How long should an access token lives ?
How long should the refresh token lives ?
How to logout a User by invalidating his access-token and refresh token ? (For the logout we already delete the tokens on the mobile app side, but what if the tokens have being stolen by somebody and are still valid ?)
I will try to answer your queries
How long should an access token live?
You can easily configure expiry time so it depends on your requirement.
In general, try to keep it short.
How long should the refresh token live?
Above goes for refresh token with a condition that refresh token generally lives longer than access token for obvious reasons.
How to logout a User by invalidating his access-token and refresh token?
This part can be a little tricky.
You cannot manually expire a token after it has been created. So, you cannot log out with JWT on the server-side, as you do with sessions.
Can implement a few options like
When a user performs logout action or compromised. Have a blacklist which stores invalid tokens until their initial expiry date. You will need to lookup DB for every request but storage should be less as you will be storing tokens that were between logout & expiry time. You can make the blacklist efficient by keeping it in memory instead of DB.
Store Client IP Address in the claims objects JWT. When validating the token you can check with this client's IP address if it is the same source or not. You can refine it based on need like use User-Agent along with Client IP.
Worst of all reset user credentials or JWT token components to generate a new one which automatically invalidates all existing ones.
Adding a few links for more in-depth detail
Invalidate JWT Token
Destroy JWT Token
I mean it looks more like you should just be using sessions.
JWTs are not a simple replacement. They have a specific function and for some reason they have become embedded as some sort of automatic go to for any auth system.
From what you have described (the lifting of a basic auth to a more secure and modern auth system) you should be using sessions.
Good ol' Cookie sessions.
I'd go in to why more but to sum up:
A) You can control the session without odd stick on "banlist" tables and extra architecture for the JWTs for users that are banned/logged out for a system that doesn't actually need these if you just used traditional cookie based sessions.
B) They are tried and tested and the browser will keep them safe! Session cookies can be made "secure" and "http-only". There are many odd places people put JWTs including the local/session storage of a browser just waiting for a naughty js injected advert to suck them up. JWTs,just like SessionIDs, should
be in an Http-Only, Secure and Same-Site strict Cookie.
So you may as well just use a session ID and get on with life without strange front end state management when the browser is quite happy and doing that securely for you when using a Session Cookie.
C) Traditional sessions are easy to implement. Harder to understand how/why they work with all the SameSite/HttpOnly/CORS/Secure parts going on...but to implement when once understood is 99x easier and require less code when there is the Spring Framework already doing that 99% for you.
I mean sure it isn't hard to write your own JWTAuthTokenAuthFilter and implement a JWTAuthenticationProvider and a JWTCreationService and a `JWTAutoRefreshFilter...and whatever else you dream of...but why bother if you just need a session. Spring does it in like 20 lines of well tested code.
To sum up:
I mean of course properly implemented JWTs are secure...it is just maybe they are not always the best fit tool for a job.
Have a read of:
Stop Using JWTs for Sessions
Of course JWTs have a use. They are for letting a 3rd party know "yes, this is someone I know" before the client hits their API end points. Or for say having one of your servers talk to another of yours...or having client's servers talk to yours or even your servers talk to another companies:
JWT Auth - Best Practices

Blocking specific user JWT tokens?

Say a user logged in multiple times from different devices, and then they decide they want to logout of device a, we have no way of deleting the JWT which was provided to that device right?
Here is what I've implemented, I'm not sure if this is how other sites do it or if it's a decent way of doing it.
User logs in
I create a redis session token, which has the userId + device name associated to it
I store this redis token as the subject of the JWT
I pass back the JWT.
Now that the user has a JWT, they can now access secured api endpoints. Lets say the user wanted to remove this session, here is what I've done.
User fetches * redis session tokens for the particular userId (of course they need a valid jwt to fetch this data)
They choose the redis session token which they want to destroy.
They send that token to a /destroy/{token} endpoint
The jwt which uses that has that token as the subject will not work anymore.
Doing it this way means on each request, I'll have to decompile the jwt, grab the redis token, and see if it still exists. I guess this isn't expensive todo at all using redis, or any other in memory DB.
Is this a solid/efficient way of doing this? Are there any better/easier ways of doing this?
While implementing JWT authentication/authorization in several apps I also had this same question and reached the same solution if not a very similar one:
In my case, I would store the JWT + UserID + DeviceName in the database, and then I would have an HTTP Request
DELETE /logout/DeviceName with a header Authorization: JWTGoesHere.
This gives me two benefits:
I can now logout a user from any device using a valid JWT (it does not need to be exactly the same JWT, it only needs to be a JWT for that user).
Makes possible the implementation of "Logout all sessions except this one".
In terms of speed, the applications we've developed receive hundreds of requests per second.
More than 90% of these requests need to be authorized, which means checking that the JWT is syntactically valid, checking existence against the database and last but not least check if it's expired.
All these checks (using Redis as the database) take less than 10ms.
Bottom line is: Benchmark it, and if it doesn't take really long then it doesn't need any optimization.
Hope it helps!

Killing "session" with SignalR, OWIN, and Web API

It has been a long road but I have SignalR working with my Web API which uses OWIN for token authentication.
I have a mechanism where if a user authenticates on terminal #1 and then later authenticates on terminal #2, I can send them a Javascript alert saying "Hey, only one session at a time. Which one do you want to log out?"
The question I have is how to kill their "session" on one of the terminals? I say "session", but since this is a REST based API there really is no session. If I could force them to re-authenticate on the terminal they choose to "log out" from that would be sufficient.
I have the SignalR connectionId of each client. Is there a way I can expire their authentication token and force a logout?
Note - The client is separate from the Web API in that they are hosted on two different servers. The client is just HTML/Javascript making calls to the Web API.
If you are using a bearer token approach, and you are not storing tokens (or token hashes) into some kind of persistent storage (e.g. a DB), then you have no way to invalidate a token.
Since OAuth is not an Authentication protocol, it do not have any kind of log out concept in it. Your only option is to remove the token from the client storage (I can imagine it is stored inside the localStorage or in a cookie).
Of course this does not really invalidate anything, and if the token is not deleted for some reason, it can still be used for authorization purposes.
Your only option, if you really need a single access token valid at a single time, is to store some information about it in a database, and check that storage every time you validate the token. You could, for instance, store the hash of the token (never store the real token for this reason, they have the same value of passwords once stored) with the username, but please note that this approach makes your authorization protocol a little less stateless than before.

OAUTH2 - Using refresh tokens to implement sliding expiration

I have a single-page web application that uses OAuth bearer tokens to authenticate users. We do not use cookies, and there is no support for sessions. It simply makes calls to an ASP.NET Web API to access protected resources with an access token. We also support refresh tokens to obtain a new access token.
How would I implement a sliding expiration? I only see three options:
Issue a new access token on every request using the refresh token. This defeats the whole purpose of refresh tokens.
Track when the last request was in the client app. Each request would see when the last one was, and if it was after a set period, log them out and bring up the login screen. If not and their access token has expired, issue a new one and let them continue. This seems kind of messy and insecure to me.
Forget refresh tokens. Store access tokens in a database with the expiration date and update it on every request. I prefer to not do a DB operation on every request.
Is there another option or do one of these actually sound acceptable?
You said there is no session support. But this is pretty much what sessions are for, and ASP.NET and IIS support them with quite a few options for how they are managed, with or without cookies and with or without a database if I recall right. If sessions are not available in your case...
There is also the option of using an encrypted token, which contains session identity and timeout info. Then the server merely needs to know the key for decrypting the token. The server decrypts the token on each request, updates the time and sends a new encrypted token back with the new response. You can send the token as a header, cookie, part of url, take your pick. But cookies and headers are designed for this use pattern and take less work in my experience.
A token that does not decrypt is treated as an unauthorized request. Timeout is handled as you normally would, e.g. using the refresh token to get a new authentication.
If you have a server farm, only the key for decryption has to be shared between the servers. No need for a session in a database or shared cache.
You can elaborate this to expire keys over time. Then servers only have to infrequently check with a directory service, shared cache, or database, message or queue to get the most recent keys. If you generate them properly and expire them faster than someone can brute force hack them, you win! (joke) Windows has apis to support you on the encryption and key management.
I did this for a project years ago with success. It is, in effect implementing sessions without server side state. And as with all session methods and all authentication methods it has vulnerabilities.
But without some special reason to the contrary, I would just use sessions for their intended purpose. If I want each browser tab to have separate authentication I would use header based session tokens. If I want browser tabs in a browser session to share authentication I would use session cookies.
Or I would use your option three, maybe with a shared cache instead of a database, depending on performance requirements and infrastructure. I suspect that IIS+ASP.Net may even do that for you, but I have been away from them too long to know.

Resources