Be careful of the JWT hype train

Darragh O'Riordan on January 23, 2019

I’ve been researching using node as a back end for a few months now and SO MANY node articles, courses and project “starters” on GitHub suggest u... [Read Full]
markdown guide
 

I think there's way too much hype around it and people are using JWT because it's shiny!

As our industry shifts our paradigm from monoliths to microservices, knowing JWT is quickly becoming a requirement. Sometimes it is good to use the new shiny toy as an excuse to learn it. Even if your app serves less than 4,000 requests per minute and JWT would be overkill for your application, learning JWT and having practical knowledge of it is also of value.

Many articles will show you how to setup and login with JWT but they ignore the hard parts - Logging users out and blacklisting users

This is one area that is definitely overlooked and also complex. The most common solution for this is on the auth server itself, which will keep a list of users that are authenticated, expiring them when they log out. On each request the token will need to be checked against the auth server to see if the token is still valid. This adds significant overhead.

More commonly, most companies will decrease the expiry of the JWT, so it must be refreshed more often. This is due to the difficulty and overhead of managing a true logout experience.

“JWT is secure”

JWT is secure, but it is at the same time less secure than session based authentication. For example, the JWT is more vulnerable to hijacking and has to be designed to prevent hijacking. An unexpiring JWT can become a security risk.

You are also trusting the token signature cannot be compromised. This can happen if you are using weak encryption, encryption that becomes vulnerable in the future, or having the the private keys compromised. This vulnerability doesn't exist with sessions.

So while JWT is secure, it introduces new attack vectors that need to be considered.

There are valid reason to use JWTs:

  • API back end - Your site is static and your back end is an API.
  • Micro-service architecture - A very common way of authenticating across disconnected systems.
  • To Learn JWT - Implementing JWT in smaller projects is a good way to start learning JWTs.
  • Externalizing your authentication to a 3rd party provider like Auth0.

JWTs do not come without their own complixity:

  • Security is more complex and needs to be understood.
  • Just like how micro-services add complexity, JWT adds the same complexity as the auth is disconnected.
  • Simple things like logout become complex and might require changing your expectations and business requirements.
  • Doing JWT right is hard.
 

API back end - Your site is static and your back end is an API.

How can you avoid any curious customer don't call console.log() to show the jwt-secret?.

Client-side security is usually a bad joke.

Micro-service architecture - A very common way of authenticating across disconnected systems.

IP Whitelisting unless the microservice is based on dynamic IP.

 

How can you avoid any curious customer don't call console.log() to show the jwt-secret?.

You don't keep secrets in the JWT. Everything in a JWT should be considered public.

Can you tell me again, why we need JWT encryption?

JWT works with :

Ok, here is the key and it is unique, if it is stolen, then you are screwed. I will crc your key (and encrypt the crc) just for security.

Versus session works with:

Ok, here is the key, I will write down the key and if you don't use it for an hour, then I will invalidate it and you must ask it again. However, if you lose the key, then I can invalidate it, and since I generate the key, then it is safe.

Can you tell me again, why we need JWT encryption?

First of all JWT is not encryption. It is authentication and authorization.

I can't tell you why you need JWT because I do not know anything about your application. But I can tell you why I am using it.

The environment I am working in consists of multiple disconnected systems, each maintained by different departments. JWT allows us to to create an authentication service that is disconnected and also works across multiple systems.

Ok, here is the key and it is unique, if it is stolen, then you are screwed. I will crc your key (and encrypt the crc) just for security.

This is a complete misunderstanding of JWT and realky has nothing to do with JWT.

Encryption (checking the token contents against the signature) works to ensure that everything in your JWT token is valid and hasn't been altered. So it's public, but you can trust it.

That’s not encryption, that’s just signing. The data in a JWT is base64-url encoded, but otherwise easily readable.

There is a standard for JWT encryption, but that’s a whole extra level of pain.

 

The Jwt is for your back end, not your UI. The web client doesn't need to validate it, only pass it along with it's requests.

 

As our industry shifts our paradigm from monoliths to microservices, knowing JWT is quickly becoming a requirement.

Unless scaling your system has driven you to microservices as a point of last resort, they're usually the wrong answer. Over the next couple of years, people are going to figure that out the hard way.

