JSON Web Token (JWT): an introduction

For a long time, web cookies were the most common method for user authentication. Even now, this method works well for certain purposes. But sometimes more flexibility is required. That’s where JSON Web Token comes in. As a newer, more open standard, it’s being used increasingly by important websites and apps. Keep reading to find out what JWT is, how it works, and what it’s used for.

What is JSON Web Token?

A JSON Web Token (JWT) is an access token standardised according to RFC 7519, which makes it possible for two parties to securely exchange data. It contains all important information about an entity, meaning that no database queries are necessary and the session doesn’t need to be saved on the server.

JWT is especially popular in authentication processes. Its short messages can be encrypted and securely convey who the sender is and whether they have the necessary access rights. Users themselves only come into indirect contact with the token, for example, when they enter usernames and passwords into a mask. The real communication takes places between the client and the server.

How is a JWT generated?

A signed JSON Web Token consists of three parts, each of which are encoded using Base64 and separated by a point.

HEADER.PAYLOAD.SIGNATURE

Let’s look at each of these three parts in more detail.

Header

The header usually contains two parts and provides important information about the token. It contains the type of the token and the signing/encryption algorithm being used. For example, a JWT header can look as follows:

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

It is always recommended to use JWT as the type, which refers to the IANA media type “application/jwt.” In the above example, HMAC-SHA256 is used as the signing algorithm. Other common methods for encryption include RSA with SHA-256 (“RW256”) and ECDSA with SHA-256 (“ES256”). You should always use some kind of encryption. However, if the data really isn’t sensitive, you can enter “none” under encryption. Possible values are standardised by JSON Web Encryption based on RFC 7516.

In case of more complex signed or encrypted JWT, there’s the additional parameter “cty” for content type. It should also be filled with the value “JWT.” In all other cases, this parameter should be left out.

Payload

The payload field is where the information that will be transmitted to the app is located. In this part, there are defined standards that determine what and how certain data are transmitted. The information is presented as key/value pairs, and the keys are called “claims” in JWT. There are three different types of claims:

  • Registered claims are registered in the IANA JSON Web Token Claim Register. Their purpose is defined in a standard, for example “iss” for the issuer of the token, “aud” for the audience, and “exp” for the expiration time of the token. In order to keep the length of tokens as short as possible, short names are used for claims.
  • Public claims can be defined at will by the user. However, to avoid collisions in the semantics of the keys, the claims should be registered in the IANA JSON Web Token Claim Register or use collision-resistant names.
  • Private claims are used for the customised sharing of information. While public claims contain information like names and email addresses, private claims are more unique. Typical information that’s encoded using private claims include user IDs or concrete department names. When naming private claims, it’s important to make sure that a collision with registered or public claims is avoided.

All claims are optional, meaning that you don’t have to use every registered claim. In general, payloads can contain as many claims as you want, but it’s recommended to limit the information you include to what’s really necessary. The larger the JWT, the more resources it will require for encoding and decoding.

A payload could look as follows:

{ "sub": "123", "name": "Alice", "exp": 30 }

Signature

The signature of a JSON Web Token is created using the Base64 coding of the header and payload and the indicated signing algorithm. The structure is determined by the JSON Web Signature (JWS), which is standardised based on RFC 7515. In order to ensure that the signature works, it’s necessary to use a secret key that is only known to the issuing app. The signature verifies that nothing was changed in the message along the way. In the case of a token that was signed with a private key, it also ensures that the sender is who they claim to be.

Depending on how sensitive the data is, there are various possibilities:

  • No security: As mentioned above, if the data is not at all sensitive, the value “none” can be given in the header for the type of encryption. In this case, no signature will be generated. The JSON Web Token will then only consist of header and payload. Without any security, the payload can be read in plain text after Base64 decoding, and there is no way to verify if the message is coming from the correct sender or if it was altered along the way.
  • Signature (JWS): Generally, it’s enough to check whether the data is coming from the correct sender and whether it was altered. This is where the JSON Web Signature comes in, which ensures that the message wasn’t changed along the way and that it’s coming from the right sender. In this case, the payload can also be read in plain text after Base64 decoding.
  • Signature (JWS) and encryption (JWE): It’s also possible to use JSON Web Encryption (JWE), in addition to JWS. JWE encrypts the content of the payload, which is then signed with JWS. In order to decrypt the content, a password or private key is required. The sender is then verified, the message is ensured to be confidential and authentic, and the payload can’t be read in plain text after Base64 decoding.

Thanks to the encryption, you’ll be left with a seemingly random stream of characters:

{ 7WK5T79u5mIzjIXXi2oI9Fglmgivv7RAJ7izyj9tUyQ }
Note

No matter which of the above-mentioned security options you use, you should also use SSL for communication, in order to protect the data.

How do JSON Web Tokens work?

Let’s use the example of a user login to illustrate the workings of JSON Web Token. Before using a JWT, you’ll have to define a secret key (“secret”). As soon as a user has successfully entered their login information, the JWT will be returned with the key and saved locally. This transfer should take place over HTTPS to ensure that the data is protected.

Whenever the user wants to access protected resources, for example an API, or a protected path, the JWT will be sent as a parameter or authorisation header from the user agent. The communication partner can decrypt the JSON Web Token and carry out the query after a successful evaluation.

Note

Since you’re dealing with login data, you shouldn’t keep a token longer than you need to and shouldn’t store any sensitive data in your browser memory.

What are JWTs used for?

Compared with traditional options for authentication and authorisation with cookies, JWTs come with several advantages. This has led to their popularity in contexts like the following:

  1. REST applications: Rest applications ensure stateless protocols, since the information for the authentication is sent with the request.
  2. Cross-Origin Ressource Sharing: JWTs send information as a part of cross-origin resource sharing. This has a huge advantage over cookies, which generally cannot be sent as a part of this process.
  3. Use in various frameworks: JWT is standardised. If you’re using various frameworks, data related to authentication can be more easily shared.

What does a JWT example look like?

Using a JWT example, let’s take a look at how the token turns out in the end. First, let’s take the header example from above:

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

Next, an example of the payload could be as follows:

{
	"sub": "0123456789",
	"name": "John Doe",
	"admin": true
}

In order to get to the actual structure of a JWT (three parts separate by periods), the header and the payload need to be coded with Base64. For the header, this will look as follows:

base64Header = base64Encode(header)
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

And for the payload, it will turn out like this:

base64Payload = base64Encode(payload)
// eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

Now the signature has to be created. In the header, we indicated that HMAC-SHA256 should be used:

signature = HS256(base64Header + '.' + base64Payload, 'secret')
// dyt0CoTl4WoVjAHI9Q_CwSKhl6d_9rhM3NrXuJttkao

Finally, these three parts have to be put together and separated by a period:

Token = base64Header + '.' + base64Payload + '.' + signature
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.dyt0CoTl4WoVjAHI9Q_CwSKhl6d_9rhM3NrXuJttkao

Most programming languages have a library for generating JSON Web Tokens, meaning that it’s no longer necessary to do it manually.

Was this article helpful?
Page top