JWT should not be your default for sessions – Evert Pot


When designing web applications, (especially the traditional html kind),
you will at one point have to figure out how to log a user in and keep them
logged in between requests.

The core mechanism we use for this are cookies. Cookies are small strings sent
by a server to a client. After a client receives this string, it will repeat
this in subsequent requests. We could store a ‘user id’ in a cookie, and
for any future requests we’ll know what user_id the client was.

Cookie: USER_ID=123

But this is very insecure. The information lives in the browser, which means
users can change USER_ID and be identified as a different user.


The traditional way to solve this is what’s known as a ‘session’.
I don’t know what the earliest usage of sessions is, but it’s in every web
framework, and has been since web frameworks are a thing.

Often, sessions and cookies are described as 2 different things, but
they’re really not. A session needs a cookie to work.

Cookie: MY_SESSION_ID=WW91IGdvdCBtZS4gRE0gbWUgb24gdHdpdHRlciBmb3IgYSBmcmVlIGNvb2tpZQ

Instead of a predictable user id, we’re sending the client a completely random
session id that is impossibly hard to guess. The ID has no further meaning, and
doesn’t decode to anything. This is sometimes called an opaque token.

When a client repeats this session id back to the server, the server will look
up the id in (for example) a database, which links it back to the user id.
When a user wants to log out, the session id is removed from the data storage,
which means the cookie is no longer associated with a user.

Where is the session data stored?

Languages like PHP have a storage system for this built in, and will by default
by default store data in the local filesystem. In the Node.js ecosystem, by
default this data will be in ‘memory’ and disappear after the server restarts.

These approaches make sense on developer machines, or when sites were hosted
on long-lived bare-metal servers, but these days a deploy typically means
a completely fresh ‘system’, so this information needs to be stored in a place
that outlives the server. An easy choice is a database, but it’s common for
sites to use systems like Redis and Memcached, which works for tiny sites, but
still works at massive scales.

Encrypted token

Over 10 years ago, I started working a bit more with OAuth v1 and similar
authentication systems, and I wondered if we could just store all the
information in the cookie and cryptographically sign it:

Question about session tokens on Stack Overflow

Despite getting some good answers, I didn’t go through with it as I didn’t
feel confident enough in making this secure, and I felt it required a better
understanding in crypto than I did.

A few years later, we got JWT, and it’s hot shit! JWT itself is a standard for
encrypting/signing JSON objects and it’s used a LOT for authentication.
Instead of an opaque token in a cookie, we actually embed the user_id again,
but we include a signature. The signature can only be generated by the server,
and it’s calculated using a ‘secret’ and the actual data in the cookie.

This means that if the data is tampered with (the user_id was changed), the
signature no longer matches.

So why is this useful? The best answer I have for this, is that it’s not
needed to have a system for session data, like Redis or a database. All the
information is contained in the JWT, it means your infrastructure is in
theory simpler. You’re potentially making fewer calls to a data-store on
a per-request basis.


Theres are major drawbacks to using JWT.

First, it’s a complicated standard and users are prone to get the settings
wrong. If the settings are wrong, in the worst case it could mean that anyone
can generate valid JWTs and impersonate anyone else. This is not a
beginners-level problem either, last year Auth0 had a bug in one of
their products that had this very problem.

Truncated by Planet PHP, read more at the original (another 7263 bytes)