114 comments

[ 1.8 ms ] story [ 192 ms ] thread
> JSON Web Tokens (JWT) are Dangerous for User Sessions—Here’s a Solution

Actual title on the website.

Edit: To watch clickbait work in real time, check OP's submit history.

@dang might want to check into that, OP seems to have a history of forcing submissions through.
They posted this twice for some reason
The first post had the original title and it had 5 votes. Now this clickbait title and it blew up.
OK, but what's the real alternative here? I'm sick of these JWT hate articles on HN all the time with no universal solution.

Why not just use cookies and be done with it? This looks like an advertisement for Redis Enterprise.

Definitely use cookies. Opaque tokens. Works great.

All the good versions involve cookies somewhere - they’re the most resistant to all the various forms of attackers on the web.

Many use cookies in order to stamp short lived tokens, though.

Refresh tokens are the real alternative, IMO.

I kinda agree it looks like an ad for redis, since it doesn't even considers alternatives.

Agreed. Long(er) lived refresh tokens, and then having signed access tokens such as JWTs so that the API server doesn't have to hit the database on every request.
There's "JWT hate" articles on HN because people keep implementing JWT auth without understanding it - they want an easy, cheap way to do auth when talking to different services, but it can be a huge security flaw since you can't do revocation. There's a lot of ways to configure JWT, so it's very easy to shoot yourself in the foot.

JWT for short-lived tokens is fine - it can work well for signing requests between microservices. If you want to give them to end users, use refresh tokens.

As with anything, the alternative depends on your needs and use case. There is no universal solution.

You could have short-lived JWT tokens so it wouldn’t matter because they only last 5-10 minutes or less. They could be refreshed or if using OAuth, simply redirect an unauthenticated user and they’ll be reissued based on the cookies stored by the OAuth provider… assuming the redirect doesn’t break your app of course.

Alternatives? First, you could live with the possibility that tokens are valid for some period of time after logout because it usually doesn’t matter - generally you delete the cookie and the user is logged out, even if technically they could restore the cookie later. They won’t, unless you’re under attack.

Other alternatives: You could use Redis for session data as pointed out with the random key in a cookie and delete the session when done to invalidate the cookie.

You could also use Redis to keep token IDs that you want to invalidate or block. You could use something like Open Policy Agent to distribute a list of invalidated tokens to each server.

Finally, you could send your JWTs to a centralized authentication service — single point of failure, yes, but you could record invalidated tokens to memory and responses are very quick and easy to audit. With careful planning you could reduce the risks in having a single central service to validate issued tokens.

I’m sure there are other ways to mitigate this risk. The general reason why folks don’t recommend JWTs is because it’s too easy to make mistakes in the validation logic. But the same is true (with different possible mistakes) when you roll your own session cookies. At a certain point I think you have to either assume competence or you have to suggest that developers use identity proxies in the cloud, or frameworks others have written, and never implement this themselves.

But yes, this is a rather transparent advertisement for Redis as a KV session store.

Aren’t JWT tokens only supposed to be good for 10-15 minutes? I know using flask-jwt you have to go out of your way to make them last longer than that and it isn’t recommended.
I know some folks who thought they could use JWTs from a traditional LDAP identity vendor (open source Active Directory so you can manage computer login credentials centrally, issue Kerberos tokens, etc.) but they managed to misconfigure their JWTs by following the defaults from the vendor so the JWTs issued were valid forever. When I tried to explain that they couldn’t be revoked without key rotation, I got some very blank looks. I’m not even sure the tokens had an iat (issued at timestamp) though if they did you could use that to at least ignore tokens older than a certain date. They assumed because they deleted the cookie at logout, it wouldn’t matter that the session could be re-used forever. Then they implemented session limits by setting a cookie expiry time. /face-palm

Issuing your own JWTs also means you have to keep the secret or certificate used to sign them secure or if it leaks anyone could impersonate anyone else. This is especially problematic if admin or role assignment is embedded in the JWT.

