A couple weeks ago I was working on a project and I asked Cursor (Sonnet 4.5) to add auth to the server and the client. I wanted a register page, a login page, some future proofing support for Google Oauth, and for it to make any and all necessary changes to the DB structure to accomplish this. I always use planning mode and it asked me a question: Do I want to use sessions or JWTs? What is the difference between sessions and JWTS? And I’ve been doing this for over 10 years, I know what these are. I’ve built both systems before and I know when to use each one, but it struck me how, if you are vibe coding something, or you are just starting out and are faced with this question you might not know which to choose. Because they’re both fine, somewhat interchangeable in the grand scheme of things, but there is some nuance. So I wanted to write about it, and maybe help some poor programmer in the future trying to decide which to choose.
Sessions
Think of a session like a coat check at a club.
When you hand over your jacket, the attendant places it on a specific hook and hands you a ticket with a number on it. That ticket contains no information about what the coat is. It doesn’t say “black leather jacket” or “size medium.” It’s just a reference number that corresponds to a location behind the counter.
That is exactly how a session works.
Because the internet is stateless by default, the server needs a way to remember you as you move from page to page. When you log in, the server creates a file or a database entry on its end, this is the “hook” the jacket is hung n, where it stores your user details. It then generates a random Session ID, or the “ticket”, and sends it to your browser as a cookie.
Since the browser automatically sends that cookie back to the server with every single request you make, the server can grab the ID, look it up in its memory, and realize that you are still you.
The important distinction here is that the server holds all the data. The client serves only as a carrier for the reference key. If a hacker managed to steal your session cookie, they would have your ticket, but they wouldn’t know anything about you until they used it to trick the server.
This approach makes sessions stateful. The server cares. The server remembers. If the server reboots and those sessions were stored in RAM, everyone gets logged out instantly because the server lost its memory. While this was the standard for decades, it poses a specific question for the modern developer: do you want your server to be responsible for remembering every single user who is currently online?
You might actually want that responsibility because it gives you a kill switch. Since the server checks the database for every single request, you retain the power to revoke access instantly. If you need to ban a user or kick out a suspicious device, you simply delete the record on your end and the ticket becomes useless. While tokens act like a pre-paid pass that works until it expires, sessions allow you to cut the cord the moment you decide it is time to stop.
JSON Web Tokens (JWTs)
If sessions are a coat check ticket, a JWT is a laminated VIP badge.
When you walk into a high-security event with a badge, the guards don’t stop to look up your name on a clipboard. They don’t need to call the front desk to see if you are allowed in. They simply look at the badge around your neck. If the badge says “Access Level: All Areas” and bears the official holographic seal of the event, they let you pass.
This is the philosophy behind the JSON Web Token.
When you log in, the server doesn’t create a database record to remember you. Instead, it takes your user ID and your permissions, packs them into a JSON object, and cryptographically signs it using a secret key. It hands this signed token, the badge, back to your browser.
Here is the kicker: once the server hands you that token, it forgets you ever existed.
Because the data lives inside the token itself, your browser carries the full weight of your identity. When you send a request, you attach this token (usually in a header labeled “Bearer,” which literally means “the bearer of this token”). The server receives it, checks the mathematical signature to ensure no one changed the data, and grants you access. Since the signature is valid, the server trusts the badge without ever checking a database.
This makes JWTs stateless.
You generally pick this option when you prioritize scale or flexibility over strict control. Because the server doesn’t need to consult a central memory bank for every request, you can distribute traffic across dozens of different servers with ease. If you are building a mobile app that talks to multiple different backends, the JWT acts as a universal passport that works everywhere your secret key is trusted.
Summary
The fundamental difference between Session-Based Authentication and Token-Based Authentication (JWT) boils down to where the user’s state is stored. Session-based auth is stateful because the server actively maintains a central record of every logged-in user, which provides immediate revocation control but complicates scalability across multiple servers that must share that state. In contrast, Token-Based Auth using JWTs is stateless; the server cryptographically signs the user’s identity data into a self-contained token, offloading the state to the client. This design provides superior scalability because the servers don’t share memory, but it sacrifices the ability to instantly revoke a token before it naturally expires.
Leave a Reply