Signing and Validating JSON Web Tokens (JWT) For Everyone
Tags: jwt, identity, security, webdev
Published: 2020-09-27 21:17:18

When I started learning about [JSON Web Tokens](https://jwt.io/introduction/), there were some things that were straightforward to understand — _and_ some concepts that felt like _"hidden secrets"_ of JWT lore. 🧙‍♂️ 

This article aims to _demystify signing and validating JSON Web Tokens_, with little need for security or cryptography knowledge.

> _**Note:** This article is a companion to my post on [Authorization and Authentication for Everyone](https://dev.to/kimmaida/authorization-and-authentication-for-everyone-27j3). I recommend that you read that post first._

# JSON Web Token (JWT) Recap

JWTs are — in general terms — reasonably approachable. Information about them is readily available from many sources, chiefly covering:

* JSON Web Tokens (or JWT) are a **compact, URL-safe way to transfer pieces of data between two parties** (such as an [authorization server](https://dev.to/kimmaida/authorization-and-authentication-for-everyone-27j3#authorization-server) and an application).
* The JWT format is defined by [IETF](https://ietf.org/) specification [RFC 7519](https://tools.ietf.org/html/rfc7519) and is **composed of three segments** ([a _header_, a _payload_, and a _crypto_ segment](https://dev.to/kimmaida/authorization-and-authentication-for-everyone-27j3#json-web-token-jwt).
* JWTs are **_signed_ with a key** when they are generated and then **_validated_ with a key** upon receipt so we can verify that they _haven't been modified in transit_.

# The Challenge with Understanding JWT

There's a meme about being introduced to a concept and then there are steps missing while you're expected to be able to get to the end result without knowing the steps in between. The meme demonstrates "How to draw an owl":

![1. "Draw some circles." 2. "Draw the rest of the &$%# owl"](https://dev-to-uploads.s3.amazonaws.com/i/y9q9pnwz72fwddhk09ls.jpg)

To me, not being able to find approachable information about _signing and validating_ JWT felt like the missing steps to draw the owl.

Most of the resources I dug up took me deep down the rabbit hole — until my head was swimming with mind-melting jargon, [Alices and Bobs](https://en.wikipedia.org/wiki/Alice_and_Bob) (placeholder names used in cryptography examples), and complex maths. Instead of learning simpler, incremental steps to aid in my understanding, it felt like I was being given ten more complex, complete owl drawings.

# Why _Don't_ We Need to Know How Signing and Validation Work?

Why is this? Why do most JWT resources simply say _"and then you sign and validate"_ and leave it at that?

Think of it this way: for human beings to be effective or skilled with a tool, we don't need to know the intricacies of the tool's components.

🚙 When you get into your car to drive to the grocery store, do you need to know how internal combustion works? You don't. 

🔋 When you charge your laptop, do you need to know what chemical reactions take place in a lithium ion battery to create the flow of electrons in a circuit to store and produce energy? Nope!

We can still be good drivers or great computer programmers without intimate knowledge of these things. We trust that the manufacturers have used their expertise, specifications and standards, and due diligence to make useful tools for us to be more effective at the jobs we need those tools for.

This is why **_you don't need to know the exact process for signing and validating JWT in order to effectively use them_** for authenticating and authorizing your applications and APIs.

Okay, but you're reading this because you still want to know the missing steps to draw the owl. While you generally should not sign and validate tokens _yourself_ (seriously, _leave this to the experts_ — identity providers and [Identity-as-a-Service](https://auth0.com) platforms!), knowing how it works can be helpful in making you feel more _comfortable_ with using JWTs. 😌

# Anatomy of a JSON Web Token

We covered the [anatomy of JWT in depth in the previous blog article on authentication and authorization](https://dev.to/kimmaida/authorization-and-authentication-for-everyone-27j3#json-web-token-jwt), but let's do a _very brief_ recap.

JSON Web Tokens are composed of three URL-safe string segments concatenated with periods `.`

## Header Segment

The first segment is the **header segment**:

`eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9`

The header segment is a JSON object containing a signing algorithm and token type. It is [`base64Url` encoded](https://tools.ietf.org/html/rfc4648#section-5) (byte data represented as text that is URL and filename safe).

Decoded, it looks something like this:

```json
{
  "alg": "RS256",
  "typ": "JWT"
}
```

## Payload Segment

The second segment is the **payload segment**:

`eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0`

This is a JSON object containing _[data claims](https://dev.to/kimmaida/authorization-and-authentication-for-everyone-27j3#claims)_, which are statements about the user and the authentication event. This is the information that the JWT is conveying from one entity to another. Data claims might look something like this:

```json
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022
}
```

This is also `base64Url` encoded.

## Crypto Segment

The final segment is the **crypto segment**, or **signature**. JWTs are signed so they can't be modified in transit. When an [authorization server issues a token](https://dev.to/kimmaida/authorization-and-authentication-for-everyone-27j3#authorization-server), it signs it using a key.

When the client receives the ID token, the client **validates the signature** using a key as well. (If an asymmetric signing algorithm was used, different keys are used to sign and validate; if this is case, only the authorization server holds the ability to sign tokens.)

# The Rest of the ~~Owl~~ Signature

This is where the missing steps of the ~~owl~~ JWT signing / validation process are. Let's go through it step-by-step. 

## RS256 Signature

For this article, I'm going to assume use of an RS256 signing algorithm. RS256 is an RSA [Digital Signature](https://en.wikipedia.org/wiki/Digital_signature) Algorithm with [SHA-256](https://www.movable-type.co.uk/scripts/sha256.html). RSA256 is an Asymmetric Key Cryptography algorithm, which uses a pair of keys: a public key and a private key to encrypt and decrypt. In this case, the private key is used by the token issuer (authorization server), and the public key is used by the application receiving the token in order to validate it.

If this feels jargon-laden and confusing right out of the gate, don't worry! Let's break it down into smaller, distinct steps.

# The JWT Crypto Segment: Revisited

Let's explore what the crypto segment _actually is_. 

## Signing Input

First we take the first two segments of the JWT (the header and the payload). In practice, that looks something like this:

![header + payload segments](https://dev-to-uploads.s3.amazonaws.com/i/zpdq7s71y1in9s03n4wv.png)

In other words, this is the `base64Url` encoded header and the `base64Url` encoded payload, concatenated with a `.` period:

![base64 URL encoded header + payload segments](https://dev-to-uploads.s3.amazonaws.com/i/8mhapuw3p0l8rlit2md7.png)

This is what we call the **signing input**.

## Hashing

We then **hash the signing input** using the [SHA-256 hashing algorithm](https://www.movable-type.co.uk/scripts/sha256.html). Hashing converts one value into a different value. A _hash function_ uses a mathematical algorithm to generate a new value from an existing one.

* Hashing is irreversible. Once we have hashed an input, we _cannot_ get back to the original input again.
* Hashing will always produce the same output for the same input.
* No two different hashing inputs will produce the same output.

![SHA-256 hashed signing input](https://dev-to-uploads.s3.amazonaws.com/i/9vjn572h31htdlfixvqg.png)

At this point, we have a hash of the header and payload segments — which we could compare to other hashes, but _cannot_ reverse to return to the original signing input.

## Encryption

Next we **encrypt** the hashed signing input. Unlike hashing, encryption _is reversible_: we can _decrypt_ encrypted results (called ciphertext) to decipher the original input (plaintext).

For this step, the _token issuer_ (authorization server) scrambles the [hashed signing input](#hashing) using a **private [encryption key](https://medium.com/codeclan/what-are-encryption-keys-and-how-do-they-work-cc48c3053bd6)** to produce an output (ciphertext).

> _**Note:** I mentioned earlier that this example uses RSA, which is an asymmetric signing algorithm and uses one key to encrypt tokens, and another key to decrypt them. To learn more about this topic in an approachable, practical way, check out [Public Key Cryptography by Computerphile on YouTube](https://www.youtube.com/watch?v=GSIDS_lvRv4)._

This final output (the hashed, encrypted, encoded header and payload) is the **crypto segment** — or _signature_ — of the JWT.

![Encrypted, hashed signing input](https://dev-to-uploads.s3.amazonaws.com/i/39wpzam9gk0c519q97hw.png)

> _**Note:** If you'd like to dig much deeper into specifics of the RSA encryption algorithm itself, I recommend these great YouTube videos from [Eddie Woo](https://www.youtube.com/channel/UCq0EGvLTyy-LLT1oUSO_0FQ): [The RSA Encryption Algorithm](https://www.youtube.com/watch?v=4zahvcJ9glg)._

There you have it. That's the signature of a JSON Web Token. 🎉

# Validating the Signature

Okay, we can start to understand how the token was signed — but that's only half of the story! The entire point of signing the token is so that whoever _receives_ the token can validate that this JWT contains data that hasn't been tampered with.

How do applications validate JWTs?

## What Are We Working With?

First, let's look at what information is available to the application that receives the token. We have access to the JWT itself: the _header_, the _payload_, and the _signature_ (aka, the crypto segment). We also have access to a _public key_, which — as per its moniker — is freely available to the world.

> _**Note:** How are public keys made available? [JSON Web Key (JWK) RFC 7517](https://tools.ietf.org/html/rfc7517) defines a specification for JSON representation of a cryptographic key. If you use an authorization server platform, the public key will be provided — and often helpfully encapsulated in an SDK or library that handles JWT validation for you. You can read more in this blog article: [Navigating RS256 and JWK](https://auth0.com/blog/navigating-rs256-and-jwks/)._

Remember that the signature is the _encrypted, hashed header and payload_. Hashing is irreversible, but encryption can be _decrypted_ (in this case, with the public key). Validation of the JWT is about getting to a point where we can effectively compare _what we received_ to _what we expect_.

## Decode Claims

The application can decode the header and payload to get some information. Recall that these two segments are `base64Url` encoded to make them URL safe. There is nothing cryptographically magical or secure about decoding these segments; in fact, you can do so with a [simple online base64 decoding tool](https://www.base64decode.org/). Once they're decoded, we can easily read the information in them. For instance, we could decode the [header segment](#header-segment) to see what algorithm the JWT says it was signed with.

On the other hand, the _signature_'s purpose is to _validate_ that the information in the other segments is the same information that the authorization server sent — and that it hasn't been changed along the way.

From the decoded header, we can see:

```json
{
  "alg": "RS256",
  "typ": "JWT"
}
```

Our received token says that the algorithm is RS256. Our application should be configured to expect the algorithm that our authorization server (token issuer) uses. When we read the algorithm in the JWT's header, we should verify that it matches our _configured expectation_. If it doesn't match, we should reject the token outright.

## Hashing (Again)

If the algorithm in the token matches our expectation of RS256, we know we need to generate the SHA-256 hash of the header and payload segments. This will reproduce the signing input hash (again). Remember that hashing is irreversible, but the same input will always produce the same output. If we generate the hash from the header and payload we received, it _should_ match the header+payload hash that is encrypted in the signature.

Therefore, we will hash the concatenated, `base64Url` encoded header and payload. Now we have the signing input hash freshly calculated on the _application_ side.

## Decryption

The hashed signing input is also in the signature, but it's been encrypted by the authorization server (token issuer) with a private key. The application has the public key, so we can _decrypt_ the signature. Once this is done, we have access to the _original_ hash: the one generated by the authorization server when the token was first generated.

## Compare Hashes

Now we can **compare the _decrypted_ hash to the _calculated_ hash**. If they are the same, then we've verified that the data in the JWT header and payload segments has not been modified between the time the authorization server created the token and the time our application received it. 🎊

## + Verifying Token Claims

Once we've validated the signature, there's [more to verifying the JSON Web Token's data](https://dev.to/kimmaida/authorization-and-authentication-for-everyone-27j3#authentication-with-id-tokens). Claims in the payload segment should _also_ be validated, because they contain information about the [token issuer, token expiration, intended audience for the token, information binding the token to the authorization request](https://dev.to/kimmaida/authorization-and-authentication-for-everyone-27j3#authentication-claims), and more.

This data gives the receiving application vital details that the signature validation alone does not. For instance, examination of claims can reveal that a technically valid token was actually intended for a different application or user, has expired, came from an issuer that the application has no affiliation with, etc.

# JWT Signing & Validation: Wrapping Up

We've now covered signing JWT and validating JWT signatures.

![JWT crypto segment and validation](https://i.imgur.com/S49APmt.gif)

My hope is that you feel confident your understanding of JWT signatures and validation has a few more steps filled in now:

![Owl with all steps](https://dev-to-uploads.s3.amazonaws.com/i/1d70gc3c25ht8wutxtv8.png)

It's still important to reiterate that, as a developer, **you most likely will never need to _implement_ these processes yourself**. And in fact, unless your engineering focus is security and identity, you probably _shouldn't_.

Identity platforms like [Auth0](https://auth0.com), [Okta](https://okta.com), [Ping Identity](https://pingidentity.com), and more _do all of this for you_: issuing and signing tokens on the authorization server side, and providing SDKs and libraries for validation and token management on the application or API side.

---

# Resources and What's Next?

As I mentioned at the beginning, this article is a companion and supplement to [Authorization and Authentication for Everyone](https://dev.to/kimmaida/authorization-and-authentication-for-everyone-27j3), which is a much more comprehensive resource on the history of OAuth, OpenID Connect, authorization servers, JSON Web Tokens, API authorization, delegation with scopes, and more. Please check it out if you'd like to go further into identity topics.

## Learn More

In an effort to create a digestible introduction to signing and validating JWTs that is widely approachable (and is the introduction I wished _I'd_ had), I have simplified topics that are incredibly rich and complex.

🧠 To learn much more, try starting with some of the following resources:

* [Public Key Cryptography](https://www.youtube.com/watch?v=GSIDS_lvRv4)
* [What Are Encryption Keys and How Do They Work?](https://medium.com/codeclan/what-are-encryption-keys-and-how-do-they-work-cc48c3053bd6)
* [The RSA Encryption Algorithm - Part 1](https://www.youtube.com/watch?v=4zahvcJ9glg)
* [The RSA Encryption Algorithm - Part 2](https://youtu.be/oOcTVTpUsPQ)
* [Learn Identity](https://auth0.com/docs/videos/learn-identity)
* [JWT.io](https://jwt.io)

## Thank You!

If you'd like to chat, I'm available on Twitter at [@KimMaida](https://twitter.com/KimMaida), and I also speak at [conferences and events](https://github.com/kmaida#-events) — at least, I did before COVID-19. I hope to see you sometime, and **thank you so much for reading**!