I don't know why JWT would be a requirement for microservices, though. A user connects to an HTTP server, the JWT token is checked there, and the HTTP server connects to other microservices with the user information as part of its request. There's no reason to pass the JWT around.

 

Unless scaling your system has driven you to microservices as a point of last resort, they're usually the wrong answer

I am going to disagree with this statement. It sounds like you are suggesting JWT is a BAD option and should only be used as a last resort. JWT is just an option. And what you choose is will depend on your specific application and needs. So there are times when JWT is the BEST option.

To make a blanket statement saying JWT is always a BAD option is just not valid.

I don't know why JWT would be a requirement for microservices, though.

No technology is never a requirement, but an option... A tool available to us to choose and use.

There's no reason to pass the JWT around.

Blanket statements like show extreme bias and because of this bias become easily dismissed. To prove "no reason" is impossible. There's always a reason.

I wasn't saying that JWT was usually the wrong answer. I was saying that microservices are usually the wrong answer.

Can you provide a scenario where passing a JWT around among microservices is a good idea?

Can you provide a scenario where passing a JWT around among microservices is a good idea?

I'm starting to feel like I am being Sealioned here.

Sealioning

Not my intention. I genuinely would like to know of such a scenario, since I can't think of one.

 

Static site with API backend is not a use case for using JWT.

I use “static” frontends regularly with GraphQL backends and still use sessions with secure httpOnly cookies so they can’t be accessed by the browser.

IMO JWTs are okay for what I refer to as “loose” authentication (when you quickly want to hide some nonsensitive data behind a login using a service such as Auth0 but your not necessarily exposing sensitive data).

Always, when exposing potentially sensitive data, use sessions with secure httpOnly cookies.

 

Static site with API backend is not a use case for using JWT.

it is also not NOT a use case.

I like JWT when you have multiple distributed systems that need to share a single authentication that a single system doesn't have the authority to maintain itself.

Authentication as a Service.

 

Good article, but I can't agree on the ideas you brought up. An http cookie is a technology that originated from the browser world. JWT is agnostic and is not bounded to any platform or technology. We use JWT to store userId only. Sure both cookies and JWTs can be used in similar ways, but it's all about the intention of the code/solution you are building. And when using JWT the intention is a universal token that can be used anywhere and stored any where and not a cookie.

 

And the security of localStorage is not the joke that cookies are. blog.meteor.com/why-meteor-doesnt-... But when your entire argument is based on 'its probably good enough', then the presentation of new evidence is unlikely to change a thing. So have fun with your cookies!

 

I've been fighting several days to convince the other developers of the startup that I work for that JWT is not the ideal solution for authentication, I'm happy that there are other people who are talking about this :D

 

I think there's way too much hype around it and people are using JWT because it's shiny!

I think they all suggest JWT because it's easy to setup and lots of tutorials about single page applications just re-iterate that since it can be controlled by JS.

So are cookies. Cookies are just an HTTP header. Any HTTP client can read and set headers. The cookies header also has 20+ years of security and functionality built in to it for browsers (HTTPS only, expiration, site scope, blocking access from JavaScript) and there are well known and understood fixes for issues like CSRF tokens for forgery.

Exactly. That to me is the weakest argument

There was a really interesting discussion one year ago about using JWT and the local storage here if you're interested:

This is my favorite resource so far on the argument JWT and sessions: Stop using JWT for sessions, part 2: Why your solution doesn't work

ps. dev.to doesn't use JWT for the session, just to store additional user info.

 

I think a big part of JWT should be some type of API Gateway.

In an example case (microservices) we take an API key from the client and the API Gateway creates a signed JWT with relevant user info. This is where blocked/logout checks will be handled.

With this, the JWT gets passed to the corresponding API service and it won't have to check again with the API Gateway on the given JWT. The JWT can also be passed to subsequent services if needed on behalf of the parent service.

1 call to user info is needed in this scenario. And the N microservices within the API request scope doesn't not need to check user auth.

 

API Gateway? Sounds more like an auth server.
"The JWT can also be passed to subsequent services if needed on behalf of the parent service.", that's a risk not a feature.

 

i havent dealt with this situation before
but what the auth api gateway .. will hand to the services ? the user id right ? will that be on the header ?
thank you

 

JWT is also praised because it features multiple algorithms of codification. It even shows it on its homepage.

