From 44aa0591b0eed7851e961ea17bd1c9601570ac24 Mon Sep 17 00:00:00 2001 From: bndw Date: Sat, 14 Feb 2026 08:52:59 -0800 Subject: docs: clarify NIP-98 relationship to NIP-42 and write access control Explain that the gRPC NIP-98 implementation is effectively NIP-42 for reads (same pattern: authenticate once, stream many events) and adds standardized relay access control for writes (beyond event.sig). Add comparison table showing functional equivalence for streaming reads and the additional benefits for write access control. --- internal/auth/README.md | 64 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 4 deletions(-) (limited to 'internal') diff --git a/internal/auth/README.md b/internal/auth/README.md index adfe260..c41b6cb 100644 --- a/internal/auth/README.md +++ b/internal/auth/README.md @@ -6,6 +6,58 @@ This package implements [NIP-98](https://github.com/nostr-protocol/nips/blob/mas NIP-98 provides HTTP authentication using Nostr event signatures instead of bearer tokens or OAuth2. It uses cryptographic signatures to prove the request came from a specific public key, without requiring passwords or centralized identity providers. +## Relationship to NIP-42 + +This implementation serves as **NIP-42 for gRPC**, with some important distinctions: + +### For Reads (Queries/Subscriptions) + +**NIP-42 (WebSocket)**: +- Authenticates the **connection** once via challenge-response +- All subsequent REQ messages use the authenticated connection +- Enables access control for private/restricted events + +**NIP-98 (gRPC - this implementation)**: +- Authenticates **streaming RPCs** once at stream establishment +- All events streamed over that authenticated connection +- Same access control pattern as NIP-42 + +**Result**: Functionally identical! Both authenticate once and stream many events. + +``` +WebSocket + NIP-42: AUTH challenge → Subscribe → 1000 events (no re-auth) +gRPC + NIP-98: Subscribe with auth → 1000 events (no re-auth) +``` + +### For Writes (Publishing Events) + +**NIP-42 (WebSocket)**: +- Not applicable - events are self-authenticating via `event.sig` +- No connection-level auth for EVENT messages +- Relay only verifies the event signature + +**NIP-98 (gRPC - this implementation)**: +- Adds **relay access control** on top of event signatures +- Proves who is **submitting** (NIP-98) vs who **created** (event.sig) the event +- Enables use cases like: + - Rate limiting per user + - Allow-lists for relay access + - Preventing spam/abuse (submitting scraped events) + - Verifying submitter matches event author + +**Result**: Standardizes a relay access control pattern beyond base Nostr's self-authenticating events. + +### Summary + +| Use Case | WebSocket (NIP-42) | gRPC (NIP-98) | +|----------|-------------------|---------------| +| **Read auth** | Challenge-response, once per connection | Per-RPC auth, once per stream | +| **Read pattern** | ✅ Same: authenticate once, stream many | ✅ Same: authenticate once, stream many | +| **Write auth** | ❌ N/A (events self-auth) | ✅ Optional relay access control | +| **Overhead** | None after initial handshake | None for streams; minimal for unary calls | + +This implementation gives you NIP-42's read authentication pattern plus standardized relay access control for writes. + ## How It Works ### Authentication Flow @@ -167,10 +219,14 @@ authOpts := &auth.InterceptorOptions{ 1. **No passwords**: Uses public key cryptography 2. **Decentralized**: No central identity provider -3. **Per-request auth**: Each request is independently authenticated -4. **Nostr compatible**: Works with existing Nostr identities and tools -5. **Standard pattern**: Uses industry-standard gRPC credentials interface -6. **Key rotation**: Easy to rotate keys without server-side updates +3. **Nostr ecosystem compatible**: + - Same authentication as NIP-42 for WebSocket relays + - Works with existing Nostr identities (npub/nsec) + - Compatible with Nostr clients and tools +4. **Efficient for streaming**: Authenticate once per stream (like NIP-42 for WebSocket) +5. **Standard gRPC pattern**: Drop-in replacement for OAuth2/JWT using `credentials.PerRPCCredentials` +6. **Flexible access control**: Enables relay-level permissions beyond event signatures +7. **Key rotation**: Easy to rotate keys without server-side session management ## Compatibility -- cgit v1.2.3