Skip to content
العربية

JWT (JSON Web Tokens)

How signed tokens carry your identity, and the three classic ways servers verify them wrong: accepting alg:none, a weak secret, and RS256-to-HS256 confusion.

Estimated time
30 min
Level
Intermediate
Your progress in this track0%

Before this lesson

A JSON Web Token is a small signed note the server gives you after login. On every later request you hand it back, the server checks the signature, and if it holds, it trusts what the note says — who you are, your role. The data inside is only Base64, readable by anyone; the signature is what makes it trustworthy. So every JWT attack is really an attack on how the server checks that signature.

What a token looks like

Three Base64url parts joined by dots: header.payload.signature.

decoded
// header                     // payload
{ "alg": "HS256",             { "user": "guest",
  "typ": "JWT" }                "role": "member" }

The header names the algorithm. The payload is the claims. The signature is computed over header.payload with a key. Change any byte of the payload and the signature no longer matches — unless the server checks it wrong.

Three ways it goes wrong

  • alg: none. The standard includes a “none” algorithm meaning unsigned. If the server reads the algorithm from the token and honours none, it accepts a token with no signature at all. Anyone writes any payload.
  • A weak secret. HS256 signs with a shared secret. If that secret is short or common (ravens), an attacker cracks it offline with a wordlist and then signs any token they like. HMAC is only as strong as its secret.
  • Algorithm confusion. The server uses RS256 — a private key signs, the public key verifies — but also accepts HS256, verifying it with that same public key as the HMAC secret. The public key is published, so the attacker signs an HS256 token with it and the server accepts it.

How to prevent it

safe.js
// Pin the algorithm on the server. Never read it from the token. Never accept none.
jwt.verify(token, KEY, { algorithms: ['HS256'] });   // or ['RS256']

Fix the accepted algorithm in your code and pass it to the verifier. Use a long random secret for HS256 (32+ bytes, from a secret store, rotated), or asymmetric RS256/EdDSA where the verifier never holds a signing secret. Keep the verification key from ever being used as a symmetric secret, set a short expiry, and remember the payload is readable — never put secrets in it. Lean on a maintained JWT library; the hand-rolled check is where these bugs live.

Review questionA server verifies a JWT by reading header.alg and using the matching algorithm. Why is that dangerous?

Labs

  • A signature that is optional

    EasyBrowser lab

    Forge a token that makes the server treat you as admin.

  • A secret you can crack

    MediumBrowser lab

    Crack the signing secret, then sign a new token that makes you admin.

  • A mix-up between algorithms

    HardBrowser lab

    Exploit the RS256-to-HS256 confusion to forge an admin token using the public key.