DEV Community

Cover image for Don't use JWT for Authorization!
Sohan for AuthZed

Posted on

Don't use JWT for Authorization!

What's with the shouty title? Well, I wanted to grab your attention and get straight to the point:

🗣️🗣️ Don't use JWT for your backend authorization

Look, there's a time and place for every piece of technology and the tricky part is determining if your use case actually is the time and place. Hopefully this post will walk you through why JWTs might not be your best friend, and the rare cases where they actually make sense.

🔄 Quick Crash Course: What's a JWT?

So, JWT (pronounced "jot") stands for JSON Web Token. It's part of this whole family of specs called JOSE (no way!) that deal with encrypting and signing JSON. JWT is the cool kid of the family - it's defined in RFC7519 and gets all the attention. Why? Because while its siblings (JWA, JWE, JWK, JWS) handle the nitty-gritty encryption stuff, JWT is the one carrying the actual payload.

Think of a JWT as a JSON object wearing a fancy coat (some headers) and carrying an ID card (a signature) to prove it's legit. It's got these things called "claims" - like when it expires (exp), who created it (iss), who it's for (aud), and so on. The most popular claim for authorization is called "scope", which, fun fact, isn't even from JOSE - it's borrowed from OAuth2. Most developers end up mixing and matching these pieces like a authorization puzzle until something works.

⚔️ The New Enemy Problem: JWT's Achilles' Heel

Here's the thing: JWTs have a major weakness - once they're out there, you can't take them back (except waiting for them to expire). It's like giving someone an all-access pass and not being able to revoke it if they go rogue. This becomes super awkward with web sessions - ever tried implementing a proper "logout" with JWTs? Good luck with that! You're basically crossing your fingers hoping users will play nice and throw away their old tokens.

But wait, it gets worse for backend services. Imagine this: you revoke someone's access on your server, but they're still holding a valid JWT from before. They can keep accessing stuff they shouldn't - this is what the smart folks call the "New Enemy Problem" (first spotted in Google's Zanzibar paper). It's like changing the locks but forgetting about all the spare keys you handed out. Centralized authorization systems fix this by having a central service (think of it as like a bouncer at a bar) checking everyone's credentials in real-time. The New Enemy problem is a really hard and interesting distributed systems problem (and perhaps a future post here)

An example of the New Enemy problem:

  • Alice removes Bob from the ACL of a document;
  • Alice then asks Charlie to add new contents to the document;
  • Bob should not be able to see the new contents, but may do so if the ACL check is evaluated with a stale ACL from before Bob's removal

📏 JWT Scopes: Not as Fine-Grained as You'd Think

While JWTs look good on paper, things get messy in practice. Remember that scope claim I mentioned? It's... kinda vague. The spec basically just says "here's what characters you can use" and calls it a day. You'll see examples such as 'email profile phone address' floating around, and developers often try to get fancy with stuff like 'profile:admin'. But here's the million-dollar question: what does that actually mean? The whole site? Just one user's profile? Even GitHub's REST API has been wrestling with this for ages!

Modern apps need super specific permissions - we're talking granular stuff like 'issue/authzed/spicedb/52:author' instead of just 'issue:author'. When your users might need access to billions of things, you can't stuff all that into a token that's bouncing between services.

Coarse and Fine Grained Authorization

Centralized authorization is like having a smart assistant who keeps track of everything in one place. Need to check something? Just ask! For example: SpiceDB does this using something called ReBAC (Relationship-Based Access Control) - it's like a Swiss Army knife that can handle super detailed permissions while still playing nice with other permissions systems such as Role Based Access Control (RBAC), Attribute Based Access Control (ABAC), and other fancy patterns. Google also uses ReBAC for authorization across their services such as YouTube, Docs, and more.

🔮 The Crystal Ball Problem with JWT Authorization

Let's play pretend and say you're cool with using just a few JWT scopes. Even then, you've got a problem: how do you know what permissions you'll need? When your JWT gets created at the front door (like in an API gateway), it needs to predict what every downstream service might want. For anything beyond a super simple setup, that's like trying to predict next week's lottery numbers!

Plus, if you send a token with too many permissions to the next service, you're basically giving attackers a bigger target to hit. This headache led to the creation of Macaroons. These tokens can actually be trimmed down before being passed along - cool idea, right? But in reality, they're so complicated that most folks who tried them ended up saying "thanks, but no thanks."

Centralized authorization systems take a different approach. They're like "Hey, we know we can't predict the future, so just ask us when you need something!" Sure, you have to make an extra call, but systems like SpiceDB are optimized to keep data in-memory - so latency looks similar to reaching out to any other cache like redis or memcache.

🤔 So... Are JWTs Ever the Right Choice?

After all this JWT-bashing, you might think they're completely useless. But there is one scenario where they shine: one-time grants where access cannot be revoked. Though honestly, that's about as rare as finding a unicorn in your backyard!

Unicorn in the backyard

What system do you use for your authorization needs? Let me know in the comments below.

Top comments (0)