Skip to content

Commit 7fb7cff

Browse files
committed
Add Ohttp nostr nip
1 parent a3c5554 commit 7fb7cff

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed

ohttp-nostr.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# NIP-X -- Nostr Relays as OHTTP Targets
2+
3+
This NIP defines how a Nostr relay can expose an **Oblivious HTTP (OHTTP) target** interface so that clients can send Nostr requests through an **OHTTP relay** without revealing their network identity to the target relay. Each request is encapsulated with an ephemeral HPKE key pair and routed via an OHTTP relay as per RFC 9458. The target relay processes the (decapsulated) request, decrypts the payload, and returns a response; the OHTTP relay cannot read contents, and the target relay cannot see client metadata.
4+
5+
Critical note: this design relies on two distinct roles (OHTTP relay and OHTTP target). If a single operator controls both and colludes, client unlinkability collapses (a known limitation of OHTTP). See RFC 9458 for the trust split and limitations. ([IETF](https://www.ietf.org/rfc/rfc9458.html), [RFC Editor](https://www.rfc-editor.org/info/rfc9458))
6+
7+
## Motivation
8+
9+
Nostr today relies on persistent WebSocket connections that inherently expose a client’s IP address to the relay. This creates a metadata-leakage channel: even if messages are encrypted, relays can trivially correlate client activity over time and build behavioral profiles. While users can route connections through Tor or VPNs, these options add operational complexity and do not guarantee reliable performance.
10+
11+
Oblivious HTTP (OHTTP) provides a standardized way to separate transport metadata from application payloads. By routing requests through an OHTTP relay, clients conceal their network identity from the target relay while preserving end-to-end confidentiality and integrity of their Nostr events. This introduces per-request unlinkability without requiring heavy overlay networks.
12+
13+
The design keeps protocol churn minimal. Clients and relays continue to use NIP-01 semantics, but transport shifts from a connection-oriented WebSocket to stateless OHTTP messages. Deployment is incremental: relays can expose OHTTP endpoints alongside WebSocket interfaces, advertising support in NIP-11. Clients that do not adopt OHTTP remain fully interoperable.
14+
15+
## Specification / Protocol Flow
16+
17+
Note: This NIP uses "relay" where RFC 9540 uses "gateway." They are equivalent roles.
18+
19+
### NIP-11 advertisement and OHTTP key configuration
20+
21+
Relays MUST support fetching [RFC 9540 Key Configuration Fetching](https://www.rfc-editor.org/rfc/rfc9540.html#name-key-configuration-fetching) via GET request. RFC 9540 defines the gateway location as `/.well-known/ohttp-gateway`. RFC9540 also defines the key configuration encoding.
22+
23+
Relays that implement this NIP MUST advertise the following new fields in their NIP-11 document:
24+
25+
```json
26+
{
27+
"ohttp": {
28+
"max_request_bytes": 65536,
29+
"max_response_bytes": 1048576,
30+
// Key configuration is optional, but if provided, it MUST be a hexified encoding of the key configuration.
31+
"keyconfig": "01001604d51a22bc641d1ff95729b815cd036f93d4eff9c76fa3c867000e4e05e1982e849b679050c981b9cea485adb2a2f1cfc905393345cf1364d8456e3aa3abc338da000400010003",
32+
}
33+
}
34+
```
35+
36+
Relays and clients MUST at minimum support the following configurations:
37+
38+
* Key Encapsulation Mechanism (KEM): Secp256k1-HKDF-SHA256
39+
* Key Derivation Function (KDF): HKDF-SHA256
40+
* Authenticated Encryption with Associated Data (AEAD): ChaCha20Poly1305
41+
42+
// TODO: the mac should be the same as the one used in DMs
43+
44+
<!-- Note: nip11 is a standard nostr event in of type 2 and is explicitly signed -->
45+
46+
The following configurations were chosen because most of the clients and relays are already using the same cryptographic primitives.
47+
48+
Relays CAN advertise their key configuration in the NIP-11 document to reduce round trips for the clients. If relays choose to do so, the relay MUST provide a hexified encoding of the key configuration.
49+
50+
### Retrieve key configuration
51+
52+
Clients MUST retrieve the OHTTP [key configuration](https://www.ietf.org/rfc/rfc9458.html#section-3.1) from the relay using RFC 9540 at the `/.well-known/ohttp-gateway` endpoint via a GET request. Clients MUST ensure the key fetching request is secure and authenticated. If the relay advertises the configuration in its NIP-11 document, clients MAY use that as an alternative bootstrap source but doing so may reveal the clients network identity.
53+
54+
The key configuration defines the HPKE parameters required to establish secure and authenticated communication with the target relay. When fetching the configuration, clients SHOULD route the request through an OHTTP relay to avoid exposing their network identity.
55+
56+
Once the configuration is retrieved, the client encapsulates a NIP-1 message inside a Binary HTTP (BHTTP) request and then applies HPKE to form the OHTTP request per RFC 9458.
57+
58+
* EVENT messages: Encapsulate as BHTTP `POST`. The body MUST contain the event as a JSON string.
59+
* REQ messages: Encapsulate as BHTTP `GET`. The query string MUST carry the NIP-1 filter, encoded either as a hexified JSON string or URL-encoded JSON (final encoding is TBD). // TODO decide on the encoding // TODO: decide on the query param. REQ messages MUST NOT include a subscription ID, as this leaks linkable metadata.
60+
61+
In order to preserve per-request unlinkability, clients MUST use a fresh ephemeral HPKE key pair per request. Furthermore, clients MUST NOT re-send the same request to the same relay.
62+
63+
### Endpoints
64+
65+
#### Target endpoints
66+
67+
Clients that receive a `404 Not Found` response SHOULD interpret it as an indication that the relay does not support OHTTP. In this case, clients SHOULD fall back to a standard WebSocket connection if they wish to interact with the relay.
68+
69+
* `POST /.well-known/ohttp-gateway` - Submit an OHTTP-encapsulated event.
70+
71+
The HTTP body MUST be a binary payload as defined in RFC 9458. The request MUST include a `Content-Type` header with the value `message/ohttp-req`. Relays MUST decapsulate the payload using their advertised key configuration to obtain the inner BHTTP request.
72+
73+
HTTP Responses MUST only include the encapsulated BHTTP response and they MUST return `200 OK` regardless of the inner BHTTP response.
74+
75+
#### BHTTP inner requests
76+
77+
After decapsulation, relays parse the inner BHTTP request. Two methods are supported. BHTTP responses MAY include status codes other than `200 OK`.
78+
Relays MUST enforce the request and response size limits advertised in NIP-11. All responses MUST be re-encapsulated and returned to the client using the client's reply key.
79+
80+
##### `POST`
81+
82+
The request body MUST contain a single NIP-1 `EVENT` message.
83+
84+
* If valid, the relay MUST return an empty `202 Accepted` response.
85+
* If malformed or invalid for any other reason, the relay MUST return `400 Bad Request`.
86+
* For server-side errors, the relay MUST return `500 Internal Server Error`.
87+
88+
##### `GET`
89+
90+
The request query parameter MUST contain a single NIP-1 `REQ` subscription filter message.
91+
92+
* A filter MUST be included in the query string with the key `filter`. // TODO: decide on the encoding
93+
* The encoding format for this filter (hexified JSON vs. URL-encoded JSON) remains an open question.
94+
95+
Relays MUST return a `200 OK` response with the inner BHTTP response if the request is valid. The response MUST be formatted as new line delimited JSON.
96+
97+
### Key configuration lifetime
98+
99+
Relays MUST rotate their OHTTP key configurations periodically to limit replay attacks and reduce the impact of key compromise. Key rotation is signaled via the HTTP caching headers (Cache-Control, Expires, ETag) on the response to the key configuration fetch defined in RFC 9540.
100+
101+
### Backwards Compatibility
102+
103+
Relays continue to support NIP-01 over WebSockets. Clients that do not implement OHTTP interoperate unchanged. The OHTTP interface introduces new endpoints; no changes to NIP-01 message schemas.
104+
105+
### Event Scope
106+
107+
This NIP defines a client-server interaction model and is scoped to the following event types only:
108+
109+
* [NIP-17](https://github.com/nostr-protocol/nips/blob/master/17.md) - Encrypted DMs
110+
* [NIP-57](https://github.com/nostr-protocol/nips/blob/master/57.md) - Zaps
111+
* [NIP-59](https://github.com/nostr-protocol/nips/blob/master/59.md) - Gift Wraps
112+
113+
Support for additional NIPs may be defined in future revisions but is out of scope for this specification.
114+
115+
Relays that receive an event outside this scope MUST return a `400 Bad Request` status in the encapsulated BHTTP response.
116+
117+
## Open Questions
118+
119+
* Streaming: Whether to standardize a chunked/streaming profile once IETF work stabilizes. ([ietf-wg-ohai.github.io](https://ietf-wg-ohai.github.io/draft-ohai-chunked-ohttp/draft-ietf-ohai-chunked-ohttp.html)). Subscriptions: Avoid long-lived state through OHTTP. Use poll+cursor now; consider chunked OHTTP later when code and standards stabilize.
120+
121+
* Denial of service protection: Standardize a NIP for token issuance/redemption to control abuse while preserving unlinkability.
122+
123+
## Reference Implementation
124+
125+
A client reference can be found [here](https://github.com/arminsabouri/nostr/blob/ohttp-example/crates/nostr-sdk/examples/ohttp.rs).
126+
A nostr relay reference can be found [here](https://github.com/arminsabouri/nostr-rs-relay/tree/ohttp-target).

0 commit comments

Comments
 (0)