All about JSON Web Tokens (JWT)
JSON Web Token (JWT), pronounced “jot”, by definition, is a widely-recognized standard for user authentication, enabling secure information exchange online as a JSON object. These tokens are compact, self-contained units of information that can be securely transmitted between parties. This information can be verified and trusted because it is digitally signed.
JWT is a stateless method of authentication, which means once the token is generated, there is no extra data that need to be stored on the server for verifying the token (like sessions). JWT carries enough information with it required to decrypt it and read its content.
Structure of JWT
JSON Web Tokens consist of three parts separated by dots (.
) These are:
1. Header
2. Payload
3. Signature
It typically looks like this: xxxxx.yyyyy.zzzzz. Below is a valid token, you can play around with JWT tokens here: https://jwt.io/#debugger-io
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Header
Header contains the information which specifies the type of token and the algorithm used to generate the token. The decoded structure looks like this:
{
“alg”: “HS256”, // Algorithm used to generate this token
“typ”: “JWT” // Type of token
}
There are several algorithms that can be used to generate the token. Some of them are: HMAC with SHA-256 (HS256), HMAC with SHA-512 (HS512), RSA with SHA-256 (RS256), etc.
The “typ” field in the header of a JSON Web Token (JWT) specifies the type of the token. While the most common value for this field is “JWT,” there are other possible values that can be used to denote different types of tokens or token formats. Some of these values include: JWT, JWE, SAML,
Payload
It is the second part of the JWT and contains the claims. Claims are statements about an entity (typically, the user) and additional data. There are three types of claims:
- Registered Claims: These are a set of predefined claims that are commonly used to convey information about the token itself or the entity it represents. These are not mandatory but are “recommended” as it provides a set of useful, interoperable claims. Some of the registered claims include:
1. iss (Issuer): Identifies the issuer of the token, typically the authorization server.
2. sub (Subject): Identifies the subject of the token, typically the user or entity being authenticated.
3. aud (Audience): Specifies the intended audience for the token, typically the recipient or the resource server that the token is intended for.
4. exp (Expiration Time): Specifies the expiration time of the token. After this time, the token should not be accepted for processing.
5. iat (Issued At): Specifies the time at which the token was issued.
The full list can be found here: https://datatracker.ietf.org/doc/html/rfc7519#section-4.1 - Public Claims: These are claims that are defined by the application and are not reserved for specific purposes. They can be used to convey any custom information relevant to the application’s context. Examples of public claims might include user roles, permissions, or any other user-related data.
- Private Claims: Similar to public claims, private claims are also defined by the application but are intended to be kept private between the parties involved. These claims may contain sensitive information that should not be exposed to unauthorized parties. Examples might include user email addresses, user IDs, or any other personally identifiable information (PII).
The difference between public and private claims is when using a JWT decryption tool, public claims can be seen, but the private claims are encrypted so it can be accessed only by the party involved.
{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
// Private claim (encrypted)
"userId": "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
}
Signature
The signature in a JSON Web Token (JWT) is a crucial component that ensures the integrity and authenticity of the token data. It provides a means for verifying that the token has not been tampered with and that it was indeed issued by a trusted party. This part of the token, cannot be decrypted since it is a hash and not an encrypted value. (This gibberish is unique and reproducible. If given the same inputs, it will always give the same result).
The signature is used to verify the message wasn’t changed along the way, and, in the case of tokens signed with a private key, it can also verify that the sender of the JWT is who it says it is. To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.
// Signature
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
// A simple signature: jbcOUQ2bbiYlfVtprEkaT_S6Y6yQnBDOAKDHIHjvl7g
Verification: To verify the signature of a JWT, the following steps are typically performed:
- The header and payload of the JWT are serialized into a single string.
- The serialized string is hashed using the same cryptographic algorithm used to generate the signature.
- The decrypted signature value from the JWT is compared to the hash value obtained in the previous step.
- If the two values match, the token is considered valid, indicating that it has not been tampered with and was issued by a trusted party.
“Everyone can read my tokens! They can change the claims and grant themselves admin access!”
This first part is true, as you can take any valid JWT token, if you try to encrypt it, you can see all the claims it has. (You might not be able to read the value of private claims since they are encrypted). That is why you should never store sensitive information in the token (no, a user’s role is not sensitive — a password is).
The second part is not entirely true. They sure can update the claims and show themselves as admin, but that is of no use. Let me show you why!
How does JWT work?
- Authentication Request: A user attempts to access a protected resource by sending credentials (e.g., username/password) to the authentication server.
- Token Generation: Upon successful authentication, the server generates a JWT containing relevant user information and signs it with a secret key. The JWT is returned to the client, often stored in local storage or cookies.
- Token Transmission: Subsequent requests from the client to access protected resources include the JWT in the authorization header or as a query parameter.
- Token Verification: The server extracts the JWT from the request, verifies its authenticity by recalculating the signature, and checks the claims. If the JWT is valid and contains the necessary claims, access to the requested resource is granted.

