block / block/buzz

POST /events NIP-98 requirements are undocumented, and the in-repo e2e tests use a dev-only auth path that fails against production

Open Beginner friendly
#6,499 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

## Summary

`POST /events` on the relay requires NIP-98 auth, but the requirements aren't documented anywhere I could find, and the in-repo e2e tests use an auth path that only works in dev — so copying the tests against a production relay fails with a 401 and no indication why.

Working this out took a while, and none of it is discoverable from the docs. Writing it down here in case it's useful, and I'm happy to send a docs PR if you'd like it (opening the issue first, per CONTRIBUTING).

## The misleading part

The e2e tests authenticate with an `X-Pubkey` header. That header is a dev-mode fallback gated on `require_auth_token` (`crates/buzz-relay/src/api/bridge.rs:117`). Against a production relay it returns:

```
401 {"error":"missing Nostr auth"}
```

So the natural move — copy what the tests do — produces an error that says nothing about the header being dev-only, and there's no doc to contradict the tests.

## What actually works

`Authorization: Nostr `, where the event must satisfy (per `crates/buzz-auth/src/nip98.rs`):

- `kind` = 27235
- `created_at` within ±60s of the relay's clock
- a **single-letter `u` tag** whose value matches the normalized request URL — trailing slash stripped. **Not** a multi-letter `url` tag.
- a `method` tag matching the HTTP method
- a `payload` tag = SHA-256 hex of the request body

The `u`-vs-`url` tag detail is the one that cost us the most time. NIP-98 in the wild is inconsistent about it, the failure is an opaque 401, and there's nothing to check your work against.

## Suggested fix

A short section in the docs covering: which endpoints require NIP-98, the five requirements above, one worked example of a valid auth event, and an explicit note that `X-Pubkey` is dev-only and will not work against a normal deployment. Ideally also a comment in the e2e tests saying the same, since those are what people copy.

Happy to write it — say the word and I'll open a PR with DCO sign-off.

## Possibly related

- #6477 — docs gap on `POST /query` (bare filter objects vs. the required array wrapper). Same class of problem on a neighbouring endpoint; might be worth fixing together.
- #6441 — NIP-98 verification validating against a normalization of `RELAY_URL` that drops the port, breaking self-hosted relays on non-443 ports. Same code path as the `u` tag matching above.
- #6123 — asks for service-to-service auth as an alternative to NIP-98, and describes the same burden from the other direction.

## Environment

Self-hosted `buzz-relay` (`ghcr.io/block/buzz:main`, image built 2026-08-09), reached over HTTPS on 443 behind a reverse proxy.

Contributor guide

Open the contributing guide

Research direction

Start with crates/buzz-auth/src/nip98.rs and crates/buzz-relay/src/api/bridge.rs:117 to confirm the authentication requirements and the dev-only X-Pubkey path. Find the existing API documentation and in-repo e2e tests, then add the requested NIP-98 section, worked example, and test comment. Done means production users can identify the required endpoints and construct a valid request without relying on X-Pubkey.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, authentication, documentation
Issue type
Documentation
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.