Using JWTs for authentication—is it worth the effort?
Tags: discuss, node, webdev, javascript
Published: 2020-12-14 23:12:21

When you look for advice on how to authenticate users of an Express/Node.js API, the most popular answer seems to be "use JSON web tokens".

I took this advice as read when I was building my first few APIs. I dilligently built the middleware for signing, verifying and revoking tokens, plus the client-side code for keeping them.

A few years later I discovered Rails. I was very late to the party, but the simplicity of using Rails [session cookies](https://www.tutorialspoint.com/ruby-on-rails/rails-session-cookies.htm) was really attractive after the hassle of building secure authentication again and again.

So, I've recently started building another Node/Express API, and I've decided to use the same session approach. It's been much less stressful.

The setup for [`express-session`](https://www.npmjs.com/package/express-session) looks like this:

```
server.use(session({
    store: new (require("connect-pg-simple")(session))({
    }),
    secret: process.env.SESSION_SECRET,
    cookie: { maxAge: 30 * 24 * 60 * 60 * 1000 }
}))
```

And then in my route handlers, it's as simple as saying:

```
// where 'user' is the user who has just authenticated
req.session.userId = user.id
```

Because sessions are stored on the server and the client only gets an encrypted cookie, this seems foolproof and easy to maintain.

The cookie is passed in automatically with every request - it _just works_.

**So, I'm wondering why people bother with the extra overhead of JWTs at all?**

The reasons I normally hear are:

## 'JWTs are more scalable when your app needs to grow'

I guess this might be true if you're keeping sessions in the memory of a particular app instance, but any realistic implementation involves an _external_ session store.

Even my minimal example above uses a table on the PostgreSQL database that powers the rest of my app.

That database is an [external service](https://www.heroku.com/postgres)—it's horizontally scalable out of the box. This doesn't seem to be a realistic problem?

## 'JWTs are more secure'

Recently I've seen lots of people suggesting it's easier for JWTs to be stolen by XSS attacks, especially if you keep them in localStorage.

The current wisdom seems to be that you need to store them as a `httpOnly` cookie. So...why not just use cookies to start with?

## 'JWTs are stateless'

This one I do understand - a stateless API is ideal, easier to test.

But what's the harm in a session that stores just the user's ID, say? Is that tiny bit of state really that bad?

To take it a bit further for the sake of argument, let's say we used the [cookie-session](https://github.com/expressjs/cookie-session) store.

What's the difference between this and using a JWT in a cookie? Just the way the token is formatted/encrypted?

## 'JWTs still work when the API is on a different domain'

This one makes sense too - cookies should be restricted to a particular domain, and if we're making requests to a third-party API on a different domain, we'll need to manually handle a token.

But how do we square this with the best practice to store JWTs in cookies rather than localStorage from earlier?


## Am I wrong?

What am I missing?

What situations would a JWT be worth the effort in?

Do you have a preference for sessions over JWT, or the reverse?