This article is the first of a series dedicated to Hype Driven Development. The goal will be to understand what are the correct use cases for some technologies and how to correctly use them (and what are the limits of said technologies).

Introduction: What are JWT

JWT (standing for JSON Web Tokens) are a type of tokens defined in RFC 7519 which contains both data and cryptographic signature allowing you to verify the origin of the token. They are nowadays pretty popular, mainly because they allow to identify a user with a stateless mechanism and are used in protocols like OpenID Connect. JWT can also be encrypted instead of signed: we will however not talk a lot about this kind of JWT here as they are less often used. In this article, we will refer to signed JWT only.

They are composed of 3 dot separated base64 encoded parts:

  • A JSON header, mainly consiting of telling which algorithm will be used for the signature
  • A JSON payload, containing everything you want, e.g. a user with its role, and some standard fields, like the expiration time or the name of the issuer
  • A signature built with the algorithm defined in the header, often a RSA or an symmetric HMAC.

Here is a simple example:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Which will be interpreted as:

Header

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

Body

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

Here, the header tells us that we indeed have a JWT signed using HMAC SHA256. The body tells us that it refers to the user 1234567890 using the standard field sub, that it as been issued the 2018-11-25 ta 11:52:54 PM (using the standard iat header) and that the user is named John Doe.

If we send back this token to the server, your API would be able to check that it has not been altered using the signature, so even by changing the sub field I would not be able to trick the server into thinking I am a different user.

In the case of an asymmetric signature, another server could even be able to check that the correct authentication server emitted the token.

However, I often see people comparing JWT to session cookies, and it is half wrong.

JWT are the stateless equivalent of traditional session tokens but still need some way of transport and client-side storage. Cookies can still be used for that (and in fact, you should really consider cookies for a web app, you do not even have to care about CSRF).

JWT can also be stored using local storage and sent using authorization bearer header, but so does session tokens. JWT are NOT opposed to cookies, but stateful tokens.

Their limits

Okay, now we know JWT, and you probably want to switch all your opaques session tokens to JWT. But wait a second, even if they are hyped, JWT do not fit all use cases!

We will not talk about some issues of the JWT standard as they are mostly handled by libraries (and you should use an up-to-date library to use JWT anyway).

First of all, JWT are meant  to be stateless, which is great, even more because everyone want to build REST APIs, but it also means you cannot revoke such a token. Well, the truth is, you could, but then you will lose all the interrest of using a JWT.

Here what a standard opaque stateful token looks like

f0e0f2ea7a3eccc03cb047ea884c79717f7fe5efee0b08267f0259283eedc74f

Here what a simple, yet still stateful (because of the lack of a lot of informations needed to make it stateless), JWT

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.TCYt5XsITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUcX16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtjPAYuNzVBAh4vGHSrQyHUdBBPM

Of course, the second one will have a worst impact on requests, especially on mobile connection.

If you use your tokens in a stateful way (using a whitelist or a blacklist), you should never consider JWT.

How to correctly use them?

Okay, so you have an API, you want to use JWT and you will use them in a stateless fashion because you do not want to handle sticky sessions or a database to store session (even if, in most cases, you will still need one, but I will explain everything to you ?).

Because you cannot revoke token, you will need to put a expiration time, and you want to keep it short. You could emit JWT without expiration time (or really long ones, like 10 years) but if any token leaks, then you will have an issue: you will not be able to differentiate legitimate and leaked token anymore. You do not want that.

Depending on the situation, the expiration time of a token should be between around 10 minutes and 4 hours. Once this period of time over, the client need to authenticate again. But by doing this, we trade ergonomy for security, we often want both.

We therefore need a second token: a refresh token, but this one will not be a JWT but a standard opaque, stateful, token. This one can have a longer lifespan and will be used by the client to ask for a new JWT token (which will be called access token). Because they are stateful, refresh token can be revoked.

By using a mix of access and refresh token, you are able to control who can call your API. Remember that because access token cannot be revoked, even by blacklisting a refresh token, a client can still use your API until his access token expire (and that is why you want to keep their lifespan short).

You might wonder, what is the point of using a stateful token? Your API is not stateless anymore! What you can do, however, is split your API in two parts:

  • The first part will be the core of your API, they take access token to authorize clients and contains most of your logic. This part is stateless.
  • The second part will be your authentication API, that will emit access and refresh token in exchange for credentials or valid refresh tokens, this part is stateful (at least for the refresh part).

Wrap up

JWT are nice, albeit not perfect but mostly require more work than just session with no additional value in most cases. You should really consider using session in most case and using JWT only when you encounter issues, like having to handle sticky sessions.