Yes but a lot of times people don't do that properly, some frameworks have incorrect defaults or people don't want to deal with writing the logic to handle refreshing tokens after that 10-15 minute window etc etc.

They are insecure but it's not a problem if you follow best practices like those, the difficulty is a lot of people don't because they don't really understand what it is they're doing or potentially causing by making the changes that let them be lazy or do things the easy way.

You could probably change the title to articles like this from "JWT Tokens are NOT safe" to "JWT Tokens are NOT safe when you ignore all security practices and take the easy way out" but that doesn't make for a flashy title.

Expiry is just one of the fields you can set. Also if you’re curious about what’s inside a JWT, the next time you see one from an OAuth cookie perhaps, copy and paste it into a tool like https://JWT.ms run by Microsoft and it can show you the details. Commonly you want to load a JWKS (with multiple keys possible for easy revocation) to validate the signature, and check the iss (issuer of the JWT), aud (your app registration or audience of the token) and expiry date of the token. Oh and don’t forget to hard-code or reference the JWKS validation method so you don’t accidentally allow “none”. JWTs are not without their complexity, but the same could be said about maintaining secure session cookies and implementing 2FA yourself perhaps.
I do want to follow up - there are two parts of JWT issuing that are problems and why I prefer using JWTs only issued by OAuth providers (third-parties that know what they’re doing) - 1. JWT tokens you issue yourself might not have expiry dates in them - I am assuming that your JWT tokens are valid for a reasonable duration such as 2 hours or less, otherwise you should probably use a different technology - and 2. Like SSL, you will have to rotate the credentials used to sign the JWT, otherwise anyone could pretend to be anyone else, at any time.

So it’s not that JWTs don’t have risks but the risks are overstated. It would be like saying never use Redis because by default it doesn’t have secure SSL or a proper password system and thus anyone could access it. Security isn’t easy, but it can be done, and often looks like a series of mitigations, monitoring tools and trade offs… such as how long sessions last, or planning for features like key rotation or session revocation in advance…

> The general reason why folks don’t recommend JWTs is because it’s too easy to make mistakes in the validation logic.

That isn't why I don't recommend JWTs, and it's not why this article is not recommending JWTs.

> Logout doesn’t really log you out!

> Blocking users doesn’t immediately block them.

> Could have stale data

^ JWTs fundamentally are not compatible with server-side authentication revocation.

Your typical developer is like, "Well, I don't care much, I'll use JWTs anyway", but then some poor soul has to deal with the ticket titled "Blocked user still able to access service", or "User still able to access service after logout", or "session never expires!" (oo... look, you configured it incorrectly).

I've been on the other side of having to deal with screwed up JWT implementations other folk have built.

It's not fun.

...and yes yes, there are work arounds, you can have rotating short lived tokens and long lived refresh tokens and a database of revoked tokens...but you've just reimplemented server side session authentication yourself, and it's probably wrong.

> I think you have to either assume competence...

I think that's terrible advice. You should never assume developers are competent to implement authentication. It's a Hard Problem, like, writing a database, and frankly, only specialists are competent to do this correctly. Anyone can writing some kind of data store, but it's a bit harder having it ACID and concurrently multiuser.

> or you have to suggest that developers use identity proxies...

...but yes, this is probably the only useful piece of advice to give to people: If you use a 3rd party authentication provider, you can delegate responsibility for doing the hard work of making sure they have a solution for the hard things; at which point, you don't really care if its JWT or cookies, or whatever.

I still wouldn't recommend people use JWTs.

"database of revoked tokens...but you've just reimplemented server side session authentication"

There's one important difference between session authentication and JWT+revocation: the revocation list can be distributed asynchronously, whereas a session list needs at least read-after-write consistency.

It's a minor point for most use cases, but occasionally can be very significant.

