2024-11-04 . 6 min(s)

Session vs JWT: The Differences You May Not Know

Session vs JWT The Differences You May Not Know

Your application just received a login request, and the credentials passed successfully to prove the identity of a user in your system. Wonderful, you have a high degree of confidence in who this user is and what they should be able to access!

But wait, what happens on the next API call where they don’t include their login credentials?

HTTP is stateless, meaning that each request is independent and doesn’t contain any context about previous requests, but asking your user to re-authenticate on every request isn’t exactly a friendly UX.

Session cookies and JSON Web Tokens (JWTs) are the two most popular ways to maintain this authentication state between calls. There are pros and cons to both, and choosing between them requires understanding these tradeoffs and how they relate to the specific needs of your application.

Session-based authentication

In session-based authentication (also known as cookie-based authentication), the server is responsible for creating and maintaining a record of the user’s authentication and providing a way for the client to reference that record in each subsequent request.

This flow starts by the user authenticating and providing some credentials to the server for verification. If the credentials are accepted, the server will create a persistent record that represents this authenticated browsing session. This record will have some sort of primary identifier (typically a random string that is at least 128 bits long) in addition to an identifier for the user, the time the session started, the expiry of the session, and perhaps context information like the IP address and User Agent. This information will be stored in the database, and the session identifier will be sent back to the client to be stored as a cookie in the user’s web browser.

Each subsequent request from the browser will include the session cookie in the HTTP headers, which the server can then use to look up the session record, confirm that it is valid and then make authorization decisions about what information to return based on the confirmed identity of the user.

The benefits of session cookies

The appeal of this approach is in its simplicity and reliability.

The database record of the session serves as a clear, centralized source of truth for the state of the session, which allows for a high degree of confidence that the session information is up to date and can be used to make authorization decisions. Revoking a user’s access to the system is quick and reliable with sessions, as you can simply delete the session record from the database or mark it as invalid. For any subsequent requests after revocation, the server will fail to find a valid session that matches the identifier in the headers and will return a 401 unauthenticated error to prompt the user to re-authenticate.

By offloading the state management to the server, we are able to reduce the data transfer overhead down to a single opaque string, which is lightweight and does not leak any information about the associated user or the context of the session.

The downside of session cookies

While session-based authentication is very reliable, at scale it can begin to introduce latency and performance issues.

Since you need the session record to be highly reliable and accessible from any host, this means inserting a write request to the database for every authentication and more importantly a read request to the database for every subsequent request that contains the session header. Since session expiry is often extended with constant use, this can also mean an additional update on every request. Over time all these database interactions can add up, and introduce notable latency across your application.

For applications that have highly dynamic clients, this latency overhead might not be worth the benefits that session-based authentication provides.

JWT authentication

JSON web tokens (JWTs) achieve similar goals of identifying and authorizing the logged-in user during subsequent requests, but solve the problem of how to manage that information in a very different way.

This flow also starts with the user providing some form of credentials that the server uses to authenticate that particular request. However, while the session-based flow relies on storing all the necessary state in a database and looking it up on every request, in the JSON web token flow all that context is self-contained in the string being sent back to the client.

At a high level, JWTs are JSON objects that follow a particular protocol for communicating “claims” or authorization context, and are then either signed or encrypted by the issuing server in order to provide assurance that these claims can be trusted. Clients can verify that the JWT has not been tampered with since the signature of the JWT contains the original header and payload data.

JWTs consist of three parts – the header, the payload and the signature.

The payload contains the core claims, such as the identity of the user the JWT was issued for, the permissions that the token might grant, and the expiry of the JWT, which indicates the time after which the JWT should no longer be accepted. The header contains information about the algorithm used to sign or encrypt the token. The header and payload are then base64url encoded, which makes the value easier to send and store. Since this is just as easy to decode, it means that the information stored in them can be viewed by anyone.

The signature is created by combining the header and the payload and then hashing that combination with a secret key, providing a way to detect if a malicious actor has tampered with the claims after the issuer signed the JWT. In distributed systems, this is typically an asymmetric signature, where the issuing server will use a private key to hash the contents and then the audience can use the corresponding public key to verify that the current payload is the same one that was signed by the issuer.

Once the JWT is constructed and signed, it is sent back to the client to store. This JWT can be used safely for authorization by verifying that the expiry has not passed and the signature is valid for the payload provided, all of which can be done on the client without checking with the server who initially issued the JWT.