JSON Web Tokens (JWT) are a compact and self-contained way to securely transmit information between parties as a JSON object. A typical JWT consists of three parts, separated by dots:
HEADER.PAYLOAD.SIGNATURE
Example of a full JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VybmFtZSI6Im1haWphMTIzIiwiZXhwIjoxNzE4MTE4MDAwfQ.
SGp1Y2la3EXAMPLE2wR7J_yPaAogwEXAMPLEqj8c
The header typically consists of two fields:
{
"alg": "HS256",
"typ": "JWT"
}
The payload contains the actual data (claims). These can be custom claims or registered ones:
{
"username": "teppotesti",
"exp": 1718111800,
"iat": 1718110000
}
Note: The payload is not encrypted, so it's visible to anyone who has the token. However, it cannot be modified without invalidating the signature.
The signature ensures the token's integrity. It's created using the header and payload, combined with a secret key:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
This makes it possible to verify that the token hasn't been tampered with.
JWTs are useful for stateless authentication. The payload carries identity and metadata, and the signature ensures the token's authenticity. Just remember: don't store sensitive data in the payload, as it is readable by anyone with access to the token.
The payload is only Base64URL encoded, NOT encrypted. Anyone with the token can decode it using a simple JavaScript function:
eyJ1c2VybmFtZSI6InRlcHBvdGVzdGkiLCJleHAiOjE3MTgxMTE4MDB9
atob("eyJ1c2VybmFtZSI6InRlcHBvdGVzdGkiLCJleHAiOjE3MTgxMTE4MDB9")
{"username":"teppotesti","exp":1718111800}
NO! This is a critical difference between the payload and the signature:
eyJ1c2VybmFtZSI6InRlcH...
✓ atob() → JSON visible
SGp1Y2la3EXAMPLE2wR7J...
✗ Cannot decode back to secret
Many people confuse these concepts. Let's clarify:
The signature is created using a hash function (HMAC-SHA256), NOT encryption. Hash functions are designed to be:
Key point: Hashing creates a "digital fingerprint" of the data. You cannot reconstruct the original data from the fingerprint, but you can verify if data matches the fingerprint.
If your secret is weak (e.g., "mySecret123") → Can be cracked in minutes
If your secret is strong (crypto.randomBytes(64)) → Practically impossible to crack
crypto.randomBytes(64) for your JWT secret is critical!
Many people confuse Bearer Tokens and JWT. Let's clarify the difference:
Authentication scheme/mechanism (OAuth 2.0 standard)
Authorization: Bearer <token>Token format/structure (specific standard)
// JWT used as Bearer token (most common) Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... // Opaque token as Bearer token Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA // Simple random string as Bearer token Authorization: Bearer abc123xyz456random
You can send different types of letters (JWT, plain text, encrypted data) in the same type of envelope (Bearer authentication).
When you see Authorization: Bearer eyJhbGciOi..., you are using:
Both concepts work together but serve different purposes!