Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authentication: JWT usage vs session

Tags:

session

jwt

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.


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


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


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.

Processing
Running a session store 24/7 costs money.
You can not get away with 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.

Bandwidth
Some cloud providers charge for network activity between server instances.
This applies since it is almost certain that the API and session store are separate instances.

Clustering the session store
The cost escalates all aforementioned costs even further.


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.