Be careful of the JWT hype train

Published on January 23, 2019

I’ve been researching using Node.js as a back end for a few months now and SO MANY Node.js articles, courses and project “starters” on GitHub suggest using JWT on your client facing API as a session token.

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

🔐 What is JWT? 🔐

JWT is a JSON object that gets signed in a standardised way. This signed object or token can then be sent to the user through any mechanism. It’s usually returned in the body of an HTTP response or in some header like a cookie. The client sends this back to your server where you check the signature and use the data provided if it’s a valid token.

The idea is that token has all the details about the user and their permissions for resources on your API stored in it. Your API doesn’t have to hit another resource to get data when the user sends a valid JWT with a request for some resource.

This is in comparison to a simple session ID that is sent to the client, usually in a cookie. Which the client sends back to your server with each subsequent request. The server validates the session ID against a list it keeps in your database. Then it looks up whatever it needs to about the user to fulfil the request. All state remains on the server/database.

JWT is a terrible solution for client sessions on a web application.

“It will make my API stateless”

This is when you plan to put all the user data and permissions etc in the token so you don’t have to make a database call to get user data on your API. Sounds great but…

It’s probably premature optimisation

If you’re building a client server web application and you expect less than ummm say 4,000 requests per minute to the database, then the LOWEST paid ($50/month) tier Postgres and a cheap dyno on Heroku can handle that for you no problem. You don’t need stateless anything and you don’t even need memcached or Redis.

Even the completely FREE Heroku tiers should be good for at least 120 requests a minute. You should upgrade if your project is that popular (and congratulations on the success!).

Unless you’re expecting significant scale then for almost any company’s product you can scale up database sessions until you have enough cash and engineering talent to add something else. Don’t prematurely optimise.

Is your API truly stateless for user data?

It’s VERY difficult to avoid state in a useful client to server web application. Do you really retrieve nothing else about your user from the DB on each request? No role changes or payment status changes might have occurred since the JWT was issued? No intersections between the user and the specific request at all?

Like it’s possible if you have a micro-services architecture or something but unlikely in general.

You can’t implement stateless basic account administration

Many articles will show you how to setup and login with JWT but they ignore the hard parts - Logging users out and blacklisting users. Acceptable solutions for these features involve maintaining state.

If you want to legitimately have a user “log out” then you need to keep a list of JWTs that have been invalidated by the user. Now you have state that is checked on every request.

If you use a salt to sign each users token so you can later change the salt to log a user out, then you have to check a list of the salts each time the user makes a request and now you have state that is checked on every request.

If you want to be able to block a user because their account is in debt, deleted, or they are up to no good then now you need to keep a list of blocked users and you have state that is checked on every request.

If you increase the transience of the JWT to support log outs then you have a user logging in every 5 minutes, a terrible user experience and probably no users.

Stateful JWT - “I just store the user Id in my JWT”

Yes, you can put a user identifier encoded as a JWT in a cookie and use it like a session cookie but this is server sessions with JWT. Why bother with the JWT hassle? Just use some kind of uuid from a session library and be done with it.

“JWT is supported in all these frameworks and works better across both browsers and mobile clients”

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.

Every back end web framework supports HTTP headers and in fact probably has first class support for cookies, with a sessions library (via a generated id) tied to a data store of some kind.

“JWT is secure”

The signing and verification is pretty secure. However many articles and courses describe storing your JWT in local storage. This is not secure. Any JavaScript on the page can read it and use it.

You almost certainly have JavaScript on the page that you didn’t write that came from an NPM package or a CDN. Vulnerability injection in this way has been done before and will happen again.

The alternative to local storage is storing the JWT in a cookie. So now you need to protect the cookie just like you would with an old school session Id.

So what should you do?

Well you probably don’t need JWT. JWT has its uses but there’s a good chance it’s actually the wrong solution for your application and it’s making things more complicated or insecure than a session store with Ids and cookies.

So just be sure you know why you’re using JWT and understand its limitations before adding it to your awesome new app!! 😊

Darragh ORiordan

Hi! I'm Darragh ORiordan.

I live and work in Sydney, Australia building and supporting happy teams that create high quality software for the web.

I also make tools for busy developers! Do you have a new M1 Mac to setup? Have you ever spent a week getting your dev environment just right?

My Universal DevShell tooling will save you 30+ hours of configuring your Windows or Mac dev environment with all the best, modern shell and dev tools.

Get DevShell here: ✨ https://devshell.darraghoriordan.com


Read more articles like this one...

List of article summaries

#engineering

Building an AI generated game with Stable Diffusion and data from Wikipedia

Last week I released a game called Doodle:ai.

In the game you’re shown AI generated images and you have to guess the Wikipedia topic it used to create the game.

#engineering

Easiest way to optimise images for web

Here is how I optimise all pngs and jpgs in a folder for publishing to the web.

#developer-experience

Start tracking DORA metrics for your team in just 15 minutes with Apache Dev Lake

DORA (DevOps Research and Assessment) metrics are an excellent way for engineering organisations to measure and improve their performance.

Up until now, monitoring the DORA metrics across Github, Jira, Azure Devops etc required custom tooling or a tedious manual process.

With Apache Dev Lake you can get beautiful reporting for DORA metrics on your local machine in as little as 15 minutes (honestly!).

From Google Sheets to Grafana
From Google Sheets to Grafana

#engineering

A summary of NDC Sydney 2022 Developer Conference

I attended my first in-person conference for more than 3 years last week! NDC is one of the more well-known developer conferences in Australia and New Zealand. It’s a 5 day conference with 3 days of talks and 2 days of workshops.

There’s so much to learn across all the streams so I try to take notes for each of the talks to quickly reference them later. This post contains all my notes. I’ll add the relevant videos to talks later if they’re released.

A reminder that these notes are just my notes. They’re paraphrased and summarised from what the speaker actually said. Each speakers would have provided must more clarity and went into more detail during their pressos!

Comments