Files
amethyst/nestsClient/specs/EGG-02.md
T
Claude 5c40e27fde docs(nestsClient/specs): EGG-00..EGG-12 — Extensible Gossip Guidelines
Wire-protocol specs for nostrnests-style audio rooms, in the
style of Nostr NIPs and Blossom BUDs. Each spec documents one
self-contained capability that a client or relay can implement;
two compliant peers implementing the same set of EGGs round-trip
without further coordination.

Layout:

  README.md            cover, status table, conformance levels
  EGG-01.md  Room event (kind:30312)              required
  EGG-02.md  Auth + WebTransport handshake        required
  EGG-03.md  Audio plane (moq-lite)               required
  EGG-04.md  Presence (kind:10312)                required
  EGG-05.md  In-room chat (kind:1311)             optional
  EGG-06.md  Reactions (kind:7)                   optional
  EGG-07.md  Roles & moderation (kind:4312)       optional
  EGG-08.md  Scheduling (status=planned)          optional
  EGG-09.md  User server list (kind:10112)        optional
  EGG-10.md  Theming (c/f/bg tags)                decorative
  EGG-11.md  Recording                            decorative
  EGG-12.md  Catalog track (catalog.json)         optional

Conformance levels (Listener / Speaker / Host) defined in the
README so a deployment can declare "we implement EGG-01..EGG-04"
and other peers know exactly what to expect.

Each spec follows the same shape (Summary / Wire format /
Behavior numbered MUST/SHOULD/MAY rules / Example /
Compatibility) and fits on a single printed page. Wire formats
are documented exactly as nostrnests + amethyst implement them
on this branch — no hypothetical capabilities, no "future" tags
without an EGG number.
2026-04-27 03:54:45 +00:00

112 lines
3.6 KiB
Markdown

# EGG-02: Auth & WebTransport handshake
`status: draft`
`requires: EGG-01, NIP-98`
`category: required`
## Summary
To open the audio plane (EGG-03), a peer first proves identity to a per-room
auth sidecar (moq-auth) using a NIP-98 HTTP signature, receives a short-lived
JWT, then opens a WebTransport session against the moq-relay carrying the JWT
in the URL.
Two separate URLs are involved: the `service` tag from EGG-01 is the auth
sidecar; the `endpoint` tag is the relay.
## Wire format
### Step 1 — token request
```
POST <service>/auth
Authorization: Nostr <base64(NIP-98 kind:27235 event)>
Content-Type: application/json
{ "namespace": "nests/<kind>:<host_pubkey_hex>:<room_d>",
"publish": <boolean> }
```
`<kind>` is `30312` for nests audio rooms (EGG-01).
The NIP-98 event MUST bind to this exact URL, method `POST`, and the SHA-256
hash of the request body.
### Step 2 — token response
```
HTTP/1.1 200 OK
Content-Type: application/json
{ "token": "<jwt>" }
```
The JWT carries (at minimum):
| claim | meaning |
|---------|---------------------------------------------------------------|
| `root` | The exact `namespace` echoed back. Authorisation is scoped here. |
| `get` | Read-allowed sub-paths; for nests this is `[""]` (any). |
| `put` | Publish-allowed sub-paths. For listeners: `[]`. For speakers: `[<own pubkey hex>]`. |
| `iat` | Unix seconds; issuance. |
| `exp` | Unix seconds; expiry. MUST be `iat + 600` for nests today. |
### Step 3 — WebTransport CONNECT
```
:method = CONNECT
:protocol = webtransport
:scheme = https
:authority = <host:port from `endpoint`>
:path = /<namespace>?jwt=<token>
```
The relay reads the JWT from the `?jwt=` query string. No `Authorization`
header is used at this step.
## Behavior
1. Listening peers MUST request `publish: false`. Speaking peers MUST request
`publish: true` AND the JWT's `put` claim MUST list the speaker's own
pubkey hex.
2. The auth sidecar's TLS certificate MUST be a publicly-trusted chain. The
relay's TLS chain MAY be self-signed in development; production deployments
MUST use a public chain.
3. The auth sidecar SHOULD reject any request whose NIP-98 `created_at` is
more than 60 s in the past or future.
4. The JWT lifetime is fixed at 600 s. There is no refresh endpoint. A client
that needs a longer session MUST mint a fresh token and open a new
WebTransport session before the old token expires; see the deployment-side
commentary in `nestsClient/plans/`.
5. The relay MUST close the WebTransport session within 30 s of `exp`. A peer
receiving an unexpected close MUST be prepared to mint a fresh token and
reconnect.
6. The relay MUST NOT trust the WebTransport authority for authorisation —
only the JWT's `root` claim. A token issued for namespace A MUST NOT be
accepted on a session opened against namespace B.
7. A peer MUST NOT log the JWT or include it in error reports. The token is a
bearer credential.
## Example
```
> POST https://moq.nostrnests.com/auth
> Authorization: Nostr eyJ...kind27235...
> Content-Type: application/json
>
> {"namespace":"nests/30312:abchost:office-hours-2026-04","publish":false}
< HTTP/1.1 200 OK
< Content-Type: application/json
<
< {"token":"eyJhbGc..."}
> CONNECT :path=/nests/30312:abchost:office-hours-2026-04?jwt=eyJhbGc...
< 200 OK (WebTransport session established)
```
## Compatibility
EGG-03 (audio plane) operates inside the WebTransport session this EGG opens.
EGG-12 (catalog) shares the same session.