Simple Intro to JWT Basics
Tags: jwt, security, webdev, beginners
Published: 2019-09-28 17:30:11

If you have been put off learning about JWT (JSON Web Tokens) because they sound scary or complicated, I have good news; **they really aren't**. In this short simplistic guide, I'll walk through the basics of JWT, what makes them unique, and their strengths and shortcomings compared to other forms of authentication.

# Intro - What ***is*** a JWT?
JSON Web Tokens, or JWTs, are a 'stateless' (more on this later) approach to authentication and session management, where the information about the auth or session (is user admin? Permissions? Etc.) can be stored ***within*** the token itself, rather than on the server.

Essentially, you can think of JWT as a **container** full of **truths** that the server has sent (these are called *claims* in JWT terms), and metadata about how these "truths" are stored (the algorithm and type).

In the most practical terms, a JWT can be represented as a single string, which you will see later.

# Stateless? What does that mean?
JWTs are not *always* part of a stateless system, but the way they are composed lends them to that sort of setup.

With a typical non-JWT system, if you want to handle authentication and different permissions for different people, you usually use a combination of sessions and server-side storage - this would be your ***state***. When a user logs in, you create a new `session` for them, with a unique ID, and to check permissions, you lookup their user ID against a permissions table and/or roles table. Each page that you load might require multiple DB lookups, to check for a valid session, then get roles, then get permissions, etc.

By contrast, with JWT, all the information about both the validity of the user (being logged in) and their role and/or permissions, is contained ***directly within the JWT string itself***. The server, upon receiving an incoming JWT, simply has to verify that it is valid, but doesn't necessarily have to do any database lookups. This can make it stateless.

There are downsides to the this approach however, which will be discussed later.

# Breaking it down further - the parts of a JWT
JWTs can seem overwhelming, so let's break them down part by part:
## What do they actually look like?
First, you might be wondering what a JWT actually looks like. Well, the final string that is sent from the server to the client, to be stored in `localStorage`, `sessionStorage`, or a cookie, can look like this (real example):
```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiQm9iYnkgVGFibGVzIiwiaWF0IjoxNTE2MjM5MDIyLCJpc0FkbWluIjp0cnVlLCJwZXJtaXNzaW9ucyI6eyJ1c2Vyc01ha2UiOnRydWUsInVzZXJzQmFuIjp0cnVlLCJ1c2Vyc0RlbGV0ZSI6ZmFsc2V9fQ.HFRcI4qU2lyvDnXhO-cSTkhvhrTCyXv6f6wXSJKGbFk
```
Enlightening, huh? Well, it's a lot less scary once you find out this is all it is:
```
base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(signature)
```

Let's break it down further...