That said, the primary problem with distributed authentication and distributed revocation is either it slows down your processing as you wait for confirmation of new entries on the list, or you have a risk that actions might be allowed when another part of the system has tried to block them. We generally think of distributing authorization data asynchronously in the positive: adding a new user permission, rolling the list out to every authz server. But when you’re trying to block access immediately, it can be difficult.

Not to be negative—if your JWT expires after 15 minutes and your list updates every 10 seconds, you’ve improved your reaction time quite a bit for revocations.

Also, you can have an eventually consistent session store if you don’t mind that sometimes users might see a 403 they shouldn’t, if your app can cover it up such as by requesting content from a different region or waiting a bit. Similar to the idea of using a load balancer to pin sessions to particular servers.

(comment deleted)
> You could have short-lived JWT tokens so it wouldn’t matter because they only last 5-10 minutes or less.

The author argues that you can't revoke a JWT - suggesting that 30min is the usual default. To their point, if 30min is too long, then 10min is probably still too long.

However, implying that 30min is too long for a token to remain stale suggests that you aren't really working at the scale that JWT was destined to address (Facebook, Twitter, etc.). If you really are the unfortunate soul trying to solve per-request authz, specifically at the scale that JWT was designed for, then I feel deeply sorry for you. For the 99%, i.e. the rest of us, 30min is just fine.

> You could use Redis for session data as pointed out with the random key in a cookie and delete the session when done to invalidate the cookie.

I'm not picking at your argument, honestly, I'm just pointing out the absurdity of authz without JWT (or similar) at scale. Redis is eventually consistent: what happens during a network partition?

Saying that the JWT expiry is a vulnerability is tilting at windmills.

> The general reason why folks don’t recommend JWTs is because it’s too easy to make mistakes in the validation logic.

Bravo, that's the real problem with JWT right there: it's too easy to misuse - especially when convenience or demanding customers enter the picture. It also has brain-dead specification opportunities like signature-free tokens.

Could you expand on why 30min session validity after explicit logout is okay? I don’t mean to sound accusatory; I would like to understand your reasoning.
If the JWT is saved as a cookie, you can delete the cookie and the user’s browser is safely logged out. The threat model is that a user or third-party could intercept and reuse the JWT after logout. Sure. But then a malicious actor could re-use a JWT before you logout from the app also, which is a much larger risk. Malicious browser extensions for example could hide that they’re making clicks or taking actions in tabs just as they hide ads from you. Don’t get me wrong, extensions are sandboxed, but… any sandbox can be broken. In the end, whether or not your JWT was revoked at logout doesn’t affect the risk of malicious activity all that much as long as cookies behave the way they should. And as long as your JWT has appropriate expiry timestamps.
If you have an attacker that can obtain the token within 30min, it is reasonable to assume they might obtain the token immediately, and use it immediately too.

JWT expiration protects against situations where the token is stored (or made to be stored) somewhere improper and later used, not being pilfered during proper use.

As the article argues, it doesn't even protect against a malicious user using stale credentials to wreak havoc, such as a disgruntled employee that had access to the precious admin panel being fired.

I absolutely agree. That’s why I said:

> you could live with the possibility that tokens are valid for some period of time after logout because it usually doesn’t matter - generally you delete the cookie and the user is logged out, even if technically they could restore the cookie later. They won’t, unless you’re under attack.

I suppose if you really want to avoid the hop to session storage as much as possible, you could have your applications servers continuously refresh a lightweight Bloom filter or other probabilistic data structure storing maybe-invalidated sessions in memory, and in case of a potential hit, confirm it with the session store. Then your logout endpoint just needs to wait until all servers receive the data to tell you you're logged out (I suppose CAP applies here). If this sounds like overkill to anyone reading this, then it probably is!
(comment deleted)
No solution is universal. That said: use sessions. They’ve worked fine for decades and there’s a 99% chance they work fine for your app.
It is funny that this is the way most web auth systems worked back before the JWT brand was invented. I made one that had a prefix extension bug, but you didn’t see the marketing drumbeat against it until it got a name and you could paint a target on its back.

