๐ Stateless vs. Stateful Authentication and Why JWT Matters

Introduction
I'm building a scheduling web app. The backend exposes endpoints to handle users, appointments, payment flows, and more. Some resources are public, but others are restricted to signed-in and authorized users. There are several ways to implement this requirement, each with pros and cons. In this article, I share why I decided to use JWT.
Stateless vs. Stateful Authentication
Not long ago, many systems used stateful authentication:
The user logs in
The server creates a session and stores it in memory or a database
The server sends a
sessionIdto the client (usually inside a cookie)With each request, the client sends this
sessionIdand the server looks up the session
And yes, it works. But the main issue appears when the system starts to scale. As the number of clients grows, infrastructure requirements grow as well. Network latency increases, and we need to consume more and more resources just to check whether the user is authenticated. Since the server is responsible for validating the session, this workload becomes centralized and harder to scale.
The alternative is to remove this load from the server and make the client responsible for providing all the data required to prove it is authenticated.
No more session store.
No more lookups.
No more server coordination.
This is stateless authentication any authentication method where the server does not store client/session data.
JSON Web Token โ The JWT
One of the most widely used stateless authentication methods is JWT, a compact, encoded token made of three parts:
Header: contains information about how the token was signed (e.g., HS256, RS256)
Payload: where we store important information (
userId,email, roles, etc.)Signature: ensures the payload has not been altered
Once issued, a JWT works like a passport the client carries.
Every request should include a Bearer <token> header, and the server only needs to verify the tokenโs signature and check its expiration. If both are valid, the request is authorized without any database or memory lookup for session data.
Request
curl -X 'POST' \
'http://localhost:3001/auth/login' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{
"email": "paulo@example.com",
"password": "mypassword123"
}'
Response
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3ZTk1NmZiYi1lZDg1LTRhOWItOTcwNC0xNzk0YzlmZTViM2UiLCJ1c2VybmFtZSI6IlBhdWxvIE1lbmRlcyIsImlhdCI6MTc2NDM0NTY3NSwiZXhwIjoxNzY0MzQ1NzExfQ.29rHpuCWQh-I7dSz-5k6vs65dV1q0FzkoOi-pI3ZIQE"
}
A JWT decoded

Final Thoughts
JWT is only the starting point. From here, I'll extend the system with refresh tokens, access control, and roles. But the foundation is in place: a stateless and scalable authentication layer.