Multiple algorithms is not a feature but a problem. We don't need +10 methods of codification but a single one that works everywhere. And so far, only HS256 and HS384 are cross-compatible.

One of the problems of the cookie-session is the session hijacking. JWT doesn't solve it, either for XSS or CSRF. So, what's the objective of JWT?.

Finally, if we want security then we must use SSL. And if we use SSL, JWT is turned redundant.

 

Actually, it's assumed that generation of JWT and exchange of it has to be conducted through SSL for security reasons.

So I don't really think JWT is redundant since it's use case is more suited for API gateway backend to authenticate API services of a given user.

 

But JWT assumes that both parties know each other, JWT doesn't address that problem.

Nah pretty sure SSL doesn't work this way.

Since that technology just provides you a encrypted tunnel.

It does not identify you as who you are as a user besides basic information of the computer you are using.

No, the raison d'etre of SSL is that each communication is safe, so it can't be read or modified by a third party, exactly what JWT promises.

Yeah you are assuming that it identifies the user who are using it but the SSL only identify the computer itself is being used but the problem is that you can have multiple ppl using the same computer. So it is not that specific to the point of that it identify the correct information the user is using at the specific point of time

😵 in a nutshell, we already have session and ssl, the encryption is done by ssl and the identification is done by the session (or cookies or token). SSL is not about identification but that it is possible with a session that it doesn't require a special tool to configure.

So, why we need JWT? To replace ssl and session/cookies? Not really, we still use ssl and or session.

JWT allows a way to not have to check a central DB for every request to say an API. Albeit not w/o drawbacks as covered by this piece. So instead of -- 1) receive request, 2) look up user's session for info and to determine if it's valid, 3) serve user request -- with JWT you can eliminate step 2.

As the author describes for most small and medium sites, validating a request against a central session store is really not that onerous. It's only when you get into Netflix territory - then you have to worry about how to distribute all that state where it's always available and accurate in real time for any service that needs to authenticate the user.

 

Great observation.

I would refute with two points:

1) Your application doesn't need it now but if it's a real application then you should always be getting ready for the future. JWT support is extremely easy to add now-a-days as any production-ready web framework will support out of the box or with a plugin.

2) JWT is a common standard for handling several different concerns. Having it implemented out of the box means it will already be there when you actually do need it.

I personally design everything with a scaling-first mentality. It's easy to neglect scaling until your awesome app crashes at the awesomest time ever and you lose all of your awesome users and you awesome clients don't feel awesome about paying you an awesome amount of money.

 

I don't see how cookies are going to stop your scaling? Get user info and store it in a cache with TTL.

 

But how do you check wether an user is authenticated or not in a single page application? What if I'm running an app and web app on the same API?

 

But how do you check wether an user is authenticated or not in a single page application?

It's quite straightforward:

  • on login the client receives a successful response, a secure httponly cookie is set by the server and that's it (the user is now authenticated)
  • the cookie is sent by the browser at each request
  • on logout the server invalidates the cookie, the browser forgets it and you can logout the user
  • you can still use jwt and the local storage to store additional user's data, just not the session cookie

What if I'm running an app and web app on the same API?

what do you mean?

 

Android App & Website sharing the same API & Authentication service, how are you supposed to store a cookie on an app?

You're not bound to have the same authorization mechanism for both services if it doesn't suit your Android app, but you can:

how are you supposed to store a cookie on an app?

A cookie is just a header (not much different from the Authorization header OAuth2 uses), your app has a HTTP client, they usually handle cookies easily.

I'm quite sure there's a way to store a cookie in Android, by Googling I found these:

I do not know how up to date such info is because I have zero experience developing on Android but I do know that whenever you have a decent HTTP client, you have support for cookies (they are not a new technology ;-))

If you're sending http requests with headers back and forth than you must have cookies because cookies are essentially just a header. Right?

 

A brand new approach regarding the usage of JWT, which is the combination of the two very famous security mechanisms JWT and TOTP for the first time in their digital lives.

check it out

 

Great article. Good points on JWT and how much attention it gets while not being the complete solution some make it out to be. I think you are also making a good point about shiny new technology in general. It happens a lot where something comes out and becomes the new big thing and it gets misrepresented as something it is not.

 

Thanks for all the responses. Love the community here. Some interesting points and discussion.

