JWT or not?

In a recent web portal project, made with Python and Angular, I faced the amethic doubt: should I use the standard pseudorandom generation of session tokens, or should I use a JWT?

Wait, what is a JWT?

A JWT (JSON Web Token) is a standard format for building tokens with claims. The standard defines a set of mandatory tags, a format (header, payload, signature) and some other useful things. All those things are encoded in base64 (of course the signature field is calculated before this step), concatenated with a dot . and the result is sent to the user as a token.

Note that, by default, a JWT is signed, not encrypted. So, informations are visible to anyone: do not place sensitive content in a JWT. Instead, you want to use the encrypted version, named JWE (JSON Web Encryption).

More info here: https://jwt.io/

Why we (may) need a JWT?

Old-school session tokens are pseudorandom generated text. Usually they’re hexadecimal or base64 outputs from a random sequence of bytes. This string is used as an unique identifier for a set of server-side parameters, named “session”. This “token” is sent to the client, which uses it every time it sends a request to the web server.

A JSON Web Token is a string built starting from three base64-encoded JSON. This structure allows us to:

JWT detractos says that there are a number of advantages:

  1. You don’t need a lookup in a database to retrieve the session, as you can have an arbitrary number of (custom) fields inside the payload section of the JWT to describe what you need.
  2. The claim is verifiable via a strong cryptographic function, so no risk of faked claims

The point 1 is actually quite interesting: one difficulty in a scalable web application is the session database synchronization and performance. Usually, to deal with very high web request loads, the load balancer is configured to forward requests with the same session token to the same backend server, to avoid bottleneck or inconsistency for session data. A JWT may embed data useful to rebuild the session without a lookup in the session database (so, performance improvement and lower number of issues and configurations).

Is that so?

If JWT is good or not, it depends on your context. I’m not a big fan of sending base64 blobs in HTTP just to identify an user. In fact, I think that the cost of synchronizing the session database is more manageable than kilobytes of serialized JSON to parse and verify cryptographically.

But there are also other reasons to not use JWT: first of all, they’re not encrypted, so there is a constant leak of (server-side) informations. This may be a problem or not depending on your project, but I think that one should reduce the information leakage to minimum.

Ok, so we can avoid information leaks using JWE (the encrypted version of JWT). Now the problem is that, for each request, we need to:

  1. Split a string in three components
  2. Decode three base64 fields
  3. Parse JSONs
  4. Decrypt the payload
  5. Verify the validity of the token, and other informations

Let’s assume that we can do this faster than a simple hash search and JSON decode. We can face a bigger problem.

The JWT/JWE is meant to be sent in HTTP headers, or in HTTP cookies (which are inside requests/responses headers, so…). Although HTTP RFCs doesn’t set any limit in header size, most webservers have a limit for all the HTTP request and/or response (eg. Apache is limited to 8KB). And cookies usually are limited to less than 4KB.

Even if the encryption doesn’t add a significant number of bytes, you have the base64 encoding which eats 33.33333% more space than the original text.

Last, but not least, how do you expire a single token before its natural death? In JWT, the only “proposed solution” is to synchronize a blacklist to all webservers, so you can check if the token was blacklisted and discard it. Which is funny, because this will require an hash lookup in a database.

Then, probably, we need to access to the DB anyway. So, what’s the point to decode and checks all those things instead of a simple query?

So JWT is bad…

JWT can be useful if we know in advance that:

The real question that you want to do to yourself is: how big is my project? You’re not Google, so maybe you don’t need to scale to that level. And you can still use your old (pre-JWT) method.

What about UUIDs/GUIDs?

No, they’re not meant to be unique at this level, and they are not random enough (they provide 122-bit randoms, not so many). More info in the official RFC for UUIDs: RFC 4122, section 6.