JWT vs Session Authentication: Which Should You Use? Storage, Logout, and Security Compared

A JWT is signed, not encrypted, so anyone can read it. How sessions and JWTs each work, why forced logout is hard with JWTs, whether to store tokens in localStorage or an httpOnly cookie, and refresh tokens, with a demo where you decode and tamper with a token yourself.

"JWT is newer, so just use JWT, right?"

It's the most common question when building login. The short answer: neither is simply better; each fits different situations. And more services than you'd think are better served by old-fashioned sessions.

The difference fits in one sentence:

With sessions, the server remembers who's logged in. With JWTs, the client carries a proof of login around.


Sessions: the server remembers

  1. After a successful login, the server creates a session and stores { session ID → user info } in a store (memory, Redis, etc.).
  2. The browser receives only the session ID, as a cookie. (Set-Cookie: sid=a8f3...; HttpOnly)
  3. On every request the browser sends the cookie automatically, and the server looks up the session ID to find out who you are.

The session ID itself is a meaningless random string. All the real information lives on the server.

JWT: the client carries the proof

  1. After a successful login, the server creates and signs a token containing user info and returns it.
  2. The client stores the token and sends it on each request in an Authorization: Bearer <token> header.
  3. The server doesn't look anything up; it only verifies the signature, and if the token hasn't been forged, it trusts the info inside.

A JWT (JSON Web Token) has three parts separated by dots (.):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9      ← header (algorithm)
.eyJzdWIiOiI0MiIsIm5hbWUiOiJraW0iLC...   ← payload (user info)
.zaG-JogpvAo1fU4iPmB29IwMc6r3x07Ouug...  ← signature

A JWT is not encrypted: open one yourself

Here's the most common misconception. The header and payload are not encrypted, only Base64URL-encoded, so anyone can decode and read them. Try it in the preview below.

The two things this demo shows are the core of JWTs:

  • Anyone can read the contents. So never put passwords, national ID numbers, or internal data in the payload.
  • Changing the contents breaks the signature. Even if you change role to admin, you can't produce a valid signature without the server's secret key, so the server rejects it.

A JWT signature doesn't "hide the contents"; it guarantees the contents haven't changed.

When verifying JWTs on the server, specify the allowed algorithms (for example algorithms: ["HS256"]). Trusting the alg value in the token header can open a hole where unsigned tokens like alg: "none" are accepted. Don't roll your own; use a well-tested library.


The decisive difference: forced logout

Most of the pros and cons come down to "does the server remember state?"

SessionsJWT
Where login state livesServer-side storeThe token itself
What the server does per requestLooks up the storeVerifies the signature (no lookup)
Forced logout, account suspensionImmediate, by deleting the sessionThe token stays valid until it expires
Scaling to multiple serversNeeds a shared store (Redis, etc.)Just share the secret key
Sharing with other services, mobile appsLimited by cookie domainsWorks anywhere via a header
Data sizeA short ID in a cookieHundreds of bytes or more per request

The biggest weakness of JWTs is that once issued, they can't be taken back. Even if the user changes their password or an admin suspends the account, tokens already issued stay valid until they expire. Preventing that means keeping a "revoked tokens" list on the server and checking it every time, and then the server is remembering state, just like sessions.

So JWT setups usually keep access tokens short-lived (say, 15 minutes) and use refresh tokens to get new access tokens.

TokenLifetimeWhere it's storedRole
Access tokenShort (5–15 min)Memory, etc.Sent with API requests
Refresh tokenLong (days to weeks)httpOnly cookieGets new access tokens. The server tracks them so they can be revoked

A common pattern is to issue a new refresh token every time one is used (rotation), and treat a reused old token as theft and revoke everything.


StorageStolen via XSS?CSRF riskNotes
localStorageYes (readable by JavaScript)None (not sent automatically)One malicious script running on your page and the token is gone
httpOnly cookieNo (JavaScript can't read it)Yes (sent automatically)Largely mitigated with the SameSite attribute

XSS (Cross-Site Scripting) is when an attacker's script runs on your page. CSRF (Cross-Site Request Forgery) is when another site gets the user's browser to send requests to your server with their cookies.

When you put auth data in a cookie, use these attributes together:

Set-Cookie: sid=a8f3...; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=86400
AttributeEffect
HttpOnlyCan't be read by JavaScript (document.cookie) → prevents theft via XSS
SecureSent only over HTTPS
SameSite=LaxNot sent on requests started from other sites (except things like top-level link navigation) → blocks most CSRF

An httpOnly cookie doesn't fully stop XSS. A malicious script can't steal the token, but it can still send requests on the user's behalf from inside that page. Whatever the storage, preventing XSS itself (escaping input, CSP) is the baseline.


So which should you use?

SituationRecommendation
A typical web app (frontend and API on related domains)Sessions + httpOnly cookies. Simple, and forced logout is easy
Mobile apps, several services sharing one loginJWT (short access tokens + refresh tokens)
Server-to-server calls, auth inside microservicesJWT. Verifiable without a store lookup
Services where instant blocking matters (finance, admin tools)Sessions, or JWTs with a revocation list

Summary: why this is worth knowing

MisconceptionReality
"JWTs are encrypted, so they're safe"They're only signed; anyone can read them
"JWT is newer than sessions, so it's better"It has a clear weakness: forced logout is hard
"Just put the token in localStorage"One XSS and it's stolen. Consider httpOnly cookies
"Cookies are dangerous because of CSRF"SameSite and CSRF tokens handle it well

When choosing an auth approach, set trends aside and ask first: "Who needs to remember login state?" and "Will I ever need to block an account immediately?" The answers decide most of it.