The promise of JWT

Published on 2015-12-31

In this article I will dive into JSON Web Tokens (JWT) (RFC 7519) and explain the good sides. Hopefully this will show why I basically consider them the silver bullet in web application security.

Let me start with the easy part: JSON! Yes - the JWT is JSON, just JSON! This is great. In backend code in languages like Go, Java, Ruby and PHP there might be a little overhead - but this is not much at all. If you are using Node you are golden and to the important big issue: Your frontend! Your frontend for your web applications are written in Javascript - therefore you'll have a perfect platform using JWT - JSON based tokens are very easy to implement and require very little client side code (think reduced computation and download for your users).

Let's dive in and look at a token. Here is one:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMzA4NDAyMzk0IiwibmFtZSI6Ik5vem5hYiBMZWFoY2ltIiwiY2FuX2FjY2Vzc19zdHVmZiI6ZmFsc2UsImFkbWluIjp0cnVlfQ.51tRAEw_ovOmX7xPNNjxUTFm7vTykDr30ih6srHaSKI

The token is three base64 + URL encoded JSON objects separated by punctuation marks. The data is encoded this way to make it URL safe. If we split up the parts and decode them it'll give us:

The header

{
  "alg": "HS256",
  "typ": "JWT"
}

In the header the alg specifies the algorithm used for creating the hash (used for verification) and typ is the type of token we are dealing with (in this case JWT). The final element key is one I put in there. You can generally put in extra stuff that suit your needs - in my example I can use the key to lookup the secret used to make the hash (more about that later).

The payload/data

{
  "user_id": "308402394",
  "name": "Noznab Leahcim",
  "can_access_stuff": false,
  "admin": true
}

This part can contain whatever you like. As you see I've put in the ID and name of the user along with some booleans that can be used in the frontend to show content and allow functions based on the users access.

The final part will give us some binary data that is the checksum of the rest. And this is one of the magical elements!

One of my first thoughts was great - the frontend can verify the token! That is dumb. First of all client verification would require the client code (plain text Javascript) to contain the key used to sign the token. Furthermore the client doesn't really need to do any verification. It just got it from the server - and if it did it could simply do a request to the backend that contained the token and that would give some indication of the token validity!

The magic comes from the fact that it is essentially (if implemented correctly) stateless. Every request contains the token, the token includes permissions and information used to complete the request, and the token can be self-verified by the backend which knows the secret used to sign it.

One reason this might be a bad idea is that anyone could do an offline brute-force attack to find the secret key and by optaining it they could create and sign their own tokens and create chaos. In my opinion any sane implementation include some kind of rotating or per-token secret key. An easy way to achieve this is to have a table (in-memory or made persistant) that is a key value-pair where the key is put in the header of the JWT and the value is the secret key used to sign the token.

Furthermore if two servers/backend systems each knows the secret key the token can be used for communication between them.

I hope this brief tour of JWTs have given you a feeling of what you can do with them.