How Web Authentication Works: Cookies, Sessions, Tokens, and OAuth
Every time you stay logged in to a website, something is quietly working around a core fact of the web: HTTP has no memory. Each request arrives at the server as if it were the first one it had ever seen. The server does not know that the request that just asked for your account page is the same person who typed a password a moment ago. Authentication is the set of tricks we use to bridge that gap, and understanding the pieces makes a surprising amount of web security click into place.
Authentication is not authorization
These two words get used interchangeably, and they are not the same thing. Authentication answers the question "who are you?"[1] It is the login step, where you prove your identity with a password, a passkey, or a code from your phone. Authorization answers a different question, "what are you allowed to do?"[2] It is the check that happens after you are known, deciding whether you can see the admin dashboard or only your own profile.
A system can get authentication right and authorization wrong. Letting a logged-in user view another user's invoices by changing a number in the URL is an authorization bug, not an authentication one. Keeping the two ideas separate in your head is the first step to reasoning about either.
The real problem: HTTP forgets
Because HTTP is stateless[3], the server needs the client to carry some proof of identity on every single request. The entire design space of web authentication comes down to one question: what is that proof, and where do we keep it?
There are two broad answers. The server can hand the client a meaningless ticket and remember the details itself. Or the server can hand the client a signed document that contains the details, and trust the signature later. The first is a session. The second is a token. Almost everything else is a variation on those two.
Cookies and server-side sessions
The oldest and still most common approach is the server-side session. When you log in, the server creates a session record, stores it somewhere it controls (memory, a database, or a cache like Redis), and generates a random unguessable session ID. It sends that ID back to the browser as a cookie.
Set-Cookie: session=9f2a1c8e...; HttpOnly; Secure; SameSite=Lax
A cookie is just a small piece of data the browser stores[4] and automatically attaches to future requests for that site. On every later request, the browser sends the session cookie, the server looks up the matching record, and it knows who you are. The cookie itself contains nothing sensitive. It is a claim check, and the real information stays on the server.
The flags on that cookie do the security work. HttpOnly prevents JavaScript from reading it, which blunts a large class of theft attacks. Secure means it only travels over HTTPS. SameSite controls whether the cookie is sent on requests coming from other sites, which is the main defense against cross-site request forgery.
The strength of sessions is control. If you need to log someone out everywhere, you delete the record and the ticket is instantly worthless. The cost is that the server has to store and look up state for every active user, which takes a little more infrastructure as you grow.
Stateless tokens and JWTs
The other approach flips the arrangement. Instead of keeping the details on the server, you put them in the token and sign it. The common format is the JSON Web Token, or JWT[5]. A JWT holds a small JSON payload, your user ID, maybe your role, an expiry time, and a cryptographic signature the server can verify without looking anything up.
{ "sub": "user_123", "role": "member", "exp": 1735689600 }
Because the signature proves the token has not been tampered with, any server that knows the signing key can trust it on sight. There is no database lookup, which is appealing for systems spread across many services or many machines, since each one can verify a request on its own.
The trade-off is the one people underestimate. A signed token is valid until it expires, and you cannot easily revoke it in the meantime, because there is no central record to delete. If a token is stolen, it works until it times out. The usual fix is to keep access tokens short-lived, a few minutes, and pair them with a longer-lived refresh token that can be revoked. That restores some control, at the cost of more moving parts. A JWT is also readable by anyone who holds it, since the payload is only encoded, not encrypted, so it should never carry secrets.
A common mistake is reaching for JWTs because they sound modern when a plain session cookie would have been simpler and safer. Stateless tokens earn their keep when you genuinely have many independent services that need to verify identity without a shared session store.
OAuth and OpenID Connect
OAuth solves a question the previous methods do not: how do you let one application act on your behalf at another, without handing over your password? When an app asks to "continue with Google," you are using OAuth. You authenticate with Google directly, Google asks if you consent to share certain information with the app, and the app receives a token that grants limited access. The app never sees your Google password.
OAuth itself is about authorization, granting scoped access to resources[6]. OpenID Connect is a thin layer on top of OAuth that adds authentication[7], a standard way to answer "who is this person?" It returns an ID token, a JWT describing the user[8], which is what "sign in with" buttons actually rely on. The practical benefit is that you offload the hardest parts of security, password storage and account recovery, to a provider that specializes in it.
Where each one fits
For a single application with its own users, server-side sessions with a secure cookie are the boring, correct default. They are simple to reason about, easy to revoke, and hard to get dangerously wrong.
For a system split into many services that each need to verify identity independently, stateless tokens with short lifetimes and refresh tokens start to pay off. For letting users sign in with an existing account or granting third-party access, OAuth and OpenID Connect are the standard, and using a reputable provider is almost always safer than building it yourself.
The thread running through all of it is the same quiet fact we started with. The web forgets you on every request, and authentication is the ongoing work of helping it remember just enough, for just long enough, without leaving the door open.