For a long time, web cookies were the most common method for user au­then­tic­a­tion. Even now, this method works well for certain purposes. But sometimes more flex­ib­il­ity is required. That’s where JSON Web Token comes in. As a newer, more open standard, it’s being used in­creas­ingly 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 stand­ard­ised according to RFC 7519, which makes it possible for two parties to securely exchange data. It contains all important in­form­a­tion about an entity, meaning that no database queries are necessary and the session doesn’t need to be saved on the server.

JWT is es­pe­cially popular in au­then­tic­a­tion processes. Its short messages can be encrypted and securely convey who the sender is and whether they have the necessary access rights. Users them­selves only come into indirect contact with the token, for example, when they enter usernames and passwords into a mask. The real com­mu­nic­a­tion 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 in­form­a­tion about the token. It contains the type of the token and the signing/en­cryp­tion algorithm being used. For example, a JWT header can look as follows:

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

It is always re­com­men­ded to use JWT as the type, which refers to the IANA media type “ap­plic­a­tion/jwt.” In the above example, HMAC-SHA256 is used as the signing algorithm. Other common methods for en­cryp­tion include RSA with SHA-256 (“RW256”) and ECDSA with SHA-256 (“ES256”). You should always use some kind of en­cryp­tion. However, if the data really isn’t sensitive, you can enter “none” under en­cryp­tion. Possible values are stand­ard­ised by JSON Web En­cryp­tion based on RFC 7516.

In case of more complex signed or encrypted JWT, there’s the ad­di­tion­al 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 in­form­a­tion that will be trans­mit­ted to the app is located. In this part, there are defined standards that determine what and how certain data are trans­mit­ted. The in­form­a­tion is presented as key/value pairs, and the keys are called “claims” in JWT. There are three different types of claims:

  • Re­gistered claims are re­gistered 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 ex­pir­a­tion 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 col­li­sions in the semantics of the keys, the claims should be re­gistered in the IANA JSON Web Token Claim Register or use collision-resistant names.
  • Private claims are used for the cus­tom­ised sharing of in­form­a­tion. While public claims contain in­form­a­tion like names and email addresses, private claims are more unique. Typical in­form­a­tion that’s encoded using private claims include user IDs or concrete de­part­ment names. When naming private claims, it’s important to make sure that a collision with re­gistered or public claims is avoided.

All claims are optional, meaning that you don’t have to use every re­gistered claim. In general, payloads can contain as many claims as you want, but it’s re­com­men­ded to limit the in­form­a­tion 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 de­term­ined by the JSON Web Signature (JWS), which is stand­ard­ised 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 pos­sib­il­it­ies:

  • 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 en­cryp­tion. 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 en­cryp­tion (JWE): It’s also possible to use JSON Web En­cryp­tion (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 con­fid­en­tial and authentic, and the payload can’t be read in plain text after Base64 decoding.

Thanks to the en­cryp­tion, you’ll be left with a seemingly random stream of char­ac­ters:

{ 7WK5T79u5mIzjIXXi2oI9Fglmgivv7RAJ7izyj9tUyQ }
Note

No matter which of the above-mentioned security options you use, you should also use SSL for com­mu­nic­a­tion, in order to protect the data.

How do JSON Web Tokens work?

Let’s use the example of a user login to il­lus­trate 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 suc­cess­fully entered their login in­form­a­tion, 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 au­thor­isa­tion header from the user agent. The com­mu­nic­a­tion partner can decrypt the JSON Web Token and carry out the query after a suc­cess­ful eval­u­ation.

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 tra­di­tion­al options for au­then­tic­a­tion and au­thor­isa­tion with cookies, JWTs come with several ad­vant­ages. This has led to their pop­ular­ity in contexts like the following:

  1. REST ap­plic­a­tions: Rest ap­plic­a­tions ensure stateless protocols, since the in­form­a­tion for the au­then­tic­a­tion is sent with the request.
  2. Cross-Origin Ressource Sharing: JWTs send in­form­a­tion 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 frame­works: JWT is stand­ard­ised. If you’re using various frame­works, data related to au­then­tic­a­tion 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 pro­gram­ming languages have a library for gen­er­at­ing JSON Web Tokens, meaning that it’s no longer necessary to do it manually.

Go to Main Menu