295

What is the advantage of using JWTs over sessions in situations like authentication?

Is it used as a standalone approach or is it used in the session?

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
Pourya8366
  • 3,424
  • 4
  • 21
  • 28

7 Answers7

475

JWT doesn't have a benefit over using "sessions" per se. JWTs provide a means of maintaining session state on the client instead of doing it on the server.

What people often mean when asking this is "What are the benefits of using JWTs over using Server-side sessions".

With server-side sessions, you will either have to store the session identifier in a database, or else keep it in memory and make sure that the client always hits the same server. Both of these have drawbacks. In the case of the database (or other centralised storage), this becomes a bottleneck and a thing to maintain - essentially an extra query to be done with every request.

With an in-memory solution, you limit your horizontal scaling, and sessions will be affected by network issues (clients roaming between Wifi and mobile data, servers rebooting, etc).

Moving the session to the client means that you remove the dependency on a server-side session, but it imposes its own set of challenges.

  • Storing the token securely.
  • Transporting it securely.
  • JWT sessions can sometimes be hard to invalidate.
  • Trusting the client's claim.

These issues are shared by JWTs and other client-side session mechanisms alike.

JWT, in particular, addresses the last of these. It may help to understand what a JWT is:

It is a bit of information. For user sessions, you could include the username and the time when the token expires. But it could conceivably be anything, even the session ID or the user's entire profile (please don't do that though). It has got a secure signature that prevents malicious parties from generating fake tokens (you need access to the server's private key to sign them and you can verify that they were not modified after they were signed). You send them with every request, just like a cookie or Authorization Header would be sent. In fact, they are commonly sent in the HTTP Authorization header but using a cookie is fine too.

The token is signed and so the server can verify its origin. We will assume that the server trusts its own ability to sign securely (you should use a standard library: don't try to do it yourself, and secure the server properly).

On the issue with securely transporting the token, the answer is commonly to send it via an encrypted channel, usually httpS.

Regarding securely storing the token in the client, you need to ensure that the bad guys can't get to it. This (mostly) means preventing JS from bad web sites from reading the token to send it back to them. This is mitigated using the same strategies used to mitigate other kinds of XSS attacks.

If you have a need to invalidate JWTs, there are definitely ways this can be achieved. Storing a per-user epoch for only users who have requested to have their "other sessions terminated" is a very efficient method that will probably be good enough. If an application needs per-session invalidation, then a session ID can be maintained in the same way and the "killed tokens" table can still be maintained to be much smaller than the full user table (you only need to retain records newer than the longest allowed token lifetime). So the ability to invalidate the token partially negates the benefit of client-side sessions in that you would have to maintain this session killed state. This will more than likely be a much smaller table than the original session state table, so the lookups are still more efficient though.

One other benefit of using JWT tokens is that it is reasonably easy to implement using libraries available in probably every language you can expect to have it. It is also completely divorced from your initial user authentication scheme - if you move to a fingerprint-based system, you do not need to make any changes to the session management scheme.

A more subtle benefit: Because the JWT can carry "information" and this can be accessed by the client, you can now start doing some smart things. For example, remind the user that their session will be expiring a few days before they are logged out, giving them the option to re-authenticate, based on the expiry date in the token. Whatever you can imagine.

So in short: JWTs answers some of the questions and shortcomings of other session techniques.

  1. "Cheaper" authentication because you can eliminate a DB round trip (or at least have a much smaller table to query!), which in turns enable horizontal scalability.

  2. Tamper-proof client-side claims.

While JWTs does not answer the other issues like secure storage or transport, it does not introduce any new security issues.

A lot of negativity exists around JWTs, but if you implement the same security that you would for other types of authentication, you will be fine.

One final note: It is also not Cookies vs Tokens. Cookies is a mechanism for storing and transporting bits of information and can be used to store and transport JWT tokens too.

Pang
  • 9,564
  • 146
  • 81
  • 122
The Tahaan
  • 6,915
  • 4
  • 34
  • 54
  • 10
    It's worth noting that server-side sessions don't have to store any information on the server either. The server can use the client as the store in the same way as the JWT does. The real difference is in 1) avoiding browser security rules by passing the value as request header other than a cookie header, and 2) having a standardized format with JWT. – Xeoncross Nov 16 '18 at 19:06
  • 5
    Would you say it's safe to store a jwt in local storage? If not, where is a safe place to save it so that the user stays logged in? – Jessica Sep 27 '19 at 22:02
  • 1
    In your comment you do not talk about cache based solution + session token. It sounds to me "better" than JWT + "killed tokens" table, because with this "killed tokens" table, you need anyway a DB access, that you will have also with sessions + cache (that is small as well). And persisting JWT is more painfull to implement than persisting sessions, because you need to play with a refresh_token (so two tokens to maintain)... Any comment would be really appreciated... especially if you have some number to show how JWT + kill_table is more efficient than sessions + cache ;-) – tobiasBora Jan 21 '20 at 23:21
  • 5
    The difference is that a sessions table holds an entry for every single session. Could be millions of users. A killed tokens table only needs one row for a token if it was killed, and that can be reduced even further by removing the row if that token is expired. So the killed token lookup is across a much smaller table. In real world examples the performance difference is several orders of magnitude for large userbases. – The Tahaan Jan 24 '20 at 08:50
  • 10
    @TheTahaan localStorage is not recommended to store JWTs. The link that you shared also mentions that. This [blog](https://www.rdegges.com/2018/please-stop-using-local-storage/) has good explanation as to why JWT should not be stored in localStorage. – Harke Mar 05 '20 at 23:08
  • 3
    If your backend server maintains secret for each logged-in user to generate JWT (e.g. stored in cache server) , the alternative to invalidate a JWT is to [delete the secret stored in the server](https://stackoverflow.com/questions/30523238/best-practices-for-server-side-handling-of-jwt-tokens#comment80179289_30523238) (even the tokens haven't expired yet) , so all tokens generated with the deleted secret are automatically invalid, when user login next time, the server generates another new JWT for the user. By doing so it is no longer necessary to store entire JWT. on server side – Ham Feb 05 '21 at 08:54
  • 1
    [This article](https://medium.com/redteam/stealing-jwts-in-localstorage-via-xss-6048d91378a0) also describes how to perform XSS attack through LocalStorage in your browser, for those who are confused about where to store sensitive data like JWT. – Ham Feb 05 '21 at 09:01
  • Do not save it on lacal storage – mercury Mar 21 '21 at 06:26
  • 1
    @Harke If you site is vulnerable to XSS, then storing tokens in cookies also won't help you, since attacker can exploit you by session riding attack [Check this blog](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html). We can safely store tokens in local storage. – CyberSrikanth Aug 01 '21 at 14:40
  • 1
    @Xeoncross For non-JWT session id, it needs to be stored in server memory or a separate store so that the authetication can be validated on subsequent requests. Active JWTs can be kept entirely on the client side. Only invalidated JWTs need to be on the server side. How will storing non-JWTs on client work? They are not signed. – piepi Feb 15 '23 at 19:01
  • 1
    @piepi signing of payloads has been around a lot longer than JWT's specifically. They are just one of a myriad of ways you can sign (optionally encrypt) a byte blob. Before JWT's, I would just encrypt the cookie payload, base64 encode it, then send it back to the client to store in a cookie. No server-side storage required in exchange for not being able to clear the data. JWT's are over-used these days as session storage, most applications need server-side storage of the actual session data for things like reporting what devices are logged in or fitting larger session payloads. – Xeoncross Feb 18 '23 at 22:34
  • 1
    Isn't storing singed session is kind of simultaing the JWT behaviour? I known that JWTs contain more information than just auth, but pricipally if you are signing cookies then you are doing JWT. And I do agreee that in such a scenario you don't need signed tokens stored in the server. – piepi Feb 23 '23 at 14:08
  • @Ham Yes this is what I have done before, it seems like the most obvious solution to invalidate JWTs right? Although yes it wouldn't somewhat negate the speed feature of a JWT because you're storing a secret key, but it seems to be effective. Basically ever time the user logs in, a store a secret key for that user, which is fetched and checked against every time the user sends a request? – Amon Jul 06 '23 at 20:42
  • @piepi what do you think of this above approach? I guess it'd just be the same as signing a session and storing it right? – Amon Jul 06 '23 at 20:44
65

The short answer is: None.

A longer version is:

I implemented JWTs for session management after reading this recommendation in the GraphQL docs:

If you aren't familiar with any of these authentication mechanisms, we recommend using express-jwt because it's simple without sacrificing any future flexibility.

Implementation was indeed simple as it only added a little bit of complexity. After a while however, I (like you) started wondering what the benefits were. It turns out there are very few (or possibly none) for JWT as far as session management goes, as this blog post explains in detail:

Stop using JWT for sessions

Carl von Blixen
  • 810
  • 6
  • 10
  • 2
    What if you need to to work cross domain? AFAIK cookies cannot be used in that case. – The Fool Aug 26 '20 at 22:28
  • 2
    In this case you are sacrificing security against XSS provided by the browser. Cross site session should be avoided if at all possible IMHO. Mind that `abc.example.com` and `example.com` are normally considered by browsers as being the same site. – Guill Dec 21 '20 at 18:34
  • If XSS did happen even httpOnly cookies will not save user from attacks, at this point not much will help. On the other hand cookies are susceptible to CSRF and JWT in local storage is not. – Gherman Jun 30 '22 at 23:32
  • What if you store the secret key that is used to sign each JWT in the DB? Then delete it when the user logs out and create a new one when they log in? I recognize this defeats some of the purpose of a JWT but is that effective? – Amon Jul 06 '23 at 21:11
  • That graphql doc uses express-graphql which is a deprecated package. Def investigate more before following that path. https://www.npmjs.com/package/express-graphql – Guzumba Aug 31 '23 at 17:53
16

I had a similar question choosing between JWT and token + cache for user authentication.

After reading these articles, it's clear to me the benefits JWT promises do not outpace the problems it brings. So token + cache(Redis/Memcached) is the way to go for me.

Auth Headers vs JWT vs Sessions — How to Choose the Right Auth Technique for APIs

Authentication Techniques for APIs

Stop using jwt for sessions

h--n
  • 5,903
  • 4
  • 31
  • 32
10

My two cents, which on the way add some contrast to joepie91's famous blog post.

Considering that today's (and tomorrow's) applications are (mostly) cloud native
There's an economic benefit to Stateless JWT Authentication, which scales as the application scales:
Cloud applications incur cost with every passing second.
This cost is reduced when users no longer have to authenticate "against" a session store. Detailed below are some factors which add to the cost of an application when not using JWT:

Database Server
Running a session store 24/7 costs money.
You can not get away with local storage / memory based solutions in the world of K8S, as pods are ephemeral.
Sticky sessions will not fare well for the exact same reason.

Storage
Storing data costs money. storing data in a SSD costs even more.
Session related operations need to be resolved quickly, so an optical drive is not an option.

I/O
Some cloud providers charge money for Disc related I/O.

Download
Circa 2022, it is safe to assume that the API and session store are separate server instances.
Some cloud providers charge for downloading information from one instance to another.

Scaling the session store
This affects all aforementioned factors.

Eyal Perry
  • 2,255
  • 18
  • 26
  • 6
    "You can not get away with memory based solutions in the world of K8S, as pods are ephemeral" Not sure what you mean by this. Redis definitely works in a K8S environment, and a redis pod failing frequently enough to affect your users seems very unlikely. – crackpotHouseplant Apr 05 '20 at 06:28
  • @quietContest I personally prefer not to deal with likelihood when building software. BTW, solution stability aside, an attack can cause software to fail and pods to restart- which would result in session loss. I'd opt for a JWT based solution for that reason. – Eyal Perry Apr 09 '20 at 18:20
  • 6
    "I personally prefer not to deal with likelihood when building software". I think we would all prefer that, which is why we shouldn't architect systems that rely on in-memory data stores never failing, because the likelihood of that seems reasonably high. As to your other point, if you have an attacker that is able to consistently shut off your redis instance, the solution to that probably doesn't need to involve using JWTs. – crackpotHouseplant Apr 11 '20 at 04:47
  • @quietContest consistently or a once in a lifetime event are the same to me in this aspect. i.e. a well placed DDoS attack can cause the server to "log users out". This doesn't do well for the software's reliability reputation. I think redis is overkill for session management anyway. It costs and needs to be scaled, whereas (safely) storing a JWT in a cookie does not. – Eyal Perry Apr 11 '20 at 09:24
  • 1
    @quietContest thanks for your input, love the discussion! – Eyal Perry Apr 11 '20 at 09:25
1

Yet another slightly different perspective that may be useful if you are on AWS.

We had implemented PHP5.x session storage on AWS ElastiCache to centralise session storage across multiple servers.

It worked perfected until we moved to PHP7. It was difficult to configure for PHP7 and we were plagued with intermittent issues where it seemed that the session "failed/mismatched/got a bit confused" for a particular user and then they could not log in on that device until the old session expired.

We moved to using DynamoDb to store the session and no more issues. It is marginally slower but only noticeable at login (session storage) stage.

While this was going on, we implemented AWS cognito to replace our authentication and started to use the API-Gateway to deliver content via lambda python functions.

We use the PHP SDK to authenticate with Cognito and then we store the JWT in a cookie but still also use the PHP session to keep our legacy code working.

Now we have two stacks and the best of both worlds: PHP7 does it's bit and gets the main content to the user (very quickly). Then JS takes over and provides additional content using the JWT.

What I think is great about JWT is the fact that it can be passed around between these two stacks and used to authenticate the user in both cases.

Now we are wondering if it is worthwhile taking the plunge and switching over to the new JWT system entirely?

In PHP, we still use our legacy session but we also pass the token to cognito to authenticate it. It's a bit of extra security that is probably not necessary but it gives a warm cozy feeling. Then again, there are costs and maintenance with dynamoDb that could be saved.

Enigma Plus
  • 1,519
  • 22
  • 33
  • Doesn't sound beautiful, but supposedly pragmatic. But from what I can see, particularly in your case JWT-tokens are less secure (owing to possibility of XSS attachks), than server-side sessions. Because the latter can be stored in secure httponly samesite=lax or strict cookies. – x-yuri Feb 25 '21 at 02:37
  • It appears that if you've got a XSS vulnerability, SameSite [won't help](https://security.stackexchange.com/a/121986/60425) against CSRF. As such server-side sessions might be vulnerable to CSRF. And so seemingly client-side sessions are not less secure. – x-yuri Feb 25 '21 at 04:00
  • I think I follow what you are saying @x-yuri but I also think we are safe because the PHP stack does not take any "instruction" from the JWT cookie. It just logs in via the session and saves the JWT for the other stack to use. Or am I missing something? – Enigma Plus Feb 25 '21 at 17:57
  • Not so long ago I thought that JWT tokens (or rather client-side sessions) are less secure than the server-side ones. Because JWT's are vulnerable to XSS attacks. With server-side sessions if you use a httponly cookie, that possibility is eliminated. But server-side sessions might be vulnerable to CSRF. Unless you use a cookie with SameSite=Lax or Strict. Or so I thought. But it appears if you have an XSS vulnerability, that makes you [vulnerable to CSRF](https://security.stackexchange.com/a/121986/60425) as well. – x-yuri Feb 25 '21 at 20:16
  • ...As such I now think there's no clear winner. On one hand I can say, why not store the token in local storage? Storing it in a cookie you might be vulnerable to CSRF. Unless you're sure you're not vulnerable to XSS and the cookie has the SameSite attribute. On the other hand, you must take measures to prevent XSS anyway. As such storing it in local storage makes more sense. Since you don't have to even consider CSRF. A [good answer](https://stackoverflow.com/a/40376819/52499) on this matter. – x-yuri Feb 25 '21 at 20:17
  • ...P.S. It's not about taking instructions from a cookie, it's about "how do you know if a request with a cookie is triggered by a user, not by an attacker?" E.g. what if an attacker embeds a piece of code on your site that does a POST request on behalf of a user to `https://yourdomain.com/api/delete/everything`. That would be XSS+CSRF. – x-yuri Feb 25 '21 at 20:18
1

In session authentication (or stateful authentication) you can store more data than token. But you have to store the session object somewhere and this makes the authentication centralized. Also, you need to have extra memory to store the sessions and this will give extra work to manage this memory. If your application grows, now you have to implement different designs based on your needs, implementing a session cache service, and storing the session on web application or database.

In Jwt or in general Stateless authentication, you do not store anything. You send the token with the request header. This makes it decentralized authentication. The drawback of this authentication is token revocation. Each token has an expiry time and if your token is stolen, it will be valid till it expires. You have to implement logic to minimize the risk.

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
  • 1
    You can store as much data as you want in JWT token... A cookie with a DB "classic" session, or a bearer JWT token can both be stolen, and are both vulnerable to the same XSS/CSRF concerns... Both types, if stolen will remain valid until they expire... JWT bearer tokens have the issue that you can't invalidate them, as the server won't be able to tell if it's just an old version of a valid token or not. As such it's impossible to handle a logout system, without also storing data about the user internally, which means that the stateless session has become stateful. – Jack_Hu Oct 26 '22 at 07:54
0

I was an apologet of jwt since it seems to be more scalable and stateless solution.

And it was a hot trend some days ago.

But now I see these discussions again: what is better: jwt or classical sessioning.

And now there are tons of articles that convinces that sessioning is better because 'someone can steal the jwt which is probably will be stored somewhere in browser memory that is accessible by js and they'll use xss attack then'.

People now think that sessioning is better because with HTTPOnly and Secure headers, the token will be hidden from the attacker.

In modern js-driven world sound like an old good idea - at least to lower the surface of attack.

I'm thinking, maybe for browser - server communication, we just need to add some kind of ip-based information at the stage of jwt generation?

then servers can check that this jwt belongs to exactly this client?

  • 1
    Unfortunately it's not an universal solution as in most cases it's undesirable to log user out when he changes networks (wifi -> mobile etc) or enables VPN. – Zmey Jul 31 '23 at 03:11