Skip to content

Cookies

HTTP, at heart, has no memory: each request arrives as if from a stranger. Cookies are the workaround. A server hands your client a name-and-value pair in a Set-Cookie header — "remember this" — and the client presents it on later requests, which is how logins survive from one page to the next. curl, being a tool that does exactly what it's told, does none of this by default: no jar, no memory. You switch each half on explicitly.

Receiving: -c saves the jar

$ curl -s http://127.0.0.1:8901/whoami
No cookie sent.
$ curl -s -c jar.txt http://127.0.0.1:8901/set-cookie
Cookie set. Now visit /whoami.
$ cat jar.txt
# Netscape HTTP Cookie File
# https://curl.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
127.0.0.1   FALSE   /   FALSE   0   session specimen-abc123

Before the cookie: /whoami, the lab's cookie echo, reports none sent. -c (--cookie-jar) tells curl to write any cookies the response sets into jar.txt — here, the server set session=specimen-abc123, and the jar's last line is that cookie in the ancient Netscape format: domain, a flag for subdomains, path, "secure connections only?", expiry (epoch seconds; 0 means a session cookie, gone when the browser would close), name, value, tab-separated. The file is plain text and yours to inspect — do look; cookies that surprise you are common.

Sending: -b presents cookies

Writing the jar only saved the cookie. The first /whoami above was before, and a second request without -b would still be a stranger. -b (--cookie) is the sending half:

$ curl -s -b jar.txt http://127.0.0.1:8901/whoami
Cookie received: session=specimen-abc123

Given a filename, -b reads the jar and sends every cookie whose domain and path match the request. Given a string containing =, it sends that literally, no file involved:

$ curl -s -b 'session=specimen-abc123' http://127.0.0.1:8901/whoami
Cookie received: session=specimen-abc123

Same result, nothing stored. (That = is how curl tells a value from a filename: no =, it assumes a file.) The inline form is handy for one request with a token a program handed you; the jar is the form that scales, because real sites set several cookies, rotate them, and expire them.

The session pattern

Most cookie work is one ritual: log in once, then make several requests as the logged-in client. Both flags on every call, same jar:

curl -s -b jar.txt -c jar.txt -d 'user=...&pass=...' https://site/login
curl -s -b jar.txt -c jar.txt https://site/account
curl -s -b jar.txt -c jar.txt https://site/settings

(Shown as a pattern, not a capture — the lab's one cookie can't act out a whole login dance, and the shape is what matters.) Read: -b presents what we hold; -c writes back whatever the server set or refreshed. The jar evolves exactly as a browser's does, minus the browser.

Respect what the jar is: a file full of bearer credentials. A session cookie is chapter 5's token wearing a different hat — whoever reads jar.txt can be you, at that site, until it expires. Keep jars out of repositories, don't email them, give script jars their own directory with private permissions, and let --cookie-jar paths in old scripts be a small red flag when you audit them. The companion risk runs the other way too: a jar you accept from somewhere and -b at a site carries cookies you never inspected.

Check: after -c, jar.txt exists and names the session cookie; -b jar.txt at /whoami is greeted by name; without either flag the lab still sees a stranger. If a real site's flow breaks for you, chapter 3's -v shows the Cookie: header (or its absence) on the way out and every Set-Cookie on the way back — cookies, debugged, are just headers with a memory.

Next: TLS — the padlock, and the one option that removes it.