So, somebody tampered with the claims and set their role to ADMIN
. The JWT verification will fail as the signature does not match anymore (remember, the signature is generated using the original payload defined by the issuer — where the role is USER
).
Generating and signing a new JSON Web Token won’t work for them either — as they (hopefully) don’t have access to the secret or private key you use to sign your tokens. If they do, you are in trouble.
Signing the token
There are two ways to sign JSON Web Tokens. Let’s consider a very common distributed system where we have several services (Auth Service, Warehouse Service, Order Service and Notification Service).
Secret
You could use any string as a secret (for example, dontUseThisSecret123##$%83
), and the same secret will be used to verify the signature. However, if you choose to do so, please use a non-trivial secret that is hard to brute-force.
That works okay for monolithic systems. But what if you have several services that serve users? For example; Auth Service, Warehouse Service, Invoice Service, Notification Service and Order Service.
In this case, the Secret approach is seriously risky. All services will need to have access to the secret in order to verify the token. Which means:
- All services will know the secret. That increases the risk of the secret being exposed or hijacked by an attacker. I mean, when you tell your friend a secret you don’t expect it to be spread around, right?
- All services technically have the ability to create new tokens — whose responsibility is it to generate tokens? This can introduce semantic problems of ownership.
Key Pair (Public and Private Keys)
This approach utilizes a pair of keys — private and public.
Following this approach, the issuer of our token (Auth Service) will use a private key to sign the tokens (using RSA or ECSA algorithms). As the name implies, this key will be private and won’t be shared with any other service.
Any other service interested in verifying incoming tokens will have the public key. Public keys are able to verify tokens but not sign new ones. Therefore, the risks mentioned above are eliminated. There is absolutely no risk in exposing the public keys.
Choosing Between the Two?
- Use a shared secret when simplicity and efficiency are paramount, and when communicating between trusted parties in a secure environment.
- Opt for a private-public key pair when enhanced security, non-repudiation, and scalability are critical, especially in scenarios involving communication across untrusted networks or with multiple parties.
Benefits of JWT
There are benefits to using JWTs when compared to simple web tokens (SWTs) and SAML tokens.
- More compact: JSON is less verbose than XML, so when it is encoded, a JWT is smaller than a SAML token. This makes JWT a good choice to be passed in HTML and HTTP environments.

- More secure: JWTs can use a public/private key pair for signing. A JWT can also be symmetrically signed by a shared secret using the HMAC algorithm.
- More common: JSON parsers are common in most programming languages because they map directly to objects. Conversely, XML doesn’t have a natural document-to-object mapping. This makes it easier to work with JWT than SAML assertions.
- Easier to process: JWT is used at internet scale. This means that it is easier to process on users’ devices, especially mobile.
Let’s Get in Touch
You are most welcome to follow me here on Medium. In addition, feel free to check out:
- My portfolio
- My LinkedIn Profile: Let’s connect!
- My Twitter Profile
References
https://jwt.io/introduction
https://frontegg.com/blog/jwt-authentication
https://fusionauth.io/articles/tokens/jwt-components-explained#:~:text=The%20typ%20header%20indicates%20the,used%20to%20sign%20the%20JWT
https://arielweinberger.medium.com/json-web-token-jwt-the-only-explanation-youll-ever-need-cf53f0822f50
https://auth0.com/docs/secure/tokens/json-web-tokens#benefits-of-jwts