I just hope this article might make people consider if they are using JWT to solve a specific problem for their application rather than just using it by default :) Especially people new to web development using a "starter" or doing a course that only shows them JWT in local storage.

Quoting joelnet - "Doing JWT right is hard." !

 

there are well known and understood fixes for issues like CSRF tokens for forgery.

These also add a stateful component to the API. If you want people to still be logged in after node restart or if you ever need to scale beyond one node, then you have to make sure your sessions/CSRF tokens are stored in a shared database (e.g. Redis). This creates extra failure modes to handle (session store down or overloaded) vs verifying the JWT signature. Session cookies are a great solution for many cases, but it has trade-offs too.

 

You don't need JWT, so don't take it that way; but I think you've perhaps had some difficulties and you're perhaps missing a thing or two:

  • on transience: a session cookie has transience too -- and it can be stolen just as effectively as a jwt. Anything which has "physical" access to the document can hijack cookies or localStorage. Anything "on the page" can steal my auth cookie too. Cookies won't save you here.
    • naturally, the fix is to make your jwt have a short lifespan and include a renew token which is automatically used when a web call encounters a 401. Handling expired tokens isn't really your problem -- there are already good frameworks to deal with this, and good auth providers (like Auth0) so you can have someone else deal with this complexity and the security of your user data in a professional manner.
  • No-one said you had to include the JWT as a bearer token. You can use it however you like, including as a cookie
  • There must be no secret data in a JWT. If there is, you're doing it wrong. The point of the JWT is to allow the front-end to make display decisions based on the user's scopes. Your backend still has to implement real security. The front-end should be able to validate the JWT, if it really wants to, by hitting and endpoint. NO JWT SECRETS MUST BE AT THE CLIENT. You should be using something like the OpenID Connect flow, where your login and secrets are done server-side, giving back a token to the web client. The other flows are meant for server-to-server processing, so if you're using them in the client, yes, you're doing it wrong and yes you're not secure at all

All of this is not to say you can't (or shouldn't) use session-based auth -- go ahead! JWTs just make it easier to:

  • make client-side display decisions for the user (eg if she doesn't have access to the admin area, don't show the links)
  • centralize your authentication and authorization in one service which doesn't have to be duplicated across web apps. This service can be queried for token validation as and when necessary.

Doing JWTs properly is hard. I've done it a few times -- and wrong a few of those times! But where I'm standing, the friction to get them working with something like IdentityServer is so low and the benefits for "heavier" client-side web applications outweigh the small setup cost.

 

All good, but - what about "microservices" architecture? Where several servers cannot validate the cookie session? Do you have a solution other than JWT?

 

Assuming you need the JWT for user properties because of your decoupled stateless architecture, just have another property on the JWT that holds a key.

Assuming you have a layer in your architecture that all your microservices use for config etc. Redis for example.
The value for that key in Redis could be the token.

 

This is an odd misconception I keep seeing about microservice architectures. Typically you have a gateway where requests arrive. The gateway verifies the session and forward the user context that it verified to any other systems it needs to contact.

This is how all the big companies that came up with the notion of microservices like Google and Facebook work.

 
 

No role changes or payment status changes might have occurred since the JWT was issued?

Can't we revoke JWT in that case?

By no means a JWT advocate btw.

 

Then you have a stateful revocation list you have to make available to every server and JWT is no longer stateless.

 
 

Branca

tuupola / branca-spec

Authenticated and encrypted API tokens using modern crypto

Branca Token

Authenticated and encrypted API tokens using modern crypto.

What?

Branca is a secure easy to use token format which makes it hard to shoot yourself in the foot. It uses IETF XChaCha20-Poly1305 AEAD symmetric encryption to create encrypted and tamperproof tokens. Payload itself is an arbitrary sequence of bytes. You can use for example a JSON object, plain text string or even binary data serialized by MessagePack or Protocol Buffers.

Although not a goal, it is possible to use Branca as an alternative to JWT. Also see getting started instructions.

This specification defines the external format and encryption scheme of the token to help developers create their own implementations. Branca is closely based on Fernet specification.

Design Goals

  1. Secure
  2. Easy to implement
  3. Small token size

Token Format

Branca token consists of header, ciphertext and an authentication tag. Header consists of version, timestamp and nonce. Putting…

 

'makes it hard to shoot yourself in the foot', now you need the secret on the client to decrypt?

code of conduct - report abuse