A browser or curl logs in once with a form, and a cookie carries the session from then on — see every HTTP message and every command to the session store, keep the sessions in the server's memory or in Redis, let time pass, restart the server, and set the cookie's attributes to see what each one does.
A session moves the password off the wire. The browser sends it once, in a login form; the server then
creates a record, "this random id belongs to alice", and hands the id back in a cookie. The browser
returns the cookie on every request, and the server looks the id up to learn who is asking. The simulator
shows each message, the record behind the cookie, and the store the records can move to. It follows
Basic HTTP Authentication
, where the password went with every
request.
The simulator's layout
- The client on the left is a browser window or a curl command line. The browser's page is live: its
links and its login form send the next request. curl reads and writes
jar.txt with -b and -c, and
posts the form with -d, as in the course lab. - The server on the right holds the users, where the sessions live, how long it keeps them, and the
attributes of the cookie it sets. Its Send the response button lights up when it holds a request.
- The session store appears under the server when sessions move to Redis. The command on the link
between them, and the store's Reply, are steps of their own.
- The wire in the middle shows the last HTTP message whole; clicking a line says what it does.
- The clock in the controls row moves only with Let 10 minutes pass, so expiry happens when you
choose.
- Step and Prev move one message at a time: a request, a command to the store, its reply, a response,
or the browser following a redirect.
Logging in once
The first visit to a protected page goes through three pages before it reaches it:
GET /account without a cookie gets 302 Found with Location: /login. The browser follows the
Location by itself.GET /login returns an HTML form. This time the body asks for the password, not a header: no
WWW-Authenticate is involved.POST /login carries user=alice&password=secret123 in its body, in plain text. It is the only
request in the session that carries the password.303 See Other answers a correct password. It carries Set-Cookie: sid=… and sends the browser on
to /account with a GET, so reloading the page never posts the form again. A wrong password gets the
form back with an error, as a 200: a 401 would need a WWW-Authenticate challenge.
From then on every request carries Cookie: sid=…, and the server finds the record it points at.
The cookie is a random id
The id means nothing on its own: it is a claim ticket, and all its meaning is in the server's record.
That is what makes the rest possible:
- Logout deletes the record, and the server clears the cookie with an empty value and
Max-Age=0.
Even a copy of the cookie kept elsewhere is worthless from then on. - Revoking one device deletes one record, with Revoke in the server's table.
- Changing a password does not end a session: the cookie never carried the password.
Where the sessions live
- In the server's memory, a lookup costs nothing, but a restart loses every record. The clients keep
their cookies, which now point at nothing, so everyone is logged out at once. A second instance of the
server could not see the records either.
- In Redis, every instance can read them and they survive a restart. The price is visible on the
diagram: every request that needs to know who is asking waits for a
GET sess:… and its reply.
The login writes the record with SET sess:… alice EX 600, and EX makes Redis delete it by itself.
The examples A restart logs everyone out and Sessions in Redis survive a restart play the two through.
Two lifetimes: the cookie's and the record's
The client and the server each forget on their own schedule:
Max-Age on the cookie asks the client to delete it after so many seconds. Without Max-Age or
Expires it is a session cookie, deleted when the browser closes; Close the browser shows it.- The server's lifetime is on the record, and it is the one that counts. A client can keep a cookie
as long as it likes, but a record that has expired logs nobody in.
The example The server's lifetime is shorter than the cookie's sets Max-Age to an hour and keeps the
record for ten minutes: after ten minutes the browser still sends the cookie, and gets the login page.
The cookie's attributes
A session cookie is the login itself: whoever holds it is the user until it expires. Every attribute after
the first semicolon of Set-Cookie is an instruction to the client for keeping it safe, and is never sent
back:
HttpOnly hides the cookie from scripts on the page. Run document.cookie shows what a script
sees: the cookie with HttpOnly off, an empty string with it on. A script injected through a bug could
otherwise send the cookie to another site.Secure allows the cookie only over https://. Browsers and curl refuse a Secure cookie set
over plain http://, since it could have been read or forged on the way; on this plain-http site the
login succeeds on the server and the cookie never arrives, so the next page asks for the login again.SameSite=Lax keeps the cookie off a POST that another site starts, which is the defence against
cross-site request forgery. The simulator has no second site, so it only sets it.Path=/ sends the cookie with every URL on the site.
Reading curl's jar.txt
With -c jar.txt curl writes the cookies it receives in the Netscape cookie file format, one line per
cookie: the host, whether subdomains get it, the path, the Secure flag, the expiry as a Unix time, the
name and the value. An HttpOnly cookie's line starts with #HttpOnly_. Without -b curl sends none of
it, and without -c it keeps nothing; the example curl with a cookie jar is the course lab.
Simplifications in the simulator
- One server instance: the benefit of a shared store for a second instance is described, not shown.
- The server shows passwords in plain text so you can edit them; a real one stores a hash.
- Redis is shown as plain commands and replies, not its wire protocol.
- The connection, TLS and TCP are not shown, and the site is plain
http:// throughout.
The course
Authentication and Secrets
builds the same login with
a small Python server and curl in its chapter Cookies and sessions.