INTRODUCTION
Authentication and authorization systems are an important component of modern software architecture, they are the most obvious entry point into your software system, basically the front gate to your application. As a backend engineer, building integrity into your authentication systems is critical to ensure it is secure and robust, a token-based protocol such as JSON Web Tokens (JWT) is perfect for ensuring your authentication system is secure.
Token-based authentication systems are a cornerstone of modern web security and authentication today. Known for their flexibility, security, and friendly developer experience, they are the preferred choice for a wide range of applications and services. Aside JWT, you can check out other token-based authentication protocols like OpenID Connect (OIDC) and OAuth2.0.
When working with JWTs, you are typically going to use at least 2 of JWT’s 3 methods in your authentication system; The sign method to create a signature and the JWT token to encode the claims that contain the user’s data and other additional information, the decode method to extract information associated with the JWT and the verify method to validate the digital signature and ensure the integrity of the JWT has not been tampered with.
In this article, I will distinguish between the decode and verify methods. While they are often used interchangeably when working with JSON Web Tokens, they perform very distinct functions. Before we get into the comparison, let’s go through a brief refresher on what each method does.
JWT METHODS
jwt.Sign method
jwt.sign({claims}, secret, {expiresIn: maxAge})
Note: Ensure you install import your JWT module before attempting to use the variable in my case jwt
in your code.
The signing method generates a JWT header and payload hash using the SHA-256 or SHA-384 hashing algorithm. The hash is then combined with the secret key using a digital signing algorithm, such as HMAC (Hash-based Message Authentication Code) or RSASSA-PKCS1-v1_5 (RSA Signature Scheme with Appendix-PKCS1-v1_5). The resulting signature is appended to the JWT, returning a complete token in my case
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFiY3RyZUBnbWFpbC5jb20iLCJpYXQiOjE3MDI0OTM1NzgsImV4cCI6MTcwMjc1Mjc3OH0.IUmIl24tjjDYrk127fCfm7QAj6yTPHUkp9KQ-WLD2Pk
This token is used to transfer information from and within your software systems.
Breakdown of the token’s structure
jwt.Decode method
jwt.decode(token, secret, {complete: true})
What happens when you decode a JWT is that it simply extracts the header, payload that contains your claims, and signature by parsing the JSON object. It then returns a JSON object containing your claims that looks like this.
{
email: 'abctre@gmail.com',
iat: 1702538321,
exp: 1702797521
}
Note: The above object represents information I encoded in the signing process so yours may look different depending on the information you encode.
jwt.Verify method
jwt.verify(token, secret)
When you verify your JWT, jwt.verify
will execute the following steps:
Decode the JWT token; extracting the header, payload, and signature from the token.
Then it uses your secret key and the signing algorithm specified in the header to verify the signature and
Finally, it will check the expiration time and other claims in the payload to ensure the token is still valid.
Once the processes highlighted above are successfully executed, it will return a JSON object similar to the one returned when you use the decode method that contains the claims you initially encoded.
Illustration
Let's put aside technical speak for a moment now and make use of a real-life illustration to demonstrate how these JWT methods work. We will take the scenario of a company employee Ruth Adebayo, Ruth is issued a company Identification card that will serve as a pass to allow her access to the office premises everytime she goes to work. At the point when the card was issued (typically during employee onboarding), Ruth’s information and employment status with the company were used to create a means of identifying her as an employee of the company in the form of an ID card containing lets say a QRCode, This is likened to the signing process where Ruth’s information and employment status with the company is encoded into an ID card with a scannable QRCode, the ID card here is the JWT token. Whenever Ruth attempts to enter the office premises, she goes through a security clearance protocol that demands that she presents her company ID card, so she shows security her ID that visibly contains information like her name, current position, and company name/logo to the security personnel, the security personnel then views the ID card and extract the information on the card with their eyes, this can be likened to the decoding process. The security personnel can allow Ruth into the premises just based on the information they have seen on her ID card. By doing that, they would be performing their duty as security personnel horribly as that would be very unsafe and can likely lead to a breach of security as Ruth may have been let go and is no longer an employee of the company unknown to the security personnel or the ID card she presented may be a fake.
To avoid this sort of security breach, the security personnel ought to take the employee’s ID and scan the QRCode to confirm the employee’s information and check their employment status ensuring that they are still an active employee of the organization before they are let into the premises, this my friends is what the verification process is all about.
Decode vs Verify
As I said earlier, jwt.decode
and jwt.verify
are often used interchangeably but perform distinct functions when handling JWT tokens.
It is easy to see why some programmers will think they both do the same thing because when successfully run, they return the same JSON object but as they say, the devil is in the details of how each method executes and arrives at the payload they return. Let’s look at their similarities and differences to fully understand how distinct they are.
Similarities
In as much as they have very distinct functions and serve different purposes, both methods have their similarities which include:
They are both important steps in the process of handling JWTs
They both rely on the information contained within the token’s header and payload to successfully return the user’s claims.
They work together to extract and validate information encoded in the token and ensure its authenticity. This is why they often return the same JSON object.
Differences
The major difference between the methods is that the decode method simply extracts the header, payload, and signature encoded in the JWT to return the claims in your payload while the verify method in addition to extracting information, also verifies the signature and validates the token to ensure its authenticity. Here are some other distinctions between decode and verify methods:
Decode | Verify |
The decoding process is simple and more straightforward. | The verification process is relatively more complex due to its cryptographic operations. |
The decoding process precedes the verification process. | The verification process comes after the information is extracted from the decoding process and then it verifies the extracted information. |
There are no security checks in the decoding process, just straight-up extraction. | During the verification, the information extracted is assessed for integrity and authenticity. |
Use Cases
Looking at the differences between both methods, you may be inclined to believe that one method is inferior to the other which is not the case. There are peculiar scenarios where the use of each method is most appropriate. Let’s look at some of the peculiar use cases for each of these methods.
jwt.Decode
Debugging and analysis: Decoding JWT can be useful when you want to debug and analyze the claims and information contained in the token without verifying its authenticity. This can help understand the format and structure of the token and detect issues with its content or extract specific claims for further analysis.
Offline data extraction: For applications that run offline, decoding JWT can still provide access to valuable information locally because, unlike the verification method, the decoding process does not require an internet connection to execute.
Pre-verification filtering: Before the verification of JWT, you can use the decoding method to filter out invalid or expired tokens and improve the efficiency of the verification process, eliminating unnecessary cryptographic operations for invalid tokens.
Token introspection: You can use the decode method to introspect the contents of a JWT in a non-verification context. For example, an API gateway might decode a token to determine the user's role and permissions before routing the request to the appropriate service.
jwt.Verify
Securing APIs and resources: To ensure that only the users with valid tokens can access protected data or perform certain actions with your system, verifying a JWT is key to securing access to your APIs, services, and other resources.
Preventing token replay attacks: Verifying the signature helps prevent replay attacks where attackers attempt to reuse a captured token to gain unauthorized access. The signature verification ensures that your token is authentic and fresh, preventing misuse and nipping such vulnerability in the bud.
Implementing authorization decisions: The claims extracted during verification can be used to make authorization decisions within an application. For example, the system can check the user's role or permissions based on the claims to determine what actions they are authorized to perform.
Auditing and logging: Verifying tokens can be used for auditing and logging purposes. The verification process can capture information about the token, the user, and the access attempt, which you can use to track access patterns and investigate potential security incidents.
Conclusion
I hope I have been able to shed some light on the distinctions between the decode and verify methods of handling JWT and you can see that none of them is inferior but serve distinct purposes and are complementary. I believe you now know the importance of understanding the strengths and limitations of each method and selecting the most appropriate method for your specific use case. See you on the next one guys. Cheers!