Just like any other 'tokens', JSON Web Tokens (JWT) is a form of secret that's used for authentication (who you are) and authorization (what you can do). Similarly, a SessionID can also be used for authentication and authorization.
What's the Difference?
The key difference is JWTs are self-contained, while SessionIDs are not.
A JWT contains three parts: <header, payload, signature>
. I won't go into details but basically payload
contains who the user is and what s/he can do, and signature
verifies the token is valid. So when server receives a JWT, it can already retrieve all the information directly from the token, i.e., self-contained.
In contrast, a SessionID is merely a long, unique, random string. By itself there is no user information. When server receives a SessionID, it needs to do extra work to find out which user it belongs to, and then what s/he can do. This extra work often requires a database lookup.
Another way to look at it, is JWT is a driver's license (proves who a user is, and what s/he can do, drive a car), while SessionID is a credit card (simply a random number that links to a bank account, that each transaction requires a card reader to talk to bank).
Why JWT?
The internet has been doing just fine with SessionIDs for many years. Even today, the majority of websites still use SessionIDs. However, in back-end systems that need to handle extremely high volume of http requests, the need to do a database lookup for every single SessionID included in each request can be expensive as it increases latency and reduces throughput.
This is not an issue for JWT as it's all self-contained. The server can simply read the JSON payload from the JWT, without making any database lookups.
Nice! Why not JWT Everything then?
First of all, JWT requires you to properly store and distribute private / public keys that are used for signing and verifying JWTs. And key management is hard to be done right, especially in a large-scale distributed system.
Secondly, since JWTs are self-contained, there is no way to revoke a JWT token. Unlike a SessionID that you can simply delete from the database and thus remove its link to a user, JWTs are not stored in database so once it's created it's valid until expired. It's like credit cards are easy to be replaced, but driver licenses, once issued, are valid anywhere.
Last but not least, because JWTs cannot be revoked, we tend to give them shorter expiration time, which requires users to re-fetch a new JWT more often. There is an option to use refresh tokens but that adds more complexity on the client side, comparing to SessionIDs where the client only needs to store a simple string.
So should I use JWT for my next project?
Probably not. SessionIDs should work just fine :)
Top comments (17)
Symmetric signing with public & private keys is not necessary for JWT. You can use a simple secret-based signing with an HMAC algorithm.
Not hard to manage, even on distributed environments. Most cloud providers offer secret management services that can easily be attached to most or all compute service. They also offer services to abstract away public/private keypair management, if you do need them.
In my experience, JWT is way easier to implement and manage in comparison to sessions. The first is stateless, the former is stateful...
Not to mention with JWT becoming the standard on many, many new commercial/open source projects, there is an increasing dev and code base geared towards this tech. There are reasons why you don't necessarily want all your data self-contained, but they're not particularly the reasons mentioned in this article imo.
There is something iffy about using same key for verifying and issuing tokens.
Having used both JWTs and traditional session ids, I agree that JWTs are probably not the best tool for a typical project. Where I have found them very useful is when passing a user's credentials between several back-end systems that all trust the server that granted the JWT and each want to do their own authentication or authorization.
Indeed. Between backend systems we don't expose to the public sending all the data self-contained makes sense. However, you really have to wonder if sending all your data upfront to the browser is the best call, though it's a common pattern.
We migrated from a simple JWT-based solution to a SessionID-to-JWT solution, where we store a session ID on the frontend, the backend validates it and replaces it to a JWT token with short expiration time and all the other services - which are running in our trusted environment - using this JWT token to authorize the requests.
With this solution:
...but the dark side is:
In addition, we use a double session ID solution:
With this we can reduce the possibility of XSS and XSRF.
The hybrid solution and the duo-session solution are both very interesting! Thanks for sharing.
I go with JWT, because for every sessionID i want to hit database which is costly and time consuming.
Yes there is no way to revoke the jwt once it is issued.
This problem can be rectified if you can store the token in redis or any other mem-cached database. To verify the token fetch token from mem-cached database and verify it. to revoke just remove the token from redis.
SessionIDs can be blazing fast if you hookup Redis to it, mitigating the complexities of jwt blacklisting. Blacklisting tokens is the inverse of storing SessionIDs, you could end up with a huge list of blacklisted tokens.
Also, jwt payloads are much bigger then transporting SessionIDs. Use case dependent factors to keep in mind.
You can store any information you want in the Claims of a Token. Given this, it is trivial to revoke the Token. It's the exact same mechanism as revoking a Session ID.
Another big difference is that you probably want to store SessionIDs in Strict/Lax HTTP-Only cookies, making it hard to (XSS) hijack someones authenticated session, while JWTs are unbound and purposely accessible to (all) JavaScript.
JWTs are also flexible. They can be stored in a secure, samesite, httponly cookie so as to mitigate XSS. This is done when the token is used for auth; you could also split the JWT to give the js only the payload and not the signature. (But also, if this is a concern for your use case, maybe JWTs are not for you - someone else said in this thread JWTs shine in the back end when APIs call other APIs).
In general though I would agree, most of the time people just pass the token to the client and then JS has access to it until it expires. And every http request they just tack that token in the authorization header as a bearer token.
Some may consider it early optimization, but JWTโs can be easier to scale than traditional session IDโs. The latter requires a single data store for session IDโs to serve potentially many application nodes. This creates a single point of failure, which will require some failover mechanism, and in general more complexity.
This complexity is easily reduced using JWTโs, which does not require this unified data store, and is available immediately as application nodes are scaled up or down.
You mentioned "JWT requires you to properly store and distribute private / public keys"
Your Auth Server signs JWT with its private key (that needs not to be distributed).
The AuthServer Public Key (for validating the signature) can be retrieved by the URL, no need to distribute/store it.
It is quite possible to revoke a JWT. Just as a Driver's License can be revoked before it's expiration the same thing can be done to a JSON Web Token. Store a unique identifier in the JWT and provide a revocation list when checking the signature of the JWT. This provides all of the benefits of a Session ID, without having to store all of the Session Information in the database.
Only use JWT's as short-lived one-time tokens. For everything else, use session cookies. If you need to make a database lookup to validate the JWT then the purpose of them is defeated.
Don't use JWTs, sessions are your friend.
cryto.net/~joepie91/blog/2016/06/1...