What Happens When You Type a URL and Press Enter
DNS lookups, TCP and TLS handshakes, HTTP requests, servers, and the browser's rendering pipeline. The whole journey of a web page, explained so it finally clicks.
Read →JWTs are popular, but popular isn't the same as right for your app. A clear comparison of sessions and tokens, where each one shines, and the storage mistakes that create security holes.
Almost every tutorial now reaches for JSON Web Tokens (JWTs) when it's time to add login. That's led a lot of developers to think sessions are outdated. They aren't. Sessions and JWTs solve the same problem in different ways, and for many web apps the "old" approach is the better one.
Let's compare them honestly.
HttpOnly, Secure and SameSite.The cookie itself means nothing. All the real information lives on the server.
Authorization: Bearer header.The token carries its own information. That's its superpower and its biggest weakness.
| Sessions | JWTs | |
|---|---|---|
| Where state lives | Server | Inside the token |
| Logout / revoke instantly | Easy: delete the session | Hard: token stays valid until it expires |
| Lookup per request | Yes (fast with Redis) | No (just signature verification) |
| Works across many services | Needs a shared session store | Easy: any service with the key can verify |
| Mobile apps / third-party APIs | Possible, a bit awkward | Natural fit |
| Size per request | Tiny ID | Can grow large with claims |
This is the part tutorials skip. Suppose a user's account is compromised, or you ban someone, or they click "log out of all devices." With sessions, you delete the server-side record and they're out immediately.
With JWTs, the token stays valid until it expires. Fixing that means one of:
Notice that both bring back server-side state. At that point, you've rebuilt sessions with extra steps. That's fine when you need what JWTs offer, but it's worth knowing going in.
This causes more real-world vulnerabilities than the choice of JWT vs session itself.
localStorage: convenient, but any JavaScript on the page can read it. One XSS bug, or one compromised npm dependency, and your users' tokens are gone.HttpOnly cookie: JavaScript can't read it at all, which makes token theft through XSS far harder. Add Secure and SameSite=Lax (or Strict) and you've also mitigated most CSRF.For browser-based apps, an HttpOnly cookie is the safer default whether it holds a session ID or a JWT.
alg: none, and don't let the token choose its own algorithm.exp, iss and aud claims, not just the signature.For a typical full stack web app: use cookie-based sessions, or a mature auth library or provider that handles it for you. Reach for JWTs when you actually have multiple services, mobile clients or third-party integrations that benefit from stateless verification.
Whatever you choose, authentication is just one item on the list. Here's the rest: a web application security checklist.
No. Neither is inherently more secure. Security depends on implementation: storage, expiry, revocation and transport. Sessions are often easier to get right.
For browser apps, prefer an HttpOnly, Secure, SameSite cookie. localStorage is readable by any script on the page, which makes XSS much more damaging.
They avoid a lookup per request, which helps at very large scale or across many services. For most apps, a session lookup in Redis or an indexed table takes about a millisecond and isn't a bottleneck.
DNS lookups, TCP and TLS handshakes, HTTP requests, servers, and the browser's rendering pipeline. The whole journey of a web page, explained so it finally clicks.
Read →There are dozens of HTTP status codes, but about fifteen cover nearly everything. What each one means, when to return it, and the mix-ups (401 vs 403, 301 vs 302) that confuse everyone.
Read →A, AAAA, CNAME, MX, TXT and NS records in plain English, why DNS changes seem slow, and the troubleshooting commands that tell you what is really going on.
Read →