JSON Web Tokens (JWTs) are a popular tool in modern web development for securely transmitting information between parties. However, despite their widespread use, misconceptions about JWTs abound. Let’s break down what JWTs are, what they’re not, and how to understand their structure and limitations.
What JWT Is
- A Compact, URL-Safe Token: JWTs are encoded as a single string of text that can be easily included in URLs or HTTP headers.
- A Data Transport Mechanism: JWTs enable the secure exchange of information, such as user authentication or session data.
- Digitally Signed: They are signed using algorithms like HMAC or RSA, ensuring the data’s integrity.
What JWT Ain’t
- Not Encrypted: The data in a JWT is encoded (often Base64URL) but not encrypted. Anyone with the token can decode and read its payload. They are not unreadable, just human-unreadable. Anyone who knows how to decode Base64 can read the payload.
- Not a Storage Mechanism: While tempting, JWTs should not store sensitive or excessive data, as they are transmitted with each request. So don’t put passwords, large datasets, or other sensitive information in them.
JWT Structure: Header, Payload, and Signature
A JWT consists of three parts, separated by dots (.
):
1. Header
The header typically contains two properties:
-
alg
: The signing algorithm (e.g.,HS256
,RS256
). -
typ
: The type of token, usuallyJWT
.
json{
"alg": "HS256",
"typ": "JWT"
}
2. Payload
The payload contains claims, which are statements about an entity (usually the user) and additional data.
-
Registered Claims: Standardized fields like
iss
(issuer),sub
(subject), andexp
(expiration time),iat
(issued at time),nbf
(not before time),exp
(expiration time), etc. - Custom Claims: Application-specific data. For example, a user’s role or permissions.
json{
"name": "Furkan Baytekin",
"email": "[email protected]",
"isAdmin": true,
"iat": 1516239022,
"exp": 1516240022
}
Warning: The payload is visible to anyone who has the token. Don’t store sensitive data here.
Note: iat, nbf, and exp are timestamps in seconds since the Unix epoch which is January 1, 1970.
3. Signature
The signature ensures that the token wasn’t tampered with. It is created by combining:
- The encoded header.
- The encoded payload.
- A calculated hash based on the header, payload, with a secret key.
This secret key should be kept secure and should only be known to the server that issues the JWTs. This is the reason how JWTs are secure.
Example JWT
Here’s an example token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiRnVya2FuIEJheXRla2luIiwiZW1haWwiOiJmdXJrYW5iYXl0ZWtpbkBnbWFpbC5jb20iLCJpc0FkbWluIjp0cnVlLCJpYXQiOjE1MTYyMzkwMjIsImV4cCI6MTUxNjI0MDAyMn0.dxKEch7ZgVvpVofbKlUMT_50FiyANemILjU8fy6XStw
- Header:
First part is:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
```. Decoded to:
```json
{
"alg": "HS256",
"typ": "JWT"
}
- Payload:
Second part is:
eyJuYW1lIjoiRnVya2FuIEJheXRla2luIiwiZW1haWwiOiJmdXJrYW5iYXl0ZWtpbkBnbWFpbC5jb20iLCJpc0FkbWluIjp0cnVlLCJpYXQiOjE1MTYyMzkwMjIsImV4cCI6MTUxNjI0MDAyMn0
Decoded to:
json{
"name": "Furkan Baytekin",
"email": "[email protected]",
"isAdmin": true,
"iat": 1516239022,
"exp": 1516240022
}
- Signature:
Last part is:
dxKEch7ZgVvpVofbKlUMT_50FiyANemILjU8fy6XStw
This is the signature generated using the header, payload, and secret key. The secret key is:
dxKEch7ZgVvpVofbKlUMT_50FiyANemILjU8fy6XStw
Generation of Signature
The signature is generated by combining the encoded header and payload with a secret key. This means changing the payload or header will result in a different signature. So, this makes the crackers job harder to guess the secret key.
Usually, HMACSHA256 algorithm is used to generate the signature. This is how the signature is generated:
javascriptHMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
Try It Yourself
Copy this JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiRnVya2FuIEJheXRla2luIiwiZW1haWwiOiJmdXJrYW5iYXl0ZWtpbkBnbWFpbC5jb20iLCJpc0FkbWluIjp0cnVlLCJpYXQiOjE1MTYyMzkwMjIsImV4cCI6MTUxNjI0MDAyMn0.dxKEch7ZgVvpVofbKlUMT_50FiyANemILjU8fy6XStw
and paste it into jwt.io. This tool will:
- Decode the token.
- Show the header and payload.
- Validate the signature (if you provide the secret).
You’ll notice that even if you didn’t provide the secret, the tool can still decode the header and payload. This is because JWTs are not encrypted, only signed.
You will also see that the signature is NOT validated. This is because you didn’t provide the secret key. If you provide the secret key, the signature will be validated. You can find the secret key I used in the signature at the very bottom of this blog post.
Conclusion
JWTs are a used to transfer public data securely between parties. It does not care about the privacy of the data, but it ensures who sent the data and that the data is not tampered with. It is a great tool for authentication and authorization in web applications.
You can use JWTs to:
- Authenticate users.
- Secure APIs.
- Share data between services.
- Implement single sign-on (SSO).
- And more.
Just remember to:
- Keep the payload small and non-sensitive.
- Use HTTPS to deliver JWTs.
- Keep the secret key secure.
- Use a strong algorithm for signing.
- Validate the signature on the server side.
- Set a reasonable expiration time.
- And don’t store sensitive data in the payload!
After emphasizing the security of JWTs this much I hope this blog post helped you understand JWTs better. Happy coding!
Secret Key I Used in the Signature
furkanbaytekin.dev