(E.g. branding something is often a transition from people using language as a club against hunger, wild animals and the unknown to using it as a club against the other man.)

It is not unusual for systems like this to have some details such as verifying the cookie against the db if somebody is doing a critical operation and not being too worried about a five minute window for people reading articles and such.

High volume attacks need their own countermeasures.

There’s no reason to put all the user info in redis and this article makes no valid argument for it. Give the token a unique ID and store that ID in redis (or some other fast store). Validate the token by checking its sig and verifying that its ID is in redis. Store all the signed metadata you want on the client, revoke it by removing its ID from redis. Addresses all cases where the token is stale. So basically redis becomes your token whitelist, not your store of user metadata. Problem solved.

Signed blobs of data such as certificates and web tokens are a very powerful massively distributed cache where the entity that benefits from the data being cached is also the entity responsible for persisting it. This is a wonderful optimization whose sole drawback is that you need an external way to decide when that entry is invalid. Solve that problem, don’t abandon the entire concept of the distributed cache.

Simple session tokens are fine, always have been.
It is an ad. OP's recent post history are all Redis ads.
TLS client certs?
> Security should be binary. Either technology is secure or it’s not.

From my experience, that's not the case for almost anything. In fact, I'd consider it a dangerous position.

Ya, I hate to be pedantic too, but security it almost entirely NOT binary. It should be, but it's not.
I respectfully disagree with both of you. Security should be binary, within a given set of requirements / implementation parameters and the intended threat model. Security must be binary within the space of “are you authenticated or not” (within the massive context specific web of trust and private keys) is binary and if it weren’t that would be a problem.
I don't think you're disagreeing with GP. Maybe it should be binary, but in reality it almost certainly is not treated that way. Trade offs are often made for UX or other business reasons.
But security through obscurity is a valid part of a security methodology, and it’s a part that inherently a continuum rather than binary.

For sure some aspects of security are binary. But even with JWT (I agree with the main points of the article), a token with an expiry of 5 minutes but no revocation capabilities is still objectively preferable to no expiry at all.

The binary aspect of security is primarily about whether you fall within your risk appetite or you don’t.

Right.

The problem then is that people - Us - all of us here on HN - frequently fail to understand their project requirements or at least fail to anticipate the future requirements of a project - and we’re arguing about what those requirements should be :)

