What is a JWT – JSON Web Token?

A JSON Web Token is an encoded string of characters that allows users to identify themselves when interacting with an API.

Why do you need a token?

Because APIs manage their connections in a different way than regular web applications do.

A web app typically relies on stateful connections. This means that when a user logs into a web app or web site, the app will open a session on the server for this user. Sessions allow the server to track users as they navigate the site and interact with the site’s pages. The session maintains a user’s settings, shopping cart, etc.
Usually, the app will issue a cookie that the user’s browser will store locally and include in all subsequent requests sent to the web app. The app recognizes the cookie and understands who is connecting and which session relates to this user.

An API works differently. The typical REST APIs and GraphQL APIs you will come across use stateless connections. This means that no session is created for a given user and every request this user makes is treated as if it came from an unknown user.
Imagine you’re visiting an elderly relative with Alzheimer and every time you speak to them, you need to remind them who you are and how you are related to them. This is how you talk to an API. 😉

Now to avoid having to identify to the API every time you send a request, what will usually happen is that when you log in, using your username and password, the app will check your credentials and reply with a token.

Like a cookie, this token will be included in an authorization header in the following requests you send through the API. But unlike a cookie, the token will not link to an open session on the server. This means the token will need to be self sufficient and include all the information the API needs to understand who you are and what you’re allowed to do with the app.

Typically, once you have logged in and received a token, this token will be your way through the API and into the app for as long as the token is valid.

A JSON Web Token (or JWT) is just one type of token that is very often used by API providers.

What’s in a JWT?

A JWT is a long string of characters that looks like this:
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJlZHdAemVyb2RheWhhY2tlci5jb20iLCJpYXQiOjE2NjU3NTM4NTYsImV4cCI6MTY2NTg0MDI1Nn0.SbZ3F1kmuntmjy8aJQFj5xUZL_RelJE4bCfWAHUVzbfxyWGIzQhq5zx-CF3voRz3xxHWfY5H1GxjbdedRjQdfw

Notice there are three parts, separated by a period. Each part is a section of the token that contains specific information. Each of these sections is base64 encoded.

The first part is the header:
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9

Once the string is decoded, you will get something like this:
{
"alg": "HS512",
"typ": "JWT"
}

It’s a short JSON document that indicates which algorithm must be used to decrypt the token’s signature, which is the third part of the JWT (more on the signature in a few seconds). This is the value of the "alg" key.
The "typ" key indicates the type of token and is generally set to "JWT". It is mostly optional and many JWTs don’t even include this key in their header.

The second part is the payload:
eyJzdWIiOiJlZHdAemVyb2RheWhhY2tlci5jb20iLCJpYXQiOjE2NjU3NTM4NTYsImV4cCI6MTY2NTg0MDI1Nn0

This contains the data the API will read in order to decide if it lets you in or leaves you on the sidewalk. Typically, a decoded payload will look something like this:
{
"sub": "edw@zerodayhacker.com",
"iat": 1665753856,
"exp": 1665840256
}

In the example above, the "sub" key is the subject and can contain different types of data. "iat" represents the date and time at which the JWT was issued. "exp" represents the date and time the JWT will expire.
This section can contain pretty much anything the API provider may want to include, such as the user’s status (registered user, admin, etc), e-mail, or even password (bad idea though, as the content of a JWT is just a base64 decode away…).

Notice that both the header and the payload, in their encoded form, start with the characters ey. This will be the case with all JWTs.

The third part is the signature:
SbZ3F1kmuntmjy8aJQFj5xUZL_RelJE4bCfWAHUVzbfxyWGIzQhq5zx-CF3voRz3xxHWfY5H1GxjbdedRjQdfw

The decoded form will be similar to this:
HMACSHA512(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
MySuperSecret
)

The signature is here to ensure that a JWT is genuine. As we have seen, anyone can base64 decode the content of the JWT’s header and payload sections.
Without the signature, anyone could edit the payload, then re-encode it, paste it back into the JWT and use it to access the app like a teenager sneaking into a bar with fake ID on a Saturday night.

Creating a signature requires a keyword that typically only the API’s provider knows. In JWT lingo, this keyword is called a secret (MySuperSecret in the example above).

The signature is generated by taking the encoded header, the encoded payload, the secret, the algorithm specified in the header, and signing the lot.

If you open and edit the content of the payload of a signed JWT, the payload won’t match the content of the signature anymore and the JWT will bounce (as a hacker, you will often get the cold treatment from target APIs in the form of the dreaded ‘Invalid token’ response).

Bottom line, if you want to edit a JWT, you need to know the secret in order to regenerate the signature.

Note that you may come across unsigned tokens. These JWTs will only contain the first two sections, without the signature. They will have the "alg" key set to "none" in the header section (more on this in a later post).

How do you look inside a JWT?

There are several tools you can use to read and (for some of them) edit the content of a JWT.

The most basic is the base64 linux command.

Copy one of the sections of a JWT and run:
echo -n 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9' | base64 --decode

To re-encode a JSON string, run the opposite command:
echo -n '{"alg":"HS512","typ":"JWT"}' | base64

 

To take things further, move on to the JSON Web Token Toolkit (install it from here).
This command line tool written in Python lets you read the content of a full JWT (not just individual sections), scan for weaknesses, test for known exploits, modify the content and resign the token if you know the secret.
If you’re aiming for any serious JWT tampering, this tool should be at the top of your list.

 

Another great resource is jwt.io.
Just paste a JWT and the page will display the corresponding header and payload. If you know the secret, type it into the input field to resign a token you’ve modified. Now click the Share JWT button or just select and copy the token and you’re off to the races. Simple and effective.

 

If you like online tools, you can also check out CyberChef. Not quite as quick and easy as jwt.io, but if CyberChef is your go-to destination for your encoding / decoding tasks and you don’t want to spread yourself across too many tools, then it will do the job for you.

 

Finally, you may want to try out the JSON Web Tokens extension for Burp Suite (does work with Community Edition). Paste a JWT and the module will decode it for you and check if the secret you provide is valid.

Why do you need to know all this?

Using JWTs to filter incoming requests is a great way for an API provider to secure their app, by making sure users issuing a request to the API have been properly authenticated and authorized to access.

But for us hackers, manipulating JWTs is also a useful way to circumvent access restrictions, impersonate other users and gain privileged access to the API.

Now that you know what a JWT is, it’s time to learn how to manipulate it. In this next post I’m walking you through some ways you can crack the signature and craft your own rogue JWT.
Check it out!

And if you want the full story on JWT, you can download Sebastián Peyrott’s JWT Handbook (free) here for a more detailed and technical run down.

 

Hi! I'm a tech journalist, getting my feet wet in ethical hacking. What you will find here is me taking notes on the tools and techniques I’m learning and offering answers to the questions I had when I first got started not so very long ago.

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top