RSRobince Studio

JWT interview revision notes

Stateless authentication tokens for APIs. Written for developers preparing for an interview who want to refresh their JWT fast. Free, no sign-up.

9 topics in these notes

  1. What is JWT?
  2. JWT structure (header, payload, signature)
  3. Signing & verifying JWTs
  4. JWT auth flow (login → token → protected route)
  5. Access token vs refresh token
  6. Storing JWTs securely (cookies vs localStorage)
  7. Revocation & blacklisting
  8. Common attacks & defenses (XSS, CSRF, algorithm issues)
  9. JWT in Node/Express (middleware example)

What is JWT?

Simple real-life example (Understand first — very important for understanding)

  • Like a concert wristband: once you’ve checked in at the gate, you get a band that proves you’re allowed inside.
  • You don’t re-check ID on every ride; the wristband is enough until it expires or is revoked.

Real-world idea: a JWT is a signed token the server gives a client so it can prove who it is on later requests without re-authenticating each time.

Technical definition

  • JWT (JSON Web Token) is a compact, URL-safe token format: base64(header).base64(payload).base64(signature).
  • Header: algorithm + token type. Payload: claims (sub, exp, roles, etc.). Signature: computed with secret/private key.
  • Stateless: server can verify token using the secret/key; no session storage needed.

Simple practical example

On login, server issues a JWT with user id and expiry. Client sends it with each API call; server verifies and trusts the claims.

Code example

const jwt = require('jsonwebtoken');

const token = jwt.sign({ sub: user.id }, process.env.JWT_SECRET, {
  expiresIn: '15m'
});

Why it matters

JWTs are a very common way to implement stateless auth in web/mobile APIs. Many backend interview questions center around them.

Interview tip

Summarize: "JWT is a signed JSON token used to carry identity and claims; server verifies signature instead of looking up a session."

JWT structure (header, payload, signature)

Simple real-life example (Understand first — very important for understanding)

  • Think of a stamped ticket: printed info (payload), type of ticket (header), and the stamp/signature that proves it’s genuine.
  • Anyone can read the printed info; only the organizer can produce a valid stamp.

Real-world idea: JWTs are not encrypted by default; they’re signed. The structure makes it easy to read and verify tokens.

Technical definition

  • Header: `{ alg: 'HS256', typ: 'JWT' }` → encoded in base64url.
  • Payload: JSON with claims (e.g. `sub`, `iat`, `exp`, `role`).
  • Signature: HMAC or asymmetric signature over header+payload using secret/private key.

Code example

// decoded structure idea
{
  "header": { "alg": "HS256", "typ": "JWT" },
  "payload": { "sub": "123", "role": "admin", "exp": 1712345678 },
  "signature": "..."
}

Why it matters

Understanding the structure helps you debug tokens, choose the right claims, and explain how verification works.

Interview tip

Explain that JWTs are base64-encoded (not encrypted) and what each part represents.

Signing & verifying JWTs

Simple real-life example (Understand first — very important for understanding)

  • Like stamping a ticket with a unique stamp: only the organizer’s stamp counts.
  • A fake ticket without the right stamp is rejected at the gate.

Real-world idea: signing ensures tokens can’t be tampered with without the secret/private key; verification checks the signature and expiry before trusting it.

Technical definition

  • Sign: `jwt.sign(payload, secretOrPrivateKey, options)`.
  • Verify: `jwt.verify(token, secretOrPublicKey, options)`.
  • Common algs: HS256 (HMAC with shared secret), RS256 (RSA with private/public key pair).

Code example

const token = jwt.sign({ sub: user.id }, process.env.JWT_SECRET, { expiresIn: '15m' });

try {
  const decoded = jwt.verify(token, process.env.JWT_SECRET);
  console.log(decoded.sub);
} catch (e) {
  console.error('Invalid or expired token');
}

Why it matters

Correct signing & verification are central to security. Getting secret management or algorithms wrong can break your auth model.

Interview tip

Mention verifying both signature and expiry, and that you never trust data from an unsigned/incorrectly signed token.

JWT auth flow (login → token → protected route)

Simple real-life example (Understand first — very important for understanding)

  • Check-in desk (login): they check your ticket and ID once and give you a wristband.
  • Every ride (protected route) just checks your wristband, not your ID again.

Real-world idea: login is done once; after that, every protected request includes the token so the server can quickly verify identity and permissions.

Technical definition

  • Login route: verify credentials, issue access token (and optionally refresh token).
  • Client stores the token (HTTP-only cookie or memory/localStorage depending on design).
  • Protected routes: read token from header/cookie, verify, attach user to request, continue.

Code example

// Express pseudo-flow
app.post('/login', async (req, res) => {
  const user = await findUser(req.body.email);
  if (!user || !(await checkPassword(req.body.password, user.password))) {
    return res.status(401).json({ message: 'Invalid credentials' });
  }
  const token = jwt.sign({ sub: user.id }, process.env.JWT_SECRET, { expiresIn: '15m' });
  res.json({ token });
});

Why it matters

