JSON Web Tokens

JSON Web Tokens dissects the token format: three base64url segments — header, claims payload, and a signature over the first two. Here the token is a credential in an HTTP header, and the Express 24,430 job is to issue one at login and verify one on every protected route.

Issuing an access token and verifying the Authorization headerJavaScript
import jwt from 'jsonwebtoken';                // npm i jsonwebtoken@9.0.3
const CLAIMS = { issuer: 'api.example.com', audience: 'bookshelf-web' };
const issueAccess = (user, ttl = '15m') =>
  jwt.sign({ roles: user.roles }, process.env.ACCESS_SECRET,
    { algorithm: 'HS256', expiresIn: ttl, subject: user.id, ...CLAIMS });
function requireJwt(req, res, next) {
  const [scheme, token] = (req.get('authorization') ?? '').split(' ');
  if (scheme !== 'Bearer' || !token) {
    return res.status(401).set('WWW-Authenticate', 'Bearer').json({ error: 'missing_token' });
  }
  try {
    req.auth = jwt.verify(token, process.env.ACCESS_SECRET,
      { algorithms: ['HS256'], ...CLAIMS });   // allow-list, never the header's alg
    next();
  } catch (err) {                              // 'invalid signature', 'jwt expired'
    res.status(401).json({ error: err.name, message: err.message });
  }
}
app.get('/books', requireJwt, (req, res) =>
  res.json({ sub: req.auth.sub, roles: req.auth.roles, books: ['Dune', 'Solaris'] }));

The decoded header and payload of a real token, then four requests — one that works and three that do not:

Output of 40
{"alg":"HS256","typ":"JWT"} . {"roles":["author"],"iat":1789665904,"exp":1789666804,
 "aud":"bookshelf-web","iss":"api.example.com","sub":"u_1"}
$ curl -H "Authorization: Bearer $AT" .../books
{"sub":"u_1","roles":["author"],"books":["Dune","Solaris"]}
$ curl -i -H "Authorization: Bearer $TAMPERED" .../books    # roles edited to ["admin"]
HTTP/1.1 401  {"error":"JsonWebTokenError","message":"invalid signature"}
$ curl -i -H "Authorization: Bearer $ONE_SEC_TOKEN" .../books     # two seconds later
HTTP/1.1 401  {"error":"TokenExpiredError","message":"jwt expired"}
$ curl -i .../books  ->  401  WWW-Authenticate: Bearer  {"error":"missing_token"}

Editing the payload to promote yourself to admin is the first thing anyone tries, and it yields invalid signature because the HMAC no longer covers those bytes. That rejection depends on the explicit algorithms allow-list: omit it and jsonwebtoken 18,189 honors the attacker-controlled alg header — the alg: "none" and RS256-downgraded-to-HS256 attacks of JSON Web Tokens. Pinning issuer and audience matters as much, or a staging token is accepted in production. The payload is readable by anyone holding the token, so put nothing there you would not print in a log.