Search

JWT vs Sessions: How Authentication Really Works

The short answer

Quick answer: After you log in, the server needs a way to recognise your later requests. With sessions, the server stores your login state and gives the browser a random session ID in a cookie; every request sends the ID, and the server looks it up. With JWTs (JSON Web Tokens), the server gives the client a signed token that contains your identity; each request sends the token, and the server only verifies the signature, with no lookup. Sessions are simple, easy to revoke and the sensible default for a web application. JWTs avoid a shared session store, which helps when many services or outside parties need to verify identity, but they are hard to revoke before they expire.

The problem: HTTP forgets

HTTP is stateless. Each request stands alone, and the server has no built-in memory that the person requesting /account is the one who logged in a moment ago. Something must travel with every request to prove it.

Two terms to keep apart:

  • Authentication: proving who you are (logging in).
  • Authorisation: deciding what you are allowed to do.

Both sessions and JWTs are ways of carrying the result of authentication from one request to the next.

How sessions work

  1. You submit your username and password.
  2. The server verifies them. See how passwords should be stored.
  3. The server creates a session record, such as user ID, creation time and expiry, in a store: a database or an in-memory store such as Redis.
  4. It sends the browser a cookie containing a long, random session ID.
  5. The browser returns the cookie automatically on every request to that site.
  6. The server looks up the ID, finds the session and knows who you are.
  7. Logging out deletes the record. The ID becomes meaningless.
Set-Cookie: sid=8f3a9c...; HttpOnly; Secure; SameSite=Lax; Path=/

The session ID is an opaque reference. It carries no information. All the state lives on the server, which is why this is called stateful authentication.

Strengths

  • Instant revocation. Delete the session and access ends immediately. "Log out everywhere" is trivial.
  • Small cookie. Nothing sensitive is held by the client.
  • Simple and mature. Every web framework has it built in.

Costs

  • A lookup on every request. In practice this is a sub-millisecond read from a fast store.
  • Shared state. With several servers, they must all reach the same session store.
  • Cookies are tied to a domain, which is awkward across unrelated domains and for some non-browser clients.

The OWASP Session Management Cheat Sheet describes how to do this well.

How JWTs work

A JWT, defined in RFC 7519, is a string in three parts separated by dots:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0MiIsImV4cCI6MTc2MDAwMDAwMH0.Xk3v...
       header                      payload                  signature
  • Header: the token type and signing algorithm.
  • Payload: claims about the user and the token.
  • Signature: computed over the header and payload with a secret or private key.

A decoded payload:

{
  "sub": "42",
  "role": "editor",
  "iat": 1759996400,
  "exp": 1760000000
}

The flow:

  1. You log in.
  2. The server builds the payload and signs it.
  3. The client stores the token and sends it with each request, usually in an Authorization: Bearer <token> header.
  4. The server verifies the signature and checks the expiry. If both pass, it trusts the claims. No database lookup is needed.

Two points are frequently misunderstood:

  • A JWT is signed, not encrypted. The payload is only Base64-encoded. Anyone holding the token can read it. Never put secrets in one.
  • The signature prevents tampering. If someone changes "role": "editor" to "role": "admin", the signature no longer matches and the token is rejected.

Signing can be symmetric (one shared secret, HS256) or asymmetric (sign with a private key, verify with a public key, such as RS256 or ES256). With asymmetric signing, other services can verify tokens without being able to create them. See how public key cryptography works.

The revocation problem

Because the server keeps no record, a valid JWT stays valid until it expires. If a user logs out, changes their password, is banned, or has a token stolen, that token still works.

The usual answers:

ApproachHow it worksTrade-off
Short expiryAccess tokens live for minutesLimits the window; users need a way to get new tokens
Refresh tokensA long-lived token, stored server-side and revocable, is exchanged for new access tokensReintroduces server state
Deny listThe server keeps a list of revoked token IDs and checks it on each requestA lookup on every request, which is what JWTs were meant to avoid
Token versionStore a version number per user; reject tokens with an older oneAlso a lookup

In other words, as soon as you need reliable revocation, you are keeping state again. The common production pattern is a short-lived access token plus a refresh token that is stored, rotated on each use, and can be revoked.

Side by side

SessionsJWTs
Where state livesOn the serverIn the token
Per-request costA store lookupA signature check
RevocationImmediateDifficult without extra state
SizeA short IDHundreds of bytes or more, on every request
ScalingNeeds a shared storeAny server with the key can verify
Changing a user's permissionsTakes effect at onceTakes effect when the token is reissued
Across services and domainsAwkwardStraightforward
Typical useWeb applicationsAPIs, service-to-service calls, federated login

Where the token is kept

This question is separate from the choice of sessions or JWTs, and it matters more for security.

StorageReadable by page scripts (XSS risk)Sent automatically (CSRF risk)
HttpOnly cookieNoYes; mitigate with SameSite and CSRF tokens
localStorage / sessionStorageYesNo
In memory onlyOnly while the page is openNo

A token in localStorage can be read by any script running on the page, including one injected through cross-site scripting. An HttpOnly cookie cannot be read by scripts at all. For browser applications, an HttpOnly, Secure, SameSite cookie is generally the safer place, and a JWT can be stored in one. See cookies vs localStorage vs sessions.

Common JWT mistakes

  • Not verifying the signature, or only decoding the token.
  • Accepting whatever algorithm the token names, including none. Always fix the expected algorithm on the server.
  • Weak signing secrets that can be guessed offline.
  • No expiry, or very long-lived tokens.
  • Sensitive data in the payload.
  • Not checking the audience and issuer, so a token minted for one service is accepted by another.
  • Using JWTs as sessions with no way to revoke them.

Use a maintained library and its verification function. Do not write token parsing yourself; see never roll your own crypto.

Which should you use?

Choose sessions when:

  • You are building a conventional web application with your own back end.
  • You need to log users out or cut off access immediately.
  • You want the simplest thing that is secure by default.

Choose JWTs when:

  • Several independent services must verify identity without calling a central store.
  • You are issuing tokens to third parties or using a single sign-on provider. OAuth and OpenID Connect commonly use JWTs; see how OAuth works.
  • Calls are between services, with short-lived tokens.

A common hybrid: the browser holds an ordinary session cookie with a gateway or back end, and that back end uses short-lived JWTs when calling internal services.

"JWTs scale better" is true in principle and rarely decisive. A session lookup in a fast store is cheap, and most applications that adopt JWTs to avoid server state end up adding it back for revocation.

Frequently asked questions

Are JWTs more secure than sessions?

No. They are a different trade-off. Sessions are easier to secure and revoke; JWTs are easier to verify across systems.

Can a JWT be revoked?

Not by itself. You need short lifetimes, refresh tokens, or a server-side deny list.

Is the data in a JWT encrypted?

Not in a standard signed JWT. The payload is readable by anyone who has the token. The signature only prevents modification.

Where should I store a JWT in the browser?

Preferably in an HttpOnly, Secure, SameSite cookie, so scripts cannot read it.

Conclusion

Sessions keep state on the server and hand the client a meaningless ID. JWTs hand the client a signed statement and keep nothing. The first gives you control; the second gives you independence between services. For most web applications, sessions are the simpler and safer choice, and JWTs earn their place when identity has to cross system boundaries.

Related articles

Sources and further reading

Usama Muneer

Usama Muneer

Coder, Blogger, Tech Speaker & Web Technologies Enthusiast. Passionate about working on open-source Programming languages & Tools while utilizing my Product Development skills.

Your experience on this site will be improved by allowing cookies Cookie Policy