Most JWT questions in interviews are about being able to explain and sketch this login → token → protected route flow clearly.

Interview tip

Draw or describe the flow end-to-end: credentials → issue token → send token → verify on each request.

Access token vs refresh token

Simple real-life example (Understand first — very important for understanding)

  • Short-lived visitor pass vs longer-term membership card.
  • You use the small pass often but it expires quickly; the membership card is used to get a new pass when needed.

Real-world idea: access tokens are short-lived and used on every request; refresh tokens live longer and are used only to get new access tokens.

Technical definition

  • Access token: short expiry (minutes); used in Authorization header.
  • Refresh token: longer expiry (days/weeks); used only at token refresh endpoint.
  • Refresh tokens are often stored more securely and can be revoked/rotated.

Why it matters

Using only long-lived access tokens increases risk if they leak. Proper access+refresh design balances usability and security.

Interview tip

Be able to explain why access tokens should be short-lived and how refresh tokens can be rotated or revoked.

Storing JWTs securely (cookies vs localStorage)

Simple real-life example (Understand first — very important for understanding)

  • Like choosing where to keep your house key: under the doormat (easy but unsafe) vs in a locked box (safer, slightly more work).
  • Where you store tokens changes which attacks are easier or harder.

Real-world idea: localStorage is simple but vulnerable to XSS; HTTP-only cookies protect against JS access but need CSRF protection.

Technical definition

  • localStorage/sessionStorage: accessible to JS; vulnerable if XSS occurs.
  • HTTP-only same-site cookies: not accessible to JS; help mitigate XSS token theft but need CSRF defenses.
  • Best practices include SameSite, Secure, and HttpOnly attributes.

Why it matters

Token storage strategy has direct security implications. Many interview questions probe your understanding of XSS vs CSRF vs storage choices.

Interview tip

Be ready to compare localStorage vs HTTP-only cookies and mention XSS/CSRF trade-offs and mitigations.

Revocation & blacklisting

Simple real-life example (Understand first — very important for understanding)

  • If a wristband is stolen, security needs a way to mark it invalid even if it hasn’t expired.
  • They might keep a short list of blocked IDs at the gate.

Real-world idea: stateless tokens don’t have a built-in "destroy" button; you need a strategy to make specific tokens invalid early.

Technical definition

  • Common strategies: maintain a blacklist/denylist of token IDs (jti) or user logout timestamps.
  • Short access token lifetime + rotating refresh tokens to narrow the window of misuse.
  • Server can check revocation list or last-logout time on each protected request.

Why it matters

Real systems need a way to handle compromised tokens or user logout. Without revocation, JWTs can stay valid until expiry.

Interview tip

Explain at least one revocation pattern and its trade-offs (memory, lookup cost, complexity).

Common attacks & defenses (XSS, CSRF, algorithm issues)

Simple real-life example (Understand first — very important for understanding)

  • Like locking doors and windows differently: one protects against someone breaking in from outside, the other from someone already inside.
  • You need different protections for different attack paths.

Real-world idea: JWTs don’t solve all security problems; you must still protect against XSS, CSRF, weak secrets, and misconfigured algorithms.

Technical definition

  • XSS: attacker runs JS in your page → can steal tokens stored in JS-accessible locations.
  • CSRF: attacker tricks browser into sending authenticated requests → mitigated by SameSite cookies, CSRF tokens, and origin checks.
  • Algorithm confusion: server must not accept `alg: 'none'` or weaker algorithms than expected.

Why it matters

Many JWT interview questions are actually about surrounding security practices, not just the token format itself.

Interview tip

Mention at least: use strong secrets/keys, enforce expected algorithm, defend against XSS (content security, sanitization) and CSRF (SameSite, CSRF token).

JWT in Node/Express (middleware example)

Simple real-life example (Understand first — very important for understanding)

  • Like a security checkpoint at the entrance of every restricted area.
  • Every request passes through it; if the pass (token) is valid, you get in; otherwise you’re stopped.

Real-world idea: you put JWT verification in Express middleware so all protected routes share the same logic and stay DRY.

Technical definition

  • Read token from Authorization header (Bearer), cookie, or custom header.
  • Verify with jwt.verify; if valid, attach user info to req and call next().
  • On failure, respond with 401/403 without hitting route handler.

Code example

function authMiddleware(req, res, next) {
  const header = req.headers.authorization || '';
  const [, token] = header.split(' ');
  if (!token) return res.status(401).json({ message: 'Missing token' });
  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET);
    req.user = payload;
    next();
  } catch (e) {
    return res.status(401).json({ message: 'Invalid or expired token' });
  }
}

app.get('/me', authMiddleware, (req, res) => {
  res.json({ userId: req.user.sub });
});

Why it matters

This pattern shows you know how to wire JWTs into real Node/Express apps, not just talk about them in theory.

Interview tip

Be able to sketch or write this middleware from memory, including error handling and reading the Authorization header.

More Backend & APIs notes

Node.js · Express · REST API · Google Cloud (GCP) · All developer notes