NIP-42 walkthrough: reading gated Nostr content from any client
- Context
- The handshake
- After auth: REQ with per-subscriber filtering
- What your client needs to handle
- NIP-11 access_control proposal
- Why this matters
Anyone with a NIP-42-aware Nostr client and a valid Nostreon subscription can read premium content from any other Nostr client. No Nostreon SDK. No special integration. This post is the concrete walkthrough for developers building or extending Nostr clients that want to support gated subscription content. We’ll look at the handshake, the filter rules, and what a client needs to implement to work end-to-end.
Context
Nostreon runs a gated relay at wss://premium.nostreon.com. Subscribers authenticate with NIP-42 and read premium content published by the creators they’ve paid for. The same content is accessible from any Nostr client that speaks NIP-42, not just the Nostreon web app.
The public relay at wss://relay.nostreon.com carries teasers, NIP-63 announcement events, and NIP-88 tier metadata for discoverability. The gated relay carries the full content and gates reads per subscription state.
The handshake
On connect, the gated relay immediately issues a NIP-42 AUTH challenge. The client signs a kind-22242 event with the matching challenge and relay URL and sends it back.
const ws = new WebSocket("wss://premium.nostreon.com");
ws.on("message", (raw) => {
const [verb, data] = JSON.parse(raw);
if (verb === "AUTH") {
// Sign a kind 22242 event with matching challenge + relay tag
const auth = signEvent({
kind: 22242,
created_at: Math.floor(Date.now() / 1000),
tags: [
["relay", "wss://premium.nostreon.com"],
["challenge", data],
],
content: "",
});
ws.send(JSON.stringify(["AUTH", auth]));
}
});
The relay verifies the signature, the created_at window, the relay-tag match, and the challenge-tag match. On success it responds ["OK", event_id, true, ""]. On failure it responds ["OK", event_id, false, "auth-required: <reason>"].
After auth: REQ with per-subscriber filtering
Once authenticated, REQ works normally but the relay filters every event before delivering it. A given event is delivered to the authenticated connection if any of these rules match:
- The authed pubkey is the event author. Creators always see their own content.
- The event author is a creator the authed pubkey has an active subscription to. Resolved server-side against the subscriptions database and cross-checked against NIP-63 kind 1163 membership events on the relay itself.
- The event is a NIP-63 kind 1163 membership or NIP-88 kind 7003 payment receipt where a
ptag matches the authed pubkey. This lets any third-party client verify the user’s own subscription state by reading from the relay directly.
Events that don’t match any rule are dropped silently. A non-subscriber who completes the NIP-42 handshake can’t read anything they haven’t paid for. A subscriber to creator A can’t read content published by creator B unless they also subscribe to B.
What your client needs to handle
Minimum viable integration for a client that wants to support reading gated Nostreon content for its users:
- Respond to
["AUTH", challenge]with a signed kind-22242 event carrying the relay URL and the echoed challenge. - Accept that REQ results are filtered. Missing events that you might have expected based on a NIP-65 relay list or a note’s relay hint are not a bug; they may be a subscription boundary. Render a subscribe affordance rather than showing the event as broken.
- When rendering an addressable event that includes a
["nip63"]tag or an["a", "37001:<creator>:<tier>"]tier reference, you can check the user’s NIP-63 kind 1163 membership events for that creator to decide whether to render the full content or a paywall. Both the tier events (kind 37001) and the membership events (kind 1163) are public information, available on the relay the user is already connected to. - If you want to discover subscription requirements before connecting, query the relay’s NIP-11 document. The proposed
access_controlfield describes what authentication is required and what kinds are gated.
NIP-11 access_control proposal
Nostreon’s gated relay ships a reference implementation of the proposed access_control field in NIP-11. You can see it live:
curl -H "Accept: application/nostr+json" https://premium.nostreon.com/
The response includes an access_control object describing the authentication requirement and the kinds that are gated, plus an info_url that clients can surface as a “subscribe” link when the current user doesn’t have access.
The proposal is at https://github.com/nostr-protocol/nips/pull/2318 and currently in review. Feedback welcome.
Why this matters
Subscription-gated content on the protocol without a platform lock-in. A reader pays once on nostreon.com; their subscription is recorded as a NIP-63 membership event on the gated relay; any NIP-42-aware client they use later can verify that membership and deliver the content. The creator gets paid via Lightning at settlement time. No custody, no platform rent, no client-specific integration.
The full relay-gate reference implementation is open source: https://github.com/Nostreon/relay-auth