NIP-98 auth validates the signed URL against a single base address — blocks serving a relay on more than one hostname
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
### Environment
- Self-hosted relay via `deploy/compose`, `compose.caddy.yml` with Caddy terminating TLS in front of the relay
- Relay image `ghcr.io/block/buzz:sha-318fbf8`
### Summary
NIP-98 HTTP Auth validation appears to compare the signed request URL against a single configured base address. That makes it impossible to serve one relay over more than one address, even when routing is otherwise working.
### Reproduction
1. Bring up a relay whose configured address is an internal one (e.g. a private network address).
2. Put it behind a reverse proxy on a public hostname, rewriting `Host` so community routing resolves (see the separate issue about community host binding).
3. Unauthenticated endpoints now work over the public hostname — `/` and `/_readiness` both return 200.
4. Any authenticated call fails, **including from a valid roster member**:
```
HTTP 401
NIP-98: NIP-98 HTTP Auth verification failed: URL mismatch:
event has `https://public.example.com/query`,
expected `http://10.0.0.1:3001/query`
```
The same member, same key, works normally against the internal address. A fresh non-member key correctly gets `403 relay_membership_required` on the internal path, so membership enforcement itself is fine.
### Why a proxy-level fix does not work
NIP-98 signs the full request URL client-side. Rewriting `Host` at the proxy cannot change a signature that was already computed, so the mismatch is structural rather than a misconfiguration — the proxy can make routing agree, but not auth.
### Question / proposal
`.env.example` suggests `BUZZ_DOMAIN`, `RELAY_URL` and `BUZZ_MEDIA_BASE_URL` are all meant to derive from one public hostname, and I could not find a separate "bind host" vs "public base URL" concept.
Would you accept a PR adding an **allow-list of acceptable base URLs** for NIP-98 verification (env-configurable, defaulting to current behaviour)? That would let a relay serve an internal and a public address simultaneously without weakening validation — the signature still has to match one of the explicitly configured origins.
If there is already an intended way to do this, I would rather use that. Happy to test a patch either way.
Contributor guide
Assessment
This issue has not been assessed yet.