Welcome to this introduction on JSON Web Tokens (JWTs, pronounced “jot”)—a powerful way to transmit information between a client and server. Imagine you’re handing out party invitations. You need each invite to carry specific details (the guest’s name), but you don’t want to store a massive guest list on your end. What if you could issue each invite with a built-in guarantee that it hasn’t been forged or tampered with? That’s exactly how JWTs help you verify and trust specific pieces of data without server-side overhead.
A JSON Web Token is a token containing data (like a user’s info) in a format that can be verified but not necessarily hidden. JWTs let you:
In practice, JWTs are often used for user authentication in modern web apps, single sign-on (SSO), or stateless session management.
Before diving into JWT specifics, it’s crucial to understand the difference between these three concepts:
JWTs use encoding for the visible parts of the token (header and payload) and hashing for the signature. They do not encrypt the payload by default.
Let’s picture JWTs through a party invite scenario:
This principle underpins JWTs: the token holds visible information, plus a signature that can be checked against a secret on the server.
A JWT has three parts, each encoded in base64 and separated by periods (.):
header.payload.signature
The header typically contains two fields:
{
"alg": "HS256", // the hashing algorithm
"typ": "JWT" // the token type
}
In this case, the algorithm is HS256, which means a SHA-256 hashing algorithm with an HMAC secret.
The payload is a JSON object with arbitrary data—often called “claims.” For example:
{
"email": "johnny@gmail.com",
"userId": 12345,
"exp": 1691100000 // optional expiration timestamp
}
The payload is encoded, not encrypted, so anyone who intercepts the token can read these claims if they decode the base64 string. That’s why sensitive data like passwords or credit card numbers should never go here!
The signature is where hashing comes in. It’s computed like:
signature = HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
The secret is kept on the server. This means if someone alters the header or payload, the signature check will fail on the server’s end.
Think of the payload as a “claim” and the signature as proof that the claim hasn’t been changed.
A JWT might look like this when combined:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 // encoded header
.eyJlbWFpbCI6ImpvaG5ueUBnbWFpbC5jb20ifQ // encoded payload
.SkuHIxgU1sDTrNKTTUIu9yDohUu8h0_4mbHiOMaUKwA // signature
You can paste this JWT into the jwt.io sandbox to decode and examine the header and payload. If you provide the correct secret (like ILoveDogs in our earlier party example), the token will show as “signature verified.” Otherwise, it will appear invalid.
Why use a JWT in your app? Common scenarios include:
In this reading, you’ve discovered:
JWTs are an elegant solution for many authentication and authorization challenges because they reduce or remove the need for server-side session storage. In the next steps, you’ll learn how to create (sign) and verify these tokens in practice, which is key to integrating JWT-based security into your applications.