summaryrefslogtreecommitdiffstats
path: root/internal
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-02-14 08:52:59 -0800
committerbndw <ben@bdw.to>2026-02-14 08:52:59 -0800
commit44aa0591b0eed7851e961ea17bd1c9601570ac24 (patch)
tree198cf6958c1f550c0a218296a0414456df68c8e5 /internal
parent756c325223ef744b476ade565cb1970c7717d053 (diff)
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.
Diffstat (limited to 'internal')
-rw-r--r--internal/auth/README.md64
1 files changed, 60 insertions, 4 deletions
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
6 6
7NIP-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. 7NIP-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.
8 8
9## Relationship to NIP-42
10
11This implementation serves as **NIP-42 for gRPC**, with some important distinctions:
12
13### For Reads (Queries/Subscriptions)
14
15**NIP-42 (WebSocket)**:
16- Authenticates the **connection** once via challenge-response
17- All subsequent REQ messages use the authenticated connection
18- Enables access control for private/restricted events
19
20**NIP-98 (gRPC - this implementation)**:
21- Authenticates **streaming RPCs** once at stream establishment
22- All events streamed over that authenticated connection
23- Same access control pattern as NIP-42
24
25**Result**: Functionally identical! Both authenticate once and stream many events.
26
27```
28WebSocket + NIP-42: AUTH challenge → Subscribe → 1000 events (no re-auth)
29gRPC + NIP-98: Subscribe with auth → 1000 events (no re-auth)
30```
31
32### For Writes (Publishing Events)
33
34**NIP-42 (WebSocket)**:
35- Not applicable - events are self-authenticating via `event.sig`
36- No connection-level auth for EVENT messages
37- Relay only verifies the event signature
38
39**NIP-98 (gRPC - this implementation)**:
40- Adds **relay access control** on top of event signatures
41- Proves who is **submitting** (NIP-98) vs who **created** (event.sig) the event
42- Enables use cases like:
43 - Rate limiting per user
44 - Allow-lists for relay access
45 - Preventing spam/abuse (submitting scraped events)
46 - Verifying submitter matches event author
47
48**Result**: Standardizes a relay access control pattern beyond base Nostr's self-authenticating events.
49
50### Summary
51
52| Use Case | WebSocket (NIP-42) | gRPC (NIP-98) |
53|----------|-------------------|---------------|
54| **Read auth** | Challenge-response, once per connection | Per-RPC auth, once per stream |
55| **Read pattern** | ✅ Same: authenticate once, stream many | ✅ Same: authenticate once, stream many |
56| **Write auth** | ❌ N/A (events self-auth) | ✅ Optional relay access control |
57| **Overhead** | None after initial handshake | None for streams; minimal for unary calls |
58
59This implementation gives you NIP-42's read authentication pattern plus standardized relay access control for writes.
60
9## How It Works 61## How It Works
10 62
11### Authentication Flow 63### Authentication Flow
@@ -167,10 +219,14 @@ authOpts := &auth.InterceptorOptions{
167 219
1681. **No passwords**: Uses public key cryptography 2201. **No passwords**: Uses public key cryptography
1692. **Decentralized**: No central identity provider 2212. **Decentralized**: No central identity provider
1703. **Per-request auth**: Each request is independently authenticated 2223. **Nostr ecosystem compatible**:
1714. **Nostr compatible**: Works with existing Nostr identities and tools 223 - Same authentication as NIP-42 for WebSocket relays
1725. **Standard pattern**: Uses industry-standard gRPC credentials interface 224 - Works with existing Nostr identities (npub/nsec)
1736. **Key rotation**: Easy to rotate keys without server-side updates 225 - Compatible with Nostr clients and tools
2264. **Efficient for streaming**: Authenticate once per stream (like NIP-42 for WebSocket)
2275. **Standard gRPC pattern**: Drop-in replacement for OAuth2/JWT using `credentials.PerRPCCredentials`
2286. **Flexible access control**: Enables relay-level permissions beyond event signatures
2297. **Key rotation**: Easy to rotate keys without server-side session management
174 230
175## Compatibility 231## Compatibility
176 232