JWT vs Session: which authentication mechanism should you choose?

Authenticating a user means knowing who they are on every request. Two main families compete: server sessions, where the server keeps track of the logged-in user, and JSON Web Tokens (JWT), where the identity travels inside a signed token carried by the client. The choice affects security, the ability to scale and the ease of logging a user out. Here is how to decide depending on your context.

Server sessions (stateful)

With a session, the server creates a session identifier at login, stores the associated data (identity, roles, cart) on the server side (memory, Redis, database) and returns to the browser a cookie containing only that identifier. On every request, the server reads the cookie, finds the session again and knows who is speaking.

  • Server-side state: the source of truth stays on the server, the client only carries an opaque reference.
  • Immediate revocation: deleting the session on the server side logs the user out instantly.
  • Cookie: automatically transmitted by the browser, ideally with HttpOnly, Secure and SameSite.

JSON Web Tokens (stateless)

A JWT is a self-contained token made of three parts encoded in base64url and separated by dots: a header, a payload (the claims, for example the user identifier and the expiry) and a signature. The server signs the token at login; afterwards it only needs to verify the signature to trust the content, without storing anything.

  • Stateless: all the necessary information is in the token, the server does not need shared memory.
  • Verifiable everywhere: any service that knows the key can validate the token, handy for distributed architectures and SSO.
  • Tools: you can inspect a token with our JWT decoder, check its signature with the JWT verifier or forge one with the JWT generator.

Comparison table

Criterion Server session JWT
StateStateful (stored on server)Stateless (carried by the client)
Server storageRequired (Redis, database)None
RevocationImmediateDifficult before expiry
Horizontal scalabilityShared store requiredNative
Transmitted sizeSmall (one identifier)Larger (signed claims)
Cross-domain / SSORestrictiveWell suited
XSS surfaceLow with an HttpOnly cookieHigh if stored in localStorage

Security: XSS, CSRF and revocation

Both approaches are safe when properly implemented, but their risks differ.

  • XSS: an HttpOnly session cookie is inaccessible to JavaScript, so it is protected from theft through injection. A JWT stored in localStorage, on the other hand, is readable by any script, which makes it a prime target. Storing the JWT in an HttpOnly cookie cancels this advantage of the JWT but reintroduces the CSRF risk.
  • CSRF: cookies are sent automatically, so they are vulnerable to CSRF without protection (SameSite attribute, anti-CSRF token). A JWT sent manually in the Authorization header is not affected.
  • Revocation: this is the weak point of the JWT. As it is self-contained, you cannot invalidate it before its expiry without reintroducing server state (revocation list, blacklist). A session is deleted instantly.

Scalability and architecture

On a single server, sessions are trivial. As soon as you spread the load across several instances, each instance must access the sessions: you need a shared store (Redis) or sticky sessions. The JWT shines here, because any instance validates the token without a network call or shared storage.

  • Microservices: a JWT propagates the identity from one service to another without a central database.
  • Public and mobile APIs: the JWT avoids cookie management on the native client side.
  • Classic monolith: the session remains simpler and safer by default.

When to choose one or the other

Choose sessions when

  • You are building a classic web application with server-side rendering
  • Immediate revocation is critical (banking, healthcare, back office)
  • You want the safest solution by default, with the fewest pitfalls
  • Your infrastructure handles a shared session store without pain

Choose the JWT when

  • You expose an API consumed by SPAs, mobile apps or third parties
  • You have a microservices architecture or cross-domain SSO
  • You must scale horizontally without a shared store
  • You accept managing short expiry and token refresh

Recommendation

For most web applications, server sessions remain the safest and simplest choice: immediate revocation, an HttpOnly cookie and zero token management on the client side. Reserve the JWT for cases where its statelessness brings real value: stateless APIs, mobile, microservices, SSO.

If you opt for the JWT, keep a short lifetime (a few minutes) coupled with a refresh token stored in an HttpOnly cookie, and provide a revocation list for sensitive cases. You then combine the best of both worlds.

Frequently asked questions

Is a JWT encrypted?

No, by default a JWT is only signed, not encrypted. Its payload is encoded in base64url and readable by anyone who intercepts it. Never put sensitive data in clear text inside a JWT. To encrypt the content, you must turn to JWE (JSON Web Encryption).

Where should you store a JWT on the client side?

The safest option is an HttpOnly, Secure and SameSite cookie, which protects against theft through XSS. The localStorage is simpler but exposes the token to any malicious script. Avoid it for high-privilege tokens.

How do you log a user out with a JWT?

As the token is self-contained, an actual logout requires either waiting for its expiry, or keeping a revocation list on the server side. This is why we use short lifetimes and a refresh token that can, in turn, be revoked.

Can you combine sessions and JWT?

Yes, this is a common practice: a short-lived JWT access token for API calls, and a refresh token managed like a session (stored and revocable on the server side) to renew the access token.