Sessions: the server stores the state, such as user id, roles and expiry. The client holds only a random session id, usually in a cookie.
- Every request needs a lookup in the session store.
- If you run many servers, they need a shared store.
- Revocation (cancelling access) is easy: delete the record, and the user is logged out.
JWTs (JSON Web Tokens): the claims (facts about the user) travel inside a signed token. Any service that has the key can verify it without a lookup. This suits distributed systems and APIs that many clients call. Cons:
- A token stays valid until it expires.
- So revocation needs short lifetimes, refresh tokens or a denylist. A denylist brings back server state.
- Tokens are larger.
- Their claims can go stale, for example after a role change.
When to choose each: for a classic web app with one backend, sessions are simpler and safer. JWTs fit better with many services, mobile clients, or delegated access through OAuth.
- Sessions keep state on the server, use an opaque id and are easy to revoke.
- Sessions need a shared store when you scale to many servers.
- A JWT is self-contained and verified without a lookup, so it works well across services.
- Revoking a JWT is hard and needs short expiry, refresh tokens or a denylist.
- Choose based on your architecture, not on what is popular.