Sessions vs JWT
A practical comparison of session-based authentication and JWT authentication, including cookies, token storage, revocation, expiration, security, scalability and common implementation patterns.
Authentication answers a simple question: how does an application know which user is making a request? Two of the most common approaches are server-side sessions and JSON Web Tokens (JWTs). Both can provide secure authentication, but they solve the problem in different ways.
With session-based authentication, the server stores authentication state and gives the browser a session identifier. With JWT authentication, the server issues a signed token containing claims that can be verified on later requests.
The difference is not simply 'sessions are stateful and JWTs are stateless'. The real design questions involve where authentication state lives, how credentials are transported, how logout works, how access is revoked, how multiple services validate identity and how tokens are stored.
This guide explains both approaches and shows how to choose an authentication architecture based on the requirements of the application rather than treating JWT as a universal replacement for sessions.
What Is Session-Based Authentication?
In session-based authentication, the server creates a session after the user successfully authenticates. The session is associated with the user's account and stored on the server or in a server-side session store.
The browser usually receives a random session identifier in a cookie. On subsequent requests, the browser automatically sends that cookie back to the server.
HTTP/1.1 200 OK
Set-Cookie: session_id=random-server-generated-value; HttpOnly; Secure; SameSite=LaxThe session identifier itself normally does not contain the user's profile or permissions. It acts as a reference that allows the server to find the corresponding authentication state.
How Sessions Work
- The user submits login credentials.
- The server verifies the credentials.
- The server creates an authenticated session.
- The server generates a random session identifier.
- The session identifier is sent to the browser in a cookie.
- The browser sends the cookie with subsequent requests.
- The server looks up the session and identifies the user.
- The server can invalidate the session when the user logs out.
The important property is that the authoritative authentication state remains on the server. The browser generally holds only an opaque identifier.
What Is JWT Authentication?
JWT stands for JSON Web Token. A JWT is a compact token format that can carry claims and be digitally signed so that a server can verify that the token was issued by a trusted party and has not been modified.
xxxxx.yyyyy.zzzzzA JWT normally consists of three Base64URL-encoded parts separated by dots: a header, a payload and a signature.
{
"sub": "12345",
"role": "user",
"exp": 1790000000
}The payload contains claims. It is not encrypted merely because it is a JWT. Anyone who obtains the token can generally decode its header and payload, so sensitive secrets should not be placed inside ordinary JWT claims.
How JWT Authentication Works
- The user authenticates with the server.
- The authentication service issues a signed JWT.
- The client stores or otherwise manages the token.
- The client sends the JWT with later requests.
- The receiving service verifies the signature and relevant claims.
- The service accepts the request if the token is valid and the required authorization checks succeed.
GET /api/profile HTTP/1.1
Authorization: Bearer eyJhbGciOi...The receiving service can often validate a JWT without querying a central session database on every request. This is one of the main architectural differences between the two approaches.
Sessions vs JWT at a Glance
| Aspect | Sessions | JWT |
|---|---|---|
| Authentication state | Stored server-side | Encoded in the token claims |
| Client credential | Usually an opaque session identifier | Signed token |
| Server lookup | Usually required | Often not required for signature validation |
| Immediate revocation | Straightforward | Requires additional design |
| Logout | Invalidate the session | Invalidate or stop accepting the token through an appropriate token strategy |
| Horizontal scaling | Requires shared session storage or appropriate session affinity | Can be convenient across independent services |
| Token contents | Usually not exposed in the identifier | Claims are readable unless encrypted separately |
| Cookie support | Very common | Can also use secure cookies |
| Authorization header | Possible, but less typical | Common for API requests |
Stateful vs Stateless Authentication
Session authentication is commonly described as stateful because the server maintains authentication state associated with the session identifier.
JWT authentication is commonly described as stateless because a service can validate a self-contained token without consulting the issuing server for every request.
However, JWT does not automatically make an entire authentication system stateless. A real application may maintain refresh-token records, token revocation lists, user sessions, device records, authorization data or other server-side state.
Where Should the Credential Be Stored?
Credential storage is one of the most important security decisions in browser authentication. Both sessions and JWTs can be transported using cookies, and a JWT does not have to be stored in localStorage.
HttpOnly Cookies
An HttpOnly cookie cannot be read by normal client-side JavaScript. This makes it useful for authentication credentials because an XSS vulnerability cannot simply use document.cookie to read the credential.
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=LaxThe same approach can be used with a JWT stored in a secure HttpOnly cookie. Using JWT does not require exposing the token to JavaScript.
localStorage and JWT
A common JWT implementation stores an access token in localStorage and reads it from JavaScript when sending requests.
const token = localStorage.getItem("accessToken");
fetch("/api/profile", {
headers: {
Authorization: `Bearer ${token}`
}
});Cookies vs Authorization Headers
Sessions are traditionally associated with cookies, while JWTs are frequently associated with Authorization: Bearer headers. These are conventions, not hard requirements.
| Transport | Typical use |
|---|---|
| HttpOnly cookie | Browser authentication where the browser manages the credential automatically. |
| Authorization: Bearer | APIs and clients where the application explicitly attaches an access token. |
| Secure cookie containing JWT | JWT-based browser authentication without exposing the token to JavaScript. |
The transport mechanism should be selected based on the client type, cross-origin requirements, CSRF model, XSS exposure and application architecture.
Session IDs Should Be Random
A session identifier should be generated using a cryptographically secure random mechanism and contain enough entropy to make guessing infeasible.
The session identifier should not contain predictable information such as a user ID, timestamp or sequential number.
session_id = cryptographically_random_valueJWT Signing and Verification
A JWT can be signed using a symmetric key or an asymmetric key pair. With symmetric signing, the issuer and verifier share a secret. With asymmetric signing, the issuer uses a private key and services can verify signatures with the corresponding public key.
| Approach | Signing | Verification |
|---|---|---|
| Symmetric | Shared secret | Shared secret |
| Asymmetric | Private key | Public key |
The verification process should validate the expected algorithm, signature and relevant claims. A JWT should never be accepted merely because its payload can be decoded.
Important JWT Claims
JWT defines registered claim names that can be useful for authentication systems. Applications can also define private claims.
| Claim | Meaning |
|---|---|
| iss | Issuer of the token. |
| sub | Subject of the token, commonly representing the authenticated user or entity. |
| aud | Intended audience. |
| exp | Expiration time. |
| nbf | Not-before time. |
| iat | Issued-at time. |
| jti | Unique identifier for the token. |
JWT Expiration
Access tokens should generally have a limited lifetime. The exp claim can define when a JWT should no longer be accepted.
{
"sub": "12345",
"iat": 1780000000,
"exp": 1780003600
}Short-lived access tokens reduce the amount of time an attacker can use a stolen token, but short expiration alone does not solve token theft or revocation requirements.
Refresh Tokens
A common JWT architecture separates short-lived access tokens from longer-lived refresh tokens.
- The access token is used for normal API requests.
- The access token expires relatively quickly.
- A refresh token is used to obtain a new access token.
- The refresh token can have a longer lifetime.
- The server can maintain state associated with refresh tokens when revocation and rotation are required.
This means a JWT-based authentication system can still have significant server-side state. Stateless access-token validation and stateful refresh-token management can coexist.
Session Expiration
Session systems can also use both absolute and idle expiration. An absolute lifetime limits how long a session can exist, while an idle timeout can invalidate a session after a period without activity.
Because the server owns the session state, changing or invalidating these values can take effect immediately when the session is checked.
Logout: Sessions vs JWT
Logout illustrates one of the biggest practical differences between server-side sessions and self-contained access tokens.
For a session, the server can invalidate the session record. Even if the browser still sends the old session ID, the server can reject it.
A signed JWT may remain cryptographically valid until its expiration time. If the server does not maintain a revocation mechanism, simply deleting the token from the client does not invalidate a copy that an attacker may already possess.
JWT Revocation
Immediate JWT revocation requires additional architecture. Possible approaches include short-lived access tokens, refresh-token rotation, server-side token records, revocation lists or changing the signing credentials in situations where broader invalidation is appropriate.
Each strategy introduces trade-offs between security, complexity, storage and operational behavior.
Session Fixation
Session-based systems need to protect against session fixation. After successful authentication, the application should establish a new session identifier rather than continuing to use an identifier that may have existed before login.
This prevents an attacker who somehow caused a victim to use a known session identifier from reusing that identifier after the victim authenticates.
JWT Replay
A stolen bearer JWT can generally be replayed by whoever possesses it until it expires or the server rejects it through an additional mechanism.
This is why token confidentiality, HTTPS, short access-token lifetimes and appropriate refresh-token handling are important parts of JWT architecture.
CSRF and Sessions
Cookies are automatically attached by the browser to matching requests. This behavior creates a CSRF consideration for cookie-based authentication.
SameSite cookie settings can reduce CSRF exposure, and applications may also use CSRF tokens or other request-validation mechanisms depending on their architecture.
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=LaxCSRF and Authorization Bearer Tokens
A token placed in an Authorization header is not automatically attached to arbitrary cross-site requests in the same way as a cookie. This can change the CSRF threat model.
However, moving a token into JavaScript-accessible storage introduces other risks, particularly if an XSS vulnerability allows an attacker to read the token.
XSS and Authentication Credentials
XSS can affect both session-based and JWT-based authentication. The important question is where the credential is accessible and what an attacker can do after gaining script execution.
HttpOnly cookies can prevent JavaScript from directly reading the cookie value. However, an XSS vulnerability can still potentially make authenticated requests from the victim's browser because the browser continues to attach the cookie.
Scaling Session-Based Authentication
A single application server can store sessions locally, but multiple application instances need a way to access the same authentication state.
A shared session store such as Redis or a database can allow multiple instances to validate the same session identifiers.
This adds infrastructure, but it also provides centralized control over authentication state and revocation.
Scaling JWT Authentication
JWTs can be convenient when multiple services need to validate the same identity information. A service can verify the token using a shared secret or public key without querying a central session store for every request.
This can simplify certain distributed architectures, but it does not eliminate the need for key management, token expiration, authorization checks and potentially stateful refresh-token infrastructure.
JWTs in Microservices
In a microservice architecture, a signed access token can carry identity and authorization-related claims that multiple services can verify.
{
"iss": "https://auth.example.com",
"sub": "user-123",
"aud": "orders-api",
"exp": 1780003600,
"scope": "orders:read"
}The audience claim can help ensure that a token issued for one service is not automatically accepted by another service that should not trust it.
Sessions in Modern Web Applications
Server-side sessions remain a practical choice for traditional websites and browser applications. A session cookie can integrate naturally with server-rendered applications, server-side authorization and centralized logout.
Frameworks and authentication libraries can also abstract much of the session management, cookie configuration and persistence logic.
JWTs in SPAs
Single-page applications can use JWT access tokens, particularly when communicating with APIs that are designed around bearer tokens.
However, an SPA does not inherently require JWT. A browser application can also use secure cookies and server-side sessions. The choice should follow the API and authentication architecture rather than the fact that the frontend is built with React, Vue or another SPA framework.
Sessions vs JWT for Next.js
A Next.js application can use either approach. Server-side sessions work naturally when the application controls the web server and can read an HttpOnly cookie during server-side requests.
JWTs can also be useful when the application exposes APIs consumed by multiple clients or when other services need to verify access tokens independently.
For a typical web application where the browser is the primary client and centralized authentication state is acceptable, a secure session cookie is often a straightforward architecture. For distributed APIs and service-to-service scenarios, signed access tokens may fit the architecture more naturally.
Sessions vs JWT for Mobile Applications
Mobile applications can use token-based authentication because the client is not a traditional browser and may communicate directly with APIs.
The security model still depends on secure credential storage, token lifetime, refresh-token rotation and device lifecycle management. A JWT does not become secure simply because the client is a mobile application.
Sessions vs JWT for Machine-to-Machine APIs
Machine-to-machine authentication has different requirements from browser login. Service identities, key rotation, scopes, audiences and credential management often matter more than browser cookies.
JWT-based access tokens can be useful in these environments, particularly when services need independently verifiable credentials. Other mechanisms, such as API keys or OAuth 2.0 client credentials, may also be appropriate depending on the architecture.
Performance Considerations
A JWT can reduce the need for a session-store lookup during access-token validation. This can be useful in distributed systems, but JWT verification itself still requires cryptographic work.
Session lookup performance depends heavily on the session store and caching architecture. A well-designed session system can be very fast, especially when using an appropriate shared in-memory store.
Authentication should not be optimized around the assumption that avoiding a database lookup is automatically more important than centralized control and operational simplicity.
JWT Payload Size
JWTs carry their claims with every request where the token is sent. Adding many claims increases the size of HTTP requests.
Do Not Put Secrets in JWT Payloads
JWT payloads are normally encoded, not encrypted. Base64URL encoding makes the content easy to decode but does not provide confidentiality.
{
"sub": "12345",
"email": "[email protected]",
"role": "admin"
}Even if a token is signed securely, its payload should be considered readable by anyone who obtains the token. If confidentiality is required, a different mechanism such as encrypted tokens may be necessary.
JWT Validation Checklist
- Verify the cryptographic signature.
- Allow only the algorithms that the application explicitly expects.
- Validate the issuer when issuer validation is required.
- Validate the audience for services that require a specific audience.
- Validate expiration.
- Validate not-before and issued-at claims when relevant.
- Check required scopes or roles separately from token signature validation.
- Use HTTPS to protect tokens in transit.
- Keep access-token lifetimes appropriate for the application's risk profile.
Session Cookie Security Checklist
- Use HTTPS in production.
- Set the Secure attribute.
- Use HttpOnly for authentication cookies that do not need JavaScript access.
- Choose an appropriate SameSite setting.
- Generate unpredictable session identifiers.
- Regenerate the session identifier after authentication.
- Set reasonable session expiration and idle timeouts.
- Invalidate sessions when the user logs out.
- Protect sensitive state-changing operations against CSRF.
- Avoid placing sensitive application data directly in the session cookie unless the mechanism is designed for it.
Can You Combine Sessions and JWTs?
Yes. Authentication architectures do not have to choose one mechanism for every component.
For example, a browser application can use a secure session cookie while an internal API gateway exchanges the authenticated identity for short-lived service tokens. Another architecture might use a session for the browser and JWT access tokens for a separate API consumed by multiple clients.
The important part is defining clear trust boundaries and avoiding unnecessary credential duplication.
Common JWT Misconceptions
- JWT is not automatically more secure than sessions.
- JWT does not have to be stored in localStorage.
- JWT does not automatically provide logout or immediate revocation.
- JWT payloads are not secret merely because they are signed.
- JWT does not eliminate all server-side state.
- Using JWT does not eliminate the need for HTTPS.
- JWT does not replace authorization checks.
- A valid signature does not mean that every service should accept the token.
Common Session Misconceptions
- Sessions do not require storing the entire user account in the cookie.
- Sessions can scale horizontally with shared session storage.
- Session cookies can be protected with HttpOnly, Secure and SameSite attributes.
- Sessions do not eliminate CSRF considerations.
- A session does not automatically protect against XSS.
- Server-side sessions can support immediate revocation.
How to Choose Between Sessions and JWT
Start with the architecture rather than the token format. Ask where authentication state should live, which clients need access, whether multiple independent services need to verify identity and how important immediate revocation is.
| Requirement | Potentially suitable approach |
|---|---|
| Traditional browser application | Server-side session with secure cookie. |
| Centralized server-side authentication state | Session-based authentication. |
| Multiple APIs independently validating access tokens | JWT access tokens can be useful. |
| Need for straightforward immediate revocation | Server-side sessions provide a direct model. |
| Distributed service architecture | JWTs may simplify independent token verification. |
| Browser application with server-controlled cookies | Sessions or JWTs in HttpOnly cookies can both be designed. |
A Practical Decision Process
- Identify all clients: browser, mobile application, third-party integration or backend service.
- Determine whether authentication state should be centrally controlled.
- Determine whether multiple services need independent token verification.
- Define logout and revocation requirements before selecting the token format.
- Choose a credential transport mechanism appropriate for the client.
- Define expiration and refresh behavior.
- Design CSRF and XSS defenses together with credential storage.
- Define how signing keys or session storage will be managed.
- Test authentication failure, expiration, logout and token-replay scenarios.
Frequently Asked Questions
Are sessions more secure than JWT?
Neither mechanism is automatically more secure. Security depends on credential storage, transport, expiration, revocation, validation, CSRF protection, XSS defenses and the surrounding application architecture.
Is JWT better for SPAs?
Not necessarily. SPAs can use JWT access tokens, but they can also authenticate with secure HttpOnly cookies and server-side sessions. The appropriate choice depends on the API and security architecture.
Does JWT replace sessions?
No. JWT is a token format and authentication mechanism that can be used in architectures where self-contained signed tokens are useful. Server-side sessions remain appropriate for many web applications.
Can a JWT be stored in an HttpOnly cookie?
Yes. A JWT can be placed in a Secure, HttpOnly cookie. JWT does not require localStorage or JavaScript-accessible storage.
Why is JWT logout difficult?
A signed JWT may remain valid until its expiration time. Immediate revocation therefore requires additional server-side state or a token lifecycle strategy such as short-lived access tokens and refresh-token rotation.
Are JWT payloads encrypted?
Ordinary signed JWTs are not encrypted. Their payload can generally be decoded by anyone who obtains the token. Signing protects integrity and authenticity, not confidentiality.
Can sessions scale to multiple servers?
Yes. Multiple application instances can use shared session storage or another architecture that makes session state available to all instances that need it.
Helpful Authentication Tools
A JWT Inspector can help inspect the structure and claims of a JSON Web Token, while a JWT Claims Viewer is useful when you specifically want to examine standard and custom claims.
A JWT Encoder can help create or inspect JWT representations during development and testing. For cookie-based authentication, a Cookie Parser and Cookie Generator can be useful for examining cookie attributes such as HttpOnly, Secure and SameSite.
Conclusion
Sessions and JWTs are both valid authentication approaches, but they make different architectural trade-offs. Sessions keep authentication state on the server and provide direct control over session invalidation. JWTs can carry verifiable claims and allow services to validate access tokens without consulting a central session store on every request.
For browser applications, secure HttpOnly cookies can be used with either session identifiers or JWTs. The choice of JWT does not require localStorage, and the choice of sessions does not prevent an application from scaling across multiple servers.
The most important factors are credential storage, HTTPS, expiration, revocation, CSRF protection, XSS defenses, authorization and the number and type of services that need to verify identity. Choose the model that fits those requirements rather than choosing JWT or sessions simply because one is more popular.