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 the password once, in a login form.
- The server 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.
- It follows
Basic HTTP Authentication, where the password
went with every request.
Reading the drawing
- Step plays nine scenes, one message per step: a request, a command to the store, its reply, a
response, or the browser following a redirect.
- The buttons on each card take the story our own way; the scene picker or Restart brings it
back.
- 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 session store appears under the server when sessions move to Redis.
- The clock moves only with Let 10 minutes pass.
- Messages so far, on the right, lists the scene's messages; a click on one goes back to it.
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.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=…; - it 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: a random id
The id is a claim ticket: all its meaning is in the server's record.
- 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.
- A changed password leaves every session running: 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 shows 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.
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.- A cookie with no
Max-Age or Expires is a session cookie, deleted when the browser closes. - The server's lifetime is on the record, and it is the one that counts: a record that has expired
logs nobody in, however long the client keeps the cookie.
- The scene The server's lifetime is shorter than the cookie's keeps the cookie for an hour and 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, 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. - Without it, a script injected through a bug could 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, the cookie never arrives, and the next page
asks for the login again.
SameSite=Lax keeps the cookie off a POST that another site starts: the defence against
cross-site request forgery.Path=/ sends the cookie with every URL on the site.
curl's cookie jar: jar.txt
With -c jar.txt, curl writes the cookies it receives in the Netscape cookie file format, one line per
cookie.
- The fields: 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_. - curl sends the jar only with
-b, and keeps cookies only with -c.
The course
Authentication and Secrets builds the same login with
a small Python server and curl in its chapter Cookies and sessions.