Skip to content

Authentication

The lab's /protected endpoint turns strangers away — chapter 2 met its 401 Unauthorized, complete with a WWW-Authenticate header naming the scheme it expects. This chapter presents credentials two ways, then spends its real length on the part most tutorials skip: where the credential ends up after you've typed it.

The lab's credentials are specimens: username paul, password specimen-pass, or a bearer token specimen-token. Yours will not be, which is exactly why the second half of this chapter exists.

Basic auth: -u

$ curl -s -u paul:specimen-pass http://127.0.0.1:8901/protected
You are in. The specimen word is 'plum'.
$ curl -s -u paul:wrong-password http://127.0.0.1:8901/protected
Authentication required.

-u user:password performs HTTP basic authentication: curl encodes the pair and sends it as an Authorization header on the request. What that header actually contains is worth seeing once, via /echo:

    "Authorization": "Basic cGF1bDpzcGVjaW1lbi1wYXNz",
$ echo cGF1bDpzcGVjaW1lbi1wYXNz | base64 -d
paul:specimen-pass

That is Base64: an encoding, reversible by anyone who can read it — as you just did, with no key and no effort. Basic auth is not encryption and pretends not to be; it is safe only because HTTPS (chapter 8) encrypts the whole conversation, header included. Over plain HTTP, a basic credential is a postcard. Every API key and token in this chapter's family rides in a header the same way and deserves the same respect: the header is visible to anything that can see the traffic or the request itself.

Bearer tokens: just a header

Many APIs skip usernames and issue a single token, presented as Authorization: Bearer <token>:

$ curl -s -H 'Authorization: Bearer specimen-token' http://127.0.0.1:8901/protected
You are in. The specimen word is 'plum'.
$ curl -s -o /dev/null -w '%{http_code}\n' -H 'Authorization: Bearer wrong-token' http://127.0.0.1:8901/protected
401

No new machinery: -H from chapter 4, with the server's expected incantation in it. Whoever holds the token is believed — there is no password behind it — so a token is a credential in full, not a username in part.

Where credentials leak

Three places collect what you type, and the captures below — all against the lab's five-second /slow endpoint, which keeps curl alive long enough to watch — show each.

1. Your shell history. Every command you type is recorded (in ~/.bash_history and its equivalents) before curl runs. History files outlive sessions, get backed up, and get read by anything that reads your home directory. A password on a command line is a password in a file. This leak has no capture to show because there is nothing to run: it's the typing itself.

2. The process list — with a surprise. While a command runs, other users on the machine can read its arguments with ps. The classic advice is that -u therefore exposes your password mid-flight. On the build machine, the truth is better and narrower:

$ ps -eo args | grep "[c]url"
curl -s -u                    http://127.0.0.1:8901/slow -o /dev/null
curl -s -H Authorization: Bearer specimen-token http://127.0.0.1:8901/slow -o /dev/null
curl -s -K lab-curlrc http://127.0.0.1:8901/slow -o /dev/null

(Only the curl lines are shown; the full listing also matched the sandbox's own shell processes, whose paths contain "curl".) Line one: modern curl rewrites its own argument list to blank the -u password — those spaces are deliberate, curl covering its tracks after reading the value. Do not build on this: it's a courtesy of recent curl on systems that allow it, not a guarantee, and it does nothing about history. Line two is the real exposure: the token set from an environment variable stayed fully visible, because it's just a header, and curl scrubs only what it knows is a password. Environment variables keep secrets out of your history; they do not keep them out of the process list while the command runs, and other tools (/proc/<pid>/environ, on Linux, to the owner and root) can read the variable itself.

3. URLs and logs. Credentials embedded in a URL — https://user:password@host/ — are kept by everything that keeps URLs: browser and proxy logs, server logs, the trace files of chapter 3. curl accepts the form; prefer -u or a header every time, and treat query strings (chapter 4's -G) as publishable: servers log them in full.

The safer patterns

A config file, kept private. -K reads options from a file, one per line:

$ cat lab-curlrc
user = "paul:specimen-pass"
$ ls -l lab-curlrc
-rw------- 1 root nogroup 28 Oct 20 00:48 lab-curlrc
$ curl -s -K lab-curlrc http://127.0.0.1:8901/protected
You are in. The specimen word is 'plum'.

The process list (line three above) shows only -K lab-curlrc: no secret in the arguments, none in history beyond the file's name, and chmod 600 — that -rw------- — means only your account can read the file. -K files can carry any options (header, cacert, and the rest), which makes them the natural home for per-service curl setups, credentials included. Protect the file like the credential it is: in a private directory, never committed to a repository.

Let curl ask. -u paul with no password makes curl prompt for it interactively; nothing is typed into history or the process list. Interactive only — a script has no keyboard to answer with — but for by-hand work it's the cleanest form.

The older standard. ~/.netrc (read with --netrc) stores per-machine logins in a long-established format that other tools (ftp clients, some APIs) also honour. It shares the config file's rule: keep it chmod 600, in your home directory, out of repositories.

Check: -u and the bearer header both open /protected, and both wrong values get the 401; the base64 in your own echo decodes back to the specimen pair in one command; and a ps taken while a slow -K request runs shows the file's name and nothing else. If you can see your real password in any of those places, the pattern, not the password, is what to change.

Next: fetching files properly — names, resumes, and redirects.