Module 4 · Authentication and security

Lesson 18 — Sessions vs tokens

JWT and its risks, refresh tokens and what fits each client best.

Published
In this lesson
  1. Exercise 1 — Token login
  2. Exercise 2 — Look inside the JWT
  3. Exercise 3 — Where the token lives
  4. Exercise 4 — ADR-0008
  5. Exercise 5 — Logout that actually works
  6. Submit

pip install djangorestframework-simplejwt. Do not look at solutions.md before submitting.

Exercise 1 — Token login

  1. Configure SimpleJWT (access 10 min, refresh 7 days, rotation + blacklist) and the token endpoints. Log in with your test user and note both tokens.
  2. Call GET /api/reservations/ with Authorization: Bearer <access>: 200. Without the header: 401. With an expired token (wait, or set the lifetime to 5s): 401 with token_not_valid.
  3. Refresh: get a new access and verify the old refresh no longer works (blacklist after rotation).

Exercise 2 — Look inside the JWT

  1. Paste your access token into jwt.io (or base64 -d each part): which claims do you see? Is your email there? Could your card number go there?
  2. Change one character of the payload and use the token: what exact error? (invalid signature).
  3. Question: what would happen if the payload carried the role and someone edited it? (without the signature they can't — explain the mechanism).

Exercise 3 — Where the token lives

  1. Serve a mini test page that fetches your API with the access token in localStorage vs in an HttpOnly; SameSite=Lax cookie. Inject a simulated "XSS" (a script reading storage/document.cookie): what can it steal in each case?
  2. Configure CSRF_TRUSTED_ORIGINS and test the cookie + SameSite=Lax flow from an "evil origin" (curl with a fake Origin): does it pass Django's CSRF?
  3. Write the 3-line summary for your README: what token lives where on TicketFlow and why.

Exercise 4 — ADR-0008

Write the ADR "Authentication: short JWT + rotated refresh in an HttpOnly cookie" — context (web + mobile, revocable purchases), decision, rejected alternatives (session only, long JWT in localStorage), consequences (blacklist in Redis/DB, logout = refresh blacklist, mobile with keychain).

Exercise 5 — Logout that actually works

  1. Implement an authenticated POST /api/auth/logout/: blacklist the user's refresh. Verify: after logout, the refresh no longer yields an access.
  2. And the already-issued access (valid up to 10 min)? Is that acceptable? How would you cut it otherwise (hint: blacklist by jti checked on every request — and what do you pay)?

Submit

Paste configuration, tokens (trimmed: NOT the real ones!) and conclusions. Next: Lesson 19 — OAuth2 and OpenID Connect.