auth: take the default header in dev too
The Caddy site writes the login to Remote-User, the name the app already takes;
a dev override pointing somewhere else is only a 401 it makes.
The task sets nothing now, so one header answers to them all —
the loop and the tailnet read the same name, and the docs make the call.
Assisted-by: Claude Opus 5 via Claude Code
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
diff --git a/AGENTS.md b/AGENTS.md
index e5bba4d..f0ca4b7 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -94,11 +94,10 @@ not a fixture; edit a `.vcf` to change what the replay serves.
an element's block, `it` is the builder, not an enclosing block's value,
so name the outer block's parameter.
- Every request needs the identity header or it gets a 401, so a bare
- `curl` against `rake dev` is refused until you pass
- `Tailscale-User-Name`, which is what that task sets
- `PRO_TACTS_IDENTITY_HEADER` to (`Remote-User` is the default everywhere
- else). The security of that rests on the app being reachable only
- through a proxy that writes the header itself — never bind it to
+ `curl` against `rake dev` is refused until you pass `Remote-User`
+ (`PRO_TACTS_IDENTITY_HEADER` renames it, and the refusal says which
+ name it read). The security of that rests on the app being reachable
+ only through a proxy that writes the header itself — never bind it to
anything but localhost.
- DAV exchanges that went wrong (a status of 400 or more but 401, a
crash, or a report to Sentry) are written whole to `log/exchange.log`,
diff --git a/Rakefile b/Rakefile
index 0747cd3..aa19bed 100644
--- a/Rakefile
+++ b/Rakefile
@@ -30,13 +30,6 @@ task :dev do
ENV["PRO_TACTS_EXCHANGE_LOG"] ||= "log/dev.log"
File.truncate("log/dev.log", 0) if File.exist?("log/dev.log")
- # No proxy in front of a dev server, so the identity header is
- # whatever a client passes by hand. The name the tailnet deployment's
- # proxy writes the login to, rather than the Remote-User default, so a
- # dev session reads the header that deployment reads
- # (ProTacts::Config#identity_header).
- ENV["PRO_TACTS_IDENTITY_HEADER"] ||= "Tailscale-User-Name"
-
Dir.mktmpdir("pro-tacts-dev") do |dir|
data_dir = Pathname.new(dir)
ENV["PRO_TACTS_DATA_DIR"] = data_dir.to_s
diff --git a/docs/plans/2026-09-15-identity-from-one-header.md b/docs/plans/2026-09-15-identity-from-one-header.md
index edb5e2a..572142d 100644
--- a/docs/plans/2026-09-15-identity-from-one-header.md
+++ b/docs/plans/2026-09-15-identity-from-one-header.md
@@ -51,13 +51,18 @@ next piece of work, not part of this one.
`PRO_TACTS_IDENTITY_HEADER` sets it. The default is `Remote-User`, what
a reverse proxy conventionally writes the authenticated user to; the
`docs` site in the same Caddyfile already sends it to another backend.
-`rake dev` sets `Tailscale-User-Name`, because a dev session has no
-proxy in front of it and is testing what the tailnet deployment does.
-That name is a misnomer inherited from the Caddy site: its `header_up`
-writes `{http.auth.user.tailscale_user}` there, which is the login, not
-the display name the header is named for. The app reads a header, not a
-meaning, so the misnomer costs nothing but a reader's double take —
-correcting it is a Caddyfile change and a resync, not an app change.
+`rake dev` sets nothing and takes the default, because the deployment
+takes it too: the Caddy site writes `{http.auth.user.tailscale_login}`
+into `Remote-User`, so a dev session and the tailnet read the same
+header name.
+
+That placeholder is the username portion of the login — `alpha`, not
+`alpha@kejadlen.dev` — which is what a `sync:` group is named after. It
+reads the way the display name did without being a display name, and it
+is unique within one domain rather than across the tailnet: two users at
+different domains with the same username would share a book. The
+Caddyfile carries a TODO to move to the whole login once the group name
+is a setting of its own.
The header is trustworthy for the same reason the pair was. `tailscale
serve` strips `Tailscale-User-Login` from an incoming request before it