5 Easy Steps to Understand JSON Web Tokens (JWT
In this article, you will explain the basics of JSON Web Tokens (JWT) and why to use them. JWT is an important part of making sure your application is trusted and secure. JWT allows information, such as user data, to be represented in a secure manner.
To explain how JWT works, let’s start with an abstract definition:
JSON Web Token (JWT) is a JSON object defined in RFC 7519 as a secure way to represent the information set of both parties. The Token consists of a header, payload, and signature.
In simple terms, JWT is just a string of the following format:
header.payload.signature
Copy the code
Note that double-quoted strings are also valid JSON objects
To illustrate how and why to use JWT, we’ll use a simple 3 entity example (see figure below). The three entities in this example are user, Application Server, and Authentication Server. The authentication server provides the JWT to the user, who can then securely communicate with the application.
In this example, the user first logs into the authentication server through the login system provided by the authentication server (for example: username and password, Facebook login, Google login, and so on). The authentication server then generates the JWT and returns it to the user. When a user makes an API request to the application server, the JWT is attached. In this step, the application server is configured to verify that the incoming JWT was generated by the authentication server (the verification process will be explained later). Therefore, when a user initiates an API request with a JWT, the application can use the JWT to verify that the API request is from an authenticated user.
Now, we’ll take a closer look at JWT itself and how it is built and validated.
Step 1. Create the HEADER
The HEADER module of the JWT contains information on how to calculate the JWT signature. Header is a JSON object in the following format:
{
"typ": "JWT",
"alg": "HS256"
}
Copy the code
In this JSON, the value of the “type” field specifies that the object is a JWT, and the value of the “ALg” field specifies the hash algorithm used to generate the JWT signature module. In our example, we use the HMAC-SHA256 algorithm, a hash algorithm with a key, to compute the signature (detailed in Step 3).
Step 2. Create PAYLOAD
The payload module of the JWT is the data stored in it (this data is also called the “statement” of the JWT). In this example, the authentication server generates the JWT, which holds the user’s information, specifically the user ID.
{
"userId": "b08f86af-35da-48f2-8fab-cef3904660bd"
}
Copy the code
In our example, we only save one declaration in payload. You can also add more declarations if you want. The PAYLOAD of JWT has several different standard declarations, such as “iss” for issuer, “sub” for subject, and “exp” for expiration time. These fields are very useful when creating a JWT and are optional. A detailed list of JWT standard fields can be found on the Wikipedia Page.
Keep in mind that the size of the data affects the size of the entire JWT, which is generally not a problem, but too large a JWT can have a negative impact on performance and cause latency.
Step 3. Create SIGNATURE
The signature is calculated with the following pseudo-code:
// Signature Algorithm data = base64urlEncode(header) + ". + base64urlEncode( payload ) hashedData = hash( data, secret ) signature = base64urlEncode( hashedData )Copy the code
This algorithm performs base64URL encodes for the header and payload generated in steps 1 and 2, and passes a period (.) in the middle of the encoded string. Connect. In pseudocode, assign the connection string to Data. Hash the data string using the hash algorithm defined in the JWT header, plus the key. Assign hash data to hashedData. The hash data generates the JWT signature (signature) through Base64URL encoding.
In our example, header and payload are encoded as base64URL:
// header
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
// payload
eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ
Copy the code
Then, the compiled header and payload are concatenated and calculated using the specified signature algorithm and key to obtain hash data for the signature. In our example, the HS256 algorithm is used, the key is the string secret, and the string data is computed to get the string hashedData. Then, base64URL encodes the string hashedData to get the following JWT signature (signature) :
// signature
-xN_h82PHVTCMA9vdoHrcZxH-x5mb11y1537t3rGzcM
Copy the code
Step 4. Merge the three MODULES of JWT
Now that we have created all three modules, we are ready to generate JWT. Remember the JWT structure header.payload-signature, we simply use periods (.). Merge them as separate. We use the base64URL encoded header and payload, and the signature obtained in Step 3:
// JWT Token eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ.-xN_h82PHVTCMA9v doHrcZxH-x5mb11y1537t3rGzcMCopy the code
You can use jwt. IO to create your JWT.
Returning to our example, the authentication server can now send this JWT to the user.
How does JWT protect data
It is important to understand that the purpose of using JWT is not to hide or obscure data in any way. The purpose of using JWT is to prove that the sent data was created by a trusted source.
As shown in the previous steps, the data in JWT is encoded and signed, but not encrypted. The purpose of coding data is to transform the structure of data. Signed data allows the data receiver to verify the reliability of the data source. So encoding and signing data does not protect the data. Encryption, on the other hand, is primarily about protecting data and preventing unauthorized access. For a detailed explanation of the differences between encoding and encryption, and more on how hash works, see this article.
Since JWT only signs and encodes data, not encryption, all JWT does not guarantee any security of sensitive data.
Step 5. Verify JWT
In our simple 3 entity example, the JWT we use is signed by the HS256 algorithm — the key of this algorithm is known only to the authentication server and the application server. When the application server sets up its authentication process, the application server receives the key from the authentication server. Since the application knows the key, the application can perform the same signature algorithm as Step 3 when the user initiates an API request with JWT to the application. The application can then verify that the signature generated by its own hash operation matches the signature in JWT (that is, it matches the JWT signature created by the authentication server). If the signatures match, it means that the JWT is valid, indicating that the API request came from a trusted source. Otherwise, if the signatures do not match, it means that the JWT received is invalid, which may also indicate a potential attack on the application. So, by validating JWT, the application establishes trust with the user.
conclusion
We learned what JWT is, how to create and validate it, and how to use it to build trust between applications and users. This is a starting point for understanding the fundamentals of JWT and what it does. JWT is just one of the challenges of ensuring trust and security in your application.
It should be noted that the JWT authentication setup described in this article uses a symmetric key algorithm (HS256). You can set up your JWT authentication in a similar way, but using an asymmetric algorithm (such as RS256) – the authentication server has one key and the application has one public key. For a detailed analysis of the differences between using symmetric and asymmetric algorithms, check out this question on Stack Overflow.
It should also be noted that the JWT must be sent over an HTTPS connection (not HTTP). Using HTTPS prevents unauthorized users from stealing the sent JWT and thus intercepting the communication between the server and the user.
Also, it is important to set expiration dates for your JWT payload — especially short ones — so that if the old JWT is leaked, it may be invalid and no longer usable.