And it’s not just people under-estimating things: it’s too easy to us ambitious-types to think “what if this simple PHP project goes viral and we need to scale to millions of users overnight?” (Answer for the curious: it won’t) - which in turn makes people think using stateless tokens is fine (well, it is fine, actually - provided you have a revocation system; TFA’s title is just clickbait, and the problems are hardly unique to JWT: almost every web platform’s built-in authX system will support stateless user-info and authorisation and use it by default… if not always and by-design (ASP.NET’s ClaimsPrincipal, Kerberos, etc). (Note I’m not referring to server-side session-state (like PHP’s $_SESSION) which is not intended for authX nor does it scale, for reasons mentioned in the article)

The article is a contrarian-sounding ad for Redis, written by a Redis employee, on Redis’ own website. Why are we treating it like news? And why am I even writing this retort? Argh! HN’s content team know how to drive my engagement! I’m doomed…

(comment deleted)
Security is binary, as in zeroes and ones that you will never lay eyes on. You seem to be claiming that security should be easy, when in fact the hacks that come will likely be much closer to the metal than you ever get.
It shouldn’t be, either. Things evolve around it, definitions change, but also things need to be less secure because of convenience or necessity. An emergency stop button that halts machinery, causes damage to the machines, stops production, but saves lives, can be the target of any number of imaginative scenarios of malicious actors hitting the button to cause damage or be a part of some grand hacker scheme. But we definitely don’t want to secure that until it takes badging in and a 2FA prompt just to use it.
Geez, even RSA is not secure if you push this thing hard enough. Cryptography is all about making it difficult to decrypt, not impossible to decrypt. One can easily setup a conspiracy theory that the government can record all the traffic, and decrypt the dump in the future when computers are fast enough.
Nothing is "secure or not" - technologies/mitigations are secure against particular attacks. HTTPS is generally secure against passive network eavesdropping, but does nothing to stop local file inclusion in a web app.

Just because there are attacks or ways around a particular defense doesn't mean it's worthless, that's why we have defense in depth.

This. That's why they call them 'attack vectors'.

I disagree with the main thesis for why JWT is a problem. JWT isn't necessarily encouraging you not to hit the DB for user lookup. This is the claim the article makes as a problem with revocation.

It reads like a really long thoughtful article based entirely on false assumptions for how to best use it.

It's ok to carry around some encrypted state in your tokens for some uses cases.

It seems like quite a silly position. By the author's own admission, it is possible to mitigate all the risks warned about. I certainly don't agree that something is never OK to use because if implemented improperly it wouldn't be secure. If I took that seriously, random password generation is insecure, because someone could just use an cryptographically insecure PRNG.
Exactly. We don’t even know for sure that there isn’t a faster way to factor numbers with classical computers.

If you’re handling sensitive data, you have to understand the tools you’re using and what their relative weaknesses are. Best practices are nice. But it’s far too easy to make a mistake following them if you don’t understand the principles behind them.

“X is always secure” is a great way to ensure X is not implemented correctly.

Holy hyperbole, Batman.

This is just a straight marketing post for Redis.

Yep if you look at the bottom paragraph it's a marketing advertisement.

I suspect the engineers that helped write this article are either very strongly for redis or cringed knowing their content would be used this way.

No system is 100% secure.

The irony is: redis and memcached are not great for storing sessions either.
Why not? Every large system I’ve ever seen used one of these for sessions.
TDLR; Use Redis to lookup your user data in realtime, instead of signing a token and trusting it.
+1. Redis is a great option, you can use other similar services, but just dont use JWT for something that it's not meant for.
TL;DR as always, is that there's nothing wrong with JWT. The problem is with thinking that there is a way to have an authentication token that isn't persisted in any way, so long as you want the ability to invalidate a token (i.e. logout, user banned, password change, etc).
The difference tho is maintaining a list of user ids you dont accept, a "blackist" (likely very small and each record expires as the token expires). This can be kept in-memory

Vs doing a network request to your DB and searching a table that could have millions of rows.

Well this is what I mean by "persisted in any way." A blacklist is still persistence.
This doesn't only apply to the way JWT tokens are usually used for sessions (no persistence). The default session store for Devise (Rails) and .NET Identity is cookies, on the client. They are encrypted with a secret key and decrypted for authentication. Identity in particular allows you to store any number of "claims" in the cookie, such as a username or role. Because the cookies are signed and HTTP only, this is safe from attackers, but this method, along with pretty much any method that isn't storing some sort of state on the server, has the same 3 problems listed in the article.

   1. Logout doesn’t really log you out!
   2. Blocking users doesn’t immediately block them.
   3. Could have stale data
I know there are ways around this with a really fast refresh time, or as I've heard, storing some sort of signature in the cookie, but I personally prefer a plain old server-side session store with something like Redis, or even just an in-memory HashMap. Authentication doesn't have to be that complicated.
Regarding Devise + Rails cookie session store:

1. Logging out deletes the cookie, you are really logged out. If your session cookie got stolen, you have other issues but I don't think this is really a matter of being 'logged out'. It is pretty easy to implement 'revoke all sessions for this user' type of logic with Devise and Devise does this of the box when a user changes their password.

2. Permissions are orthagonal to Devise. Devise stores the user ID in the session and loads the user model on every request, any permissions / blocking system would chain from there.

3. I can't think of anything that devise stores in the session where staleness would matter, other than things intended to be checked for staleness, like the salt that is used for the aforementioned revoke all sessions on password change functionality.

For 2 and 3 I was mainly referring to Identity, although I'm not sure how it works internally. For 1, I think the main issue is that when someone logs out, or you log someone out, you aren't guaranteed that they are actually logged out. There are cases where this does matter.

How does Devise handle 'revoke all sessions for this user'?

> How does Devise handle 'revoke all sessions for this user'?

The cookie has both user id and a special token which IIRC is a substring of the user's password salt. Retrieving current user from cookie includes not only looking up by id, but also verifying the salt. So if you change the password, the salt is also changed and all the old sessions will stop working.

Ah okay, so Devise does lookup the user in the database to authenticate. I guess it's not applicable to my premise then.
This is exactly the point of the blog. If you are using JWT + Workarounds to make it secure, then you'll loose all the benefits. This is why virtually no one in fin-tech use JWT.
I once watched a presentation about Macarons [https://en.wikipedia.org/wiki/Macaroons_(computer_science)] that is purportedly better than JWT. Are there any good success stories about using this?

    - Holder of macaroon can issue a sub-macaroon with smaller power, while JWT is fixed
    - Macaroon is notably longer than JWT
    - Macaroon is equivalent to signed JWT, but does not offer equivalent to encrypted JWT
Doesn't sound like it solves the problems mentioned in this article.
JWT, while having shortcomings have the advantage of decoupling systems by enabling token validation and user data retrieval without having to communicate with the auth service or the database directly. Worst case, with the approach from the article, every component has to make a call to the database, becoming dependent on the data schema, etc.
I actually find this post/ad for Redis pretty ironic, because Redis is actually a really great solution for storing revoked tokens (since you can just store the token with an expireat equal to the token's expiry timestamp). I do think it's a serious issue that most jwt howtos don't mention expiring tokens and/or refresh tokens, but "JWTs are not safe" is hilariously hyperbolic.
Once you reach this level of enlightenment ("any session should be revokable and fail closed"), there are still higher levels of abuse you'll need to prevent.

Let's say you keep your user sessions in Redis and replicate active-active between multiple regions. Your service allows for more than one active session per user, and has a second index of such "live sessions" so that users can terminate all of their sessions at once (eg. "Log out all of my devices").

You use optimistic concurrency to update multiple indices and pieces of information. Session mutation events and validations can occur anywhere.

What if an attacker slowly logs in thousands of different accounts, hundreds of sessions apiece, then logs everything out in unison?

Redis is single threaded, and all of your validation reads are going to get jammed with impossible to clear logout events. Replication is going to play these events out in all of your Redis clusters, meaning each of your regions will fall over. Nothing in logged-in flow can be processed, and you're stuck.

That was fun to fix.

I've got so many horror stories... Redis is great, but engineering at scale is tough even with great tools.

Using JWT in the browser id an anti-pattern for a different reason: they can easily balloon over 4kB if you have groups as claims and now you got to split them and a bunch of other things that are annoying.

On the backend you get similar issues. Many servers default to 4kB header sizes, or 8kB, or unlimited, or anything between there. So now you get to have some fun configuring reverse proxies and node and uwsgi and tomcat and…

(comment deleted)
https://redislabs.com/blog/json-web-tokens-jwt-are-dangerous...

> 1. Logout doesn’t really log you out!

That is true, but if someone intercepts a token then they can already see all the data (or perform all the actions), even before the user logs out, so this doesn't count as a flaw.

> 2. Blocking users doesn’t immediately block them.

Lame. A simple blacklist would suffice. The blacklist entries would expire after the lifetime of a generic token. Since the blacklist is small, it could fit in server's RAM and be fast. Or it could be stored somewhere in Redis.

> 3. Could have stale data. > Imagine the user is an admin and got demoted to a regular user with fewer permissions.

Lame. Just block the old token on any privilige changes. All roles are stored in a token anyway, so if a user's priviliges change, then all the user's tokens should be included in the blacklist.

> 4. JWT’s are often not encrypted so anyone able to perform a man-in-the-middle attack and sniff the JWT now has your authentication credentials.

Not even true. There're no credentials in the token. There's just a user ID and that's it.

> It’s been found that many libraries that implement JWT have had many security issues over the years.

And Linux kernel has had many bugs. So what now? Not use Linux?

> In many complex real-world apps, you may need to store a ton of different information.

And storing it in the JWT tokens could exceed the allowed URL length or cookie lengths causing problems. Lame. No one uses cookies or URL for that. No one stores enormous amounts of data in a JWT.

> In many real-world apps, servers have to maintain the user’s IP and track APIs for rate-limiting and IP-whitelisting.

Not a valid argument. Those apps aren't even many, they're a very small portion. Very small, almost zero.

> One popular solution is to store a list of “revoked tokens” in a database and check it for every call. And if the token is part of that revoked list, then block the user from taking the next action. But then now you are making that extra call to the DB to check if the token is revoked and so deceives the purpose of JWT altogether.

They aren't very smart, are they? Because they don't even see a difference between a short in-memory list and a database full of users records.

> Bottom line

Bottom their ass

None of your security postures will fly at any organization with an infosec team.

AuthN/AuthZ is one of the most important areas to lock down.

So you don't have to say anything on point. Just abstract imaginary accusations. Move along.
I worked for two years on a session system for an institution that cared deeply about security.

We had to trace, kill, kill all for single or multiple sessions, users, or organizations. Do this for entire IP ranges, client versions, or client ids. Rate limit all "session-mutating" (unidirectional state machine) actions, time out, model session confidence, restrict session scopes (subset authz), associate with any entity written or touched, monitor lists of compromised emails and passwords, require 2fa...

Your opinions might work where money and privacy aren't involved. But I wouldn't trust your posture with my bank info, emails, or personal messages.

What happens if your signing key leaks? Or you accidentally log session JWTs? Or someone's device goes missing, or someone steals a password, or an account manager has their info posted openly?

We're not worried about just our entire database. We're worried about any ATO, undesired action, or data leak, however small. Even one impacted person is too many.

Security really fucking matters. Take it seriously or don't touch it.

I don't get why you couldn't have a panic bit set the same way you maintain an in memory revocation leak... Also I don't get how this is any different than "what if a DB password" leaks?

What if someone steals a device and copies the httpOnly cookies from the network developer inspector tab then forges the requests using Curl?

I don't see how these problems are unique to JWTs and how they exist unmitigated with the use of in-memory revocation list.

> Note that the lightning emoji indicates a blazing fast speed. And the snail emoji indicates slow speed.

This article was embarrassing, and makes Redis Labs look childish and inept. Whatever process resulted in this blog post should be axed immediately, and this author should not be writing anything public facing.

Default rails cookie-based session storage is similarly stateless on the server, it's just a cryptographically signed packet sent by the client. Does it suffer from the same problems? Are these problems inherent to server-stateless session solutions, is the argument that you need server state?

I think.. not actually. If you store the user_id in Rails session, as is typical.

The OP seems to be complaining about storing a serialization of the user, or the complete list of user auth entitlements, in the session, to avoid doing a user lookup at all... as is apparently common with JWT? I don't use JWT. Can you just store the user-id in JWT instead, planning on doing a db lookup for the user? Is this not something people do?

Or maybe it would apply anyway, becuase you still can't "revoke" a session? It's still true that if someone snooped on your session, they could immpersonate you I think, which is also what they're complaining about? I'm a bit confused by the threat model honestly, it's a pretty verbose post.

> JWT’s are often not encrypted so anyone able to perform a man-in-the-middle attack and sniff the JWT now has your authentication credentials.

Wait.. is he saying literally the password (that can be used to get a new JWT?) is put in the JWT payload, unencrypted? This is a thing people do, really??? It is obviously a bad idea, yeah. Back to Rails, Rails started encrypting as well as signing session cookies a while ago, because of Security, yeah.

The OP seems to be conflating a bunch of differnet things... which is fine if they all apply to standard commonplace uses of JWT I guess, or if JWT is too flexible and allows people to use it wrong... but doesn't make it very clear what the problems actually are.

Still back to wondering if the claim is that ALL no-server-state sessions are bad, or just that JWT is a bad implementation of it, or just that JWT as commonly used isn't being used right (like you COULD encyrpt JWT payload, but most people don't?)

And... it ends up just being a redis ad, really?

It's an ad for Redis.

If you're spending too much time looking up the credentials associated with a session cookie, you're doing something wrong. Maybe you need a cache. Sure, sometimes it won't be in cache, but it probably will be.

In general, I agree that sessions should be opaque tokens stored in an http-only, strict same-site policy cookie. I just had a few problems with a couple of the arguments:

> 3. Could have stale data

The only use case I've seen for storing authorization information in a JWT is for something like OAuth2 scopes, which is different than strict authorization rules. They're more like delegate rules, but you should only treat those as a first line of defense before you do the checks that the authorizing user actually has access to.

Also, it's just as easy to let a redis cache go stale. Seen it more than once with this same security issue.

> 4. JWT’s are often not encrypted so anyone able to perform a man-in-the-middle attack and sniff the JWT now has your authentication credentials. This is made easier because the MITM attack only needs to be completed on the connection between the server and the client.

If someone can MITM your connection in plaintext, they have your credentials, whether or not you use a JWT. Yes, any information you encode in a JWT is plaintext, so if you put personal information in there, consider it leaked. Am I missing the argument here?

I'm wondering if we can use Pub/Sub to push revocation data to all servers. Presumably revocations are rare, plus we only need to store them only for the JWT validity period, so additional memory usage should be minimal.

The downside is it looks more brittle than the simpler approaches. Upside is performance plus ability to revoke tokens.

> If you think about it, these constant debates themselves should be a red flag because you should never see such debates, especially in the security realm. Security should be binary. Either technology is secure or it’s not.

Hm. I'm not sure this actually matches what I've learned reading from security experts....

What do other readers think?

I am sympathetic to the idea that it's suspicious that there are so many "debates" about a security topic. But I don't think security is actually all-or-nothing/binary. It depends on threat models, risk tolerance, budget, etc.

These articles are uniformly terrible. They all and this one complain about stateless authentication systems and describe stateful systems as better. Probably, at small scale. Choose stateless systems for greater scale and reliability when you have to and when you have the capacity to make the careful choices and compromises that come with it.

But JWTs are neither here nor there. JWTs are stateless if you put the user information in them, and stateful if you put the state lookup token in them. JWTs are a format, not an authentication system.

Never ceases to amaze me when marketing content makes me think less of a company.

JWT is fine when used within an auth protocol like OIDC. It’s like claiming certificates are unsafe because I send the public and private keys.
The article references 39 minutes as the upper end of JWT token expiration.

Is this typically the case? Or can JWT token remain valid for hours/days?

(Issue being that even if you “logout” of a JWT session, the session token server-side is not invalidated as it would in a traditional (I.e. redis-based cookie/session store))

This is just over stated. Expiring tokens remotely isn’t that hard.
maybe you can add a `sid` in jwt token, then store this sid in redis. when you want invoke a session, just del this sid in redis.
The author mentions that "One popular solution is to store a list of “revoked tokens” in a database and check it for every call. And if the token is part of that revoked list, then block the user from taking the next action. But then now you are making that extra call to the DB to check if the token is revoked and so deceives the purpose of JWT altogether."

I believe the author is 'assuming' the devs are not using a db to validate revoked sessions.

It doesn't have to be a DB tho it could be a server in-memory list that gets updated via pubsub or some other means. This is a hell of a lot faster than doing a network call to a DB and because revocation lists should be small by definition and only exist for the length of the token expiration they are limited in their space requirement