## The pieces
As you saw above, the JWT is made up of three major components, each of which is base64 encoded (with the [web-safe variant](https://en.wikipedia.org/wiki/Base64#RFC_4648), to avoid characters that could screw up a URL) before being joined together. Each of these components, except the signature, is also a JSON object before encoding, but more on that below:

#### Header:
The header is the part that contains the *metadata* about the JWT itself. At the bare minimum, this will contain the type of algorithm used to encrypt the signature, but sometimes also contains extra metadata, like the type of token itself (`JWT`).

Example:
```json
{
  "alg": "HS256",
  "typ": "JWT"
}
```
In this example, the header is saying "Hey, I'm a token of type JWT, with an encryption algorithm of HS256!"

#### Payload:
The payload is really the most important part in terms of functionality, not security. The payload contains the `claims` (or *truths* as I previously called them), that the server is saying belong to whomever holds the JWT and can send it back to the server.

When the user sends the JWT *back* to the server, via a header, URL, cookie, etc., the server decodes the payload and can use it in thousands of ways; for example, by allowing the user to make a "delete" action because one of the claims is that they are an admin.

Example payload:
```json
{
  "name": "Bobby Tables",
  "iat": 1516239022,
  "isAdmin": true,
  "permissions": {
     "usersMake": true,
     "usersBan": true,
     "usersDelete": false
  }
}
```

There are no mandatory key-pairs that your payload must have, although there are some that are standardized and common. For example, `iat` is a registered claim for `issued at`, and if included, must be a number representing the timestamp the JWT was issued. You should avoid conflicting with reserved/registered claim names. You can read more about them in the original spec, [here](https://tools.ietf.org/html/rfc7519#section-4).

> Reminder: You should try to keep both keys and values short, since JWT is designed to be small.

#### Signature:
The signature of a JWT is the most important part when it comes to security. Essentially it is the value of the header + payload, put through a one-way encryption hashing function that uses a *secret* that ***ONLY*** the server or other trusted entities know.

If you base64 decode the value, it looks like gibberish, because it is a secure hash:
```
.T\#..Ú\¯.uá;ç.NHo.´ÂÉ{ú.¬.H..lY
```

The pseudo code to generate this hash, on the server, looks something like this:
```
HMACSHA256(
  base64Url(header) + "." +
  base64Url(payload),
  SECRET_KEY
);
```

The signature is a way for the server to, using its secret key**, validate that the JWT a user sends it is both valid, and created by itself or trusted creator.

(PS: The secret key I used throughout my examples here was `krusty-krab-krabby-patty-secret-formula`).

> ** = If using *asymmetric encryption*, you can use public key to validate. See "Signing Algorithms" subsection under "How is it secure?" section. 

## Breakdown summary - putting it back together
So, to summarize and show how these parts fit together once again, we are taking:

```js
const header = {
  "alg": "HS256",
  "typ": "JWT"
};

const payload = {
  "name": "Bobby Tables",
  "iat": 1516239022,
  "isAdmin": true,
  "permissions": {
     "usersMake": true,
     "usersBan": true,
     "usersDelete": false
  }
};
```

...making a signature by using a one-way encryption algo...
```js
// Pseudo code
const signature = hashHS256(header, payload).withSecret(SECRET_KEY);
```
...and finally joining the parts together into a single string, after base64'ing each part:
```js
// Pseudo code
const jwtString = base64Url(header) + '.' + base64Url(payload) + '.' + base64Url(signature);
```

# How is it secure?
The security mechanism of JWT rests in its signature component (outlined above). To break it down further, when a user sends a JWT back to the server, the way the server checks to make sure that the claims should be trusted, is by validating the signature through:
 1. Take incoming header and payload
 2. Add `SECRET_KEY` that only the server and validator(s) know**
 3. Put header, payload, and secret, through one-way encryption hash
     - This creates a server-generated signature
 4. Check that the newly created signature matches the one sent in the JWT by the user
 5. If they match, that proves that the JWT the user sent was indeed created with the same *secret* owned by the server!

Please note that the strength of the security is strongly linked to your secret key - use a suitably long key (to [avoid brute force attempts](https://auth0.com/blog/brute-forcing-hs256-is-possible-the-importance-of-using-strong-keys-to-sign-jwts/)) that is never shared.

> Side note: In *addition* to validating signatures, servers often also validate JWTs by checking that they conform to the expected structure and standards. See [this auth0 guide](https://auth0.com/docs/tokens/guides/jwt/validate-jwt) for details.

> ** = or public key, if using *asymmetric* encryption, see below.

## Signing Algorithms

In these examples, I'm using HMAC, which is a *symmetric algorithm*, meaning that there is only one private key and no public key. In order for more than one party to be able to create *or* validate a JWT, they must have the secret key.

With an *asymmetric algorithm*, a secret key is still used to *create* tokens, but a public key can also be used to confirm validity. This means that another server could create the JWT, and your server could still validate it by checking against the public key, without needing to share the private/secret key. This method is often preferred because it is a way for multiple parties to be able to validate, while only those with the private key can actually create tokens.

I won't get any further into the details here, since this is supposed to be an intro, but you can read more [here](https://auth0.com/docs/tokens/concepts/signing-algorithms).

# Downside to JWT: Logging users out / invalidating tokens
So far, JWTs seem like they have numerous benefits over stateful authentication methods, but something we have not yet discussed is logging users out, deleting users, or otherwise invalidating or revoking tokens.

The truth is, this is where JTWs fall short. In order to invalidate a JWT, you *need* to have some sort of database / stateful system, because what you end up doing is maintaining either a blacklist or a whitelist.

With a blacklist, whenever you want to invalidate a token, you would add it to the blacklist table, and whenever a user tries to use a JWT, you would always need to check that it is not on the blacklist.

With a whitelist, it is basically the same thing, but add every token to the whitelist as it is created, and remove it from the whitelist when invalidating. And every incoming JWT would only be accepted if it *is* on the whitelist.

If you have to use either of these approaches, in my opinion that is symptomatic of your needs not aligning with what JWTs can provide, and it might be time to rethink your websites architecture to see if there is not a better alternative.

## Avoiding state: Auto-expiring sessions
A pretty common workaround for sites avoiding having to implement a stateful JWT system for logging out users is to just auto-expire tokens quickly.

For example, you could either put the creation time of the JWT inside of its own payload, and/or the planned expiration time. Then, when validating incoming JWTs, simply check if the expiration time is earlier or equal to the current time - if so, reject the JWT.

The problem with this is that it is still a bit of a stop-gap solution and can end up being *more* complicated than just using sessions in the first place. In order to not have users getting constantly logged out while actively using the site (annoying!), you would need to use auto-refreshing JWTs, probably through a service like [Auth0's Refresh Tokens](https://auth0.com/docs/tokens/refresh-token/current). This still doesn't allow for a manual log-out flow, unless you also introduce revoking as part of the refresh pattern.

## Avoiding state: Lazy invalidation
Imagine that you need to substantially upgrade your user management system, and force everyone to switch. A workaround that is unfortunately suggested by a lot of devs online, but is less than ideal, is to... change your private key secret. If you do that, you *immediately* invalidate ***all*** JWTs in circulation and force everyone to login again, since the signature portion of everyones' JWTs will no longer match.

# Note on complexity, vulnerabilities, and more:
There is still lots to JWT that I have not covered fully in this post (it's supposed to be an intro, in my excuse). The reality is that many developers use a third party service (aka a *Federated Identity Management* service), such as [Auth0](https://auth0.com/blog/why-identity-federation-matters/), to manage the majority of the JWT stack. This won't magically solve many of the issues I've outlined with JWT, but it will make working with them easier and abstract some of the complexity and security concerns.

---

# Additional resources:
What | Type | Link
--- | --- | ---
Wikipedia page - surprisingly dev focused | Wiki | [Wiki En](https://en.wikipedia.org/wiki/JSON_Web_Token)
RFC spec from IETF | Spec | [RFC #7519](https://tools.ietf.org/html/rfc7519)
JWT Debugger, Libraries, & More | Playground & Quick Ref | [jwt.io](https://jwt.io/)

---

PS: If you enjoyed how this guide was written, you might like some of my other cheatsheets and quick reference guides. I've been working on collecting and showcasing them [here](https://cheatsheets.joshuatz.com/).