clone

every nostr nip as a chapter of an illustrated, early-2000s printed game manual

main
nip.guide / site / nips / 70.html
70.html 18.1K
1<!DOCTYPE html>2<html lang="en">3<head>4<meta charset="utf-8">5<meta name="viewport" content="width=device-width, initial-scale=1">6<title>NIP-70 - Protected Events — Nostr Instruction Manual</title>7<meta name="description" content="NIP-70: protected events. The [&quot;-&quot;] tag marks an event that only its author may publish, enforced by relays through NIP-42 authentication.">8<link rel="preload" href="../assets/fonts/michroma-400-latin.woff2" as="font" type="font/woff2" crossorigin>9<link rel="preload" href="../assets/fonts/exo2-var-latin.woff2" as="font" type="font/woff2" crossorigin>10<link rel="preload" href="../assets/fonts/sairacondensed-600-latin.woff2" as="font" type="font/woff2" crossorigin>11<link rel="preload" href="../assets/fonts/sairacondensed-700-latin.woff2" as="font" type="font/woff2" crossorigin>12<link rel="preload" href="../assets/fonts/sairacondensed-500-latin.woff2" as="font" type="font/woff2" crossorigin>13<link rel="preload" href="../assets/fonts/sharetechmono-400-latin.woff2" as="font" type="font/woff2" crossorigin>14<link rel="preload" href="../assets/fonts/exo2-400i-latin.woff2" as="font" type="font/woff2" crossorigin>15<link rel="icon" href="../assets/favicon.svg" type="image/svg+xml">16<link rel="stylesheet" href="../assets/manual.css">17</head>18<body>1920<svg width="0" height="0" style="position:absolute">21 <defs>22 <marker id="arr" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">23 <path d="M1,1 L8,4.5 L1,8 Z" fill="#f26a00"/>24 </marker>25 <marker id="arrb" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">26 <path d="M1,1 L8,4.5 L1,8 Z" fill="#2e5f9e"/>27 </marker>28 </defs>29</svg>3031<div class="page">32 <span class="staple s1"></span><span class="staple s2"></span>3334 <header class="band">35 <a class="logo" href="../index.html">NOSTR<b>▸</b>PROTOCOL MANUAL</a>36 <span class="booklet-note">Chapter 70 - Relay Ops</span>37 </header>38 <nav class="tabs">39 <a href="../index.html">Contents</a>40 <a href="#overview" class="on">Overview</a>41 <a href="#spec">Spec</a>42 <a href="#examples">Examples</a>43 <a href="#history">History</a>44 </nav>4546 <div class="chapter">47 <div class="nipno" data-n="70">70</div>48 <div class="titles">49 <div class="kicker">Nostr Implementation Possibility - Hex № 70</div>50 <h1>Protected Events</h1>51 <p class="sub">One tiny tag, <code>["-"]</code>, marks an event that only its author may publish to a relay.</p>52 </div>53 </div>5455 <main class="spread">56 <div class="main">5758 <h2 class="bar" id="overview"><span class="num">1</span> Overview</h2>59 <p>By default, anyone can copy a signed event and publish it to any relay. The signature stays valid everywhere. This NIP adds a brake. An event that carries the <code>["-"]</code> tag is a <strong>protected event</strong>. A protected event can only be published to relays by its author.</p>60 <p>Relays enforce this rule. A relay checks that the publisher is the author before it stores the event. The check uses <a href="42.html">NIP-42</a> authentication. A relay may also refuse all protected events instead. Refusal is the required default.</p>61 <p>The tag is a clear signal from the author: do not republish this event to other relays. A relay that sees the tag knows the event is not intended for third-party redistribution.</p>6263 <div class="box hint">64 <span class="tag">Hint!</span>65 <p>Protection is not encryption. A protected event is still readable by anyone the relay serves it to. To hide content, use <a href="17.html">NIP-17</a> private messages or <a href="44.html">NIP-44</a> encryption. NIP-70 only limits who can <em>publish</em>, not who can read.</p>66 </div>6768 <figure class="diagram">69 <div class="frame">70 <svg viewBox="0 0 560 210" role="img" aria-label="A protected event from its author is accepted after authentication; the same event republished by a third party is rejected">71 <rect class="d-actor" x="10" y="20" width="120" height="50" rx="8"/>72 <text class="d-actor-label" x="70" y="42" text-anchor="middle">Author</text>73 <text class="d-note" x="70" y="59" text-anchor="middle">AUTH ok</text>74 <rect class="d-actor" x="10" y="140" width="120" height="50" rx="8"/>75 <text class="d-actor-label" x="70" y="162" text-anchor="middle">Third party</text>76 <text class="d-note" x="70" y="179" text-anchor="middle">copies the event</text>77 <rect class="d-actor" x="225" y="80" width="110" height="50" rx="8"/>78 <text class="d-actor-label" x="280" y="102" text-anchor="middle">Relay</text>79 <text class="d-note" x="280" y="119" text-anchor="middle">pubkey check</text>80 <rect class="d-actor" x="440" y="20" width="110" height="50" rx="8"/>81 <text class="d-actor-label" x="495" y="42" text-anchor="middle">Stored</text>82 <text class="d-note" x="495" y="59" text-anchor="middle">OK true</text>83 <rect class="d-actor" x="440" y="140" width="110" height="50" rx="8"/>84 <text class="d-actor-label" x="495" y="162" text-anchor="middle">Rejected</text>85 <text class="d-note" x="495" y="179" text-anchor="middle">OK false</text>86 <path class="d-msg d-flow" d="M132,50 C180,60 180,85 223,95"/>87 <path class="d-msg d-flow" d="M132,160 C180,150 180,125 223,115"/>88 <path class="d-msg blue d-flow" d="M337,95 C380,85 390,60 438,50"/>89 <path class="d-msg blue d-flow" d="M337,115 C380,125 390,150 438,160"/>90 <text class="d-label" x="165" y="42" text-anchor="middle">EVENT ["-"]</text>91 <text class="d-label" x="165" y="172" text-anchor="middle">EVENT ["-"]</text>92 <circle r="4" fill="#f26a00">93 <animateMotion dur="2.6s" repeatCount="indefinite" path="M132,50 C180,60 180,85 223,95"/>94 </circle>95 <circle r="4" fill="#2e5f9e">96 <animateMotion dur="2.6s" begin="1.3s" repeatCount="indefinite" path="M337,115 C380,125 390,150 438,160"/>97 </circle>98 </svg>99 </div>100 <figcaption>Fig. 70-1 — <b>Author-only publishing.</b> The relay accepts a protected event from its authenticated author. It rejects the same event from anyone else.</figcaption>101 </figure>102103 <h2 class="bar" id="spec"><span class="num">2</span> The Protected Tag</h2>104 <p>The tag is a simple tag with a single item: <code>["-"]</code>. The tag name is the single character <code>-</code>. The tag has no value. A client may add the tag to any event of any kind.</p>105106 <div class="crt">107 <div class="titlebar">Wire format - protected event (any kind)</div>108<pre>{109 <span class="k">"id"</span>: <span class="c">&lt;computed as in NIP-01&gt;</span>110 <span class="k">"pubkey"</span>: <span class="c">&lt;author public key&gt;</span>111 <span class="k">"kind"</span>: <span class="c">&lt;any kind&gt;</span>112 <span class="k">"tags"</span>: [[<span class="s">"-"</span>]]113 <span class="k">"content"</span>: <span class="c">&lt;arbitrary string&gt;</span>114 ...115}</pre>116 </div>117118 <div class="tscroll"><table class="ref">119 <caption>Tag reference</caption>120 <tr><th>Tag</th><th>Shape</th><th>Meaning</th></tr>121 <tr><td class="btn">-</td><td><code>["-"]</code> — name only, no value</td><td>The event is protected. Only its author may publish it to relays.</td></tr>122 </table></div>123124 <div class="box tech">125 <span class="tag">Tech Note</span>126 <p>The tag name <code>-</code> is not an English letter. Under <a href="01.html">NIP-01</a> rules, relays index only single-letter tags <code>a</code>-<code>z</code> and <code>A</code>-<code>Z</code>. So there is no standard <code>#-</code> filter, and the spec defines no way to query for protected events. Relays must inspect the <code>tags</code> array directly at publish time.</p>127 </div>128129 <h2 class="bar" id="relay"><span class="num">3</span> Relay Rules</h2>130 <p>The default behavior of a relay MUST be to reject any event that contains <code>["-"]</code>. A relay that does not implement this NIP still complies by rejecting the tag outright.</p>131 <p>A relay that wants to accept protected events MUST follow this procedure:</p>132 <ol>133 <li>Require the client to complete the <a href="42.html">NIP-42</a> <code>AUTH</code> flow first.</li>134 <li>Compare the authenticated client's pubkey with the <code>pubkey</code> field of the published event.</li>135 <li>Accept the event only when the two pubkeys are the same. Reject it otherwise.</li>136 </ol>137138 <div class="tscroll"><table class="ref">139 <caption>Relay decision table</caption>140 <tr><th>Condition</th><th>Relay action</th></tr>141 <tr><td>Event has <code>["-"]</code>, relay does not support this NIP</td><td>Reject. This is the required default.</td></tr>142 <tr><td>Event has <code>["-"]</code>, client is not authenticated</td><td>Send an <code>AUTH</code> challenge and reject with an <span class="kbd">auth-required:</span> message.</td></tr>143 <tr><td>Event has <code>["-"]</code>, authenticated pubkey matches <code>event.pubkey</code></td><td>Accept and store the event.</td></tr>144 <tr><td>Event has <code>["-"]</code>, authenticated pubkey differs from <code>event.pubkey</code></td><td>Reject the event.</td></tr>145 <tr><td>Repost embeds a protected event</td><td>Reject the repost. See §4.</td></tr>146 </table></div>147148 <figure class="diagram">149 <div class="frame">150 <svg viewBox="0 0 560 300" role="img" aria-label="Sequence diagram: relay rejects a protected event with auth-required, client authenticates, resends the event, and the relay accepts it">151 <line class="d-wire" x1="110" y1="40" x2="110" y2="285" stroke-dasharray="3 4"/>152 <line class="d-wire" x1="450" y1="40" x2="450" y2="285" stroke-dasharray="3 4"/>153 <rect class="d-actor" x="55" y="8" width="110" height="30" rx="6"/>154 <text class="d-actor-label" x="110" y="28" text-anchor="middle">Client</text>155 <rect class="d-actor" x="395" y="8" width="110" height="30" rx="6"/>156 <text class="d-actor-label" x="450" y="28" text-anchor="middle">Relay</text>157 <path class="d-msg" d="M110,62 L445,62"/>158 <text class="d-label" x="280" y="55" text-anchor="middle">["EVENT", {…, "tags":[["-"]], …}]</text>159 <path class="d-msg blue" d="M450,95 L115,95"/>160 <text class="d-label" x="280" y="88" text-anchor="middle">["AUTH", "&lt;challenge&gt;"]</text>161 <path class="d-msg blue" d="M450,128 L115,128"/>162 <text class="d-label" x="280" y="121" text-anchor="middle">["OK", &lt;id&gt;, false, "auth-required: …"]</text>163 <path class="d-msg" d="M110,170 L445,170"/>164 <text class="d-label" x="280" y="163" text-anchor="middle">["AUTH", &lt;signed kind-22242 event&gt;]</text>165 <path class="d-msg" d="M110,203 L445,203"/>166 <text class="d-label" x="280" y="196" text-anchor="middle">["EVENT", {…, "tags":[["-"]], …}] again</text>167 <path class="d-msg blue d-flow" d="M450,236 L115,236"/>168 <text class="d-label" x="280" y="229" text-anchor="middle">["OK", &lt;id&gt;, true, ""]</text>169 <text class="d-note" x="280" y="270" text-anchor="middle">Accepted only because the authenticated pubkey equals event.pubkey.</text>170 </svg>171 </div>172 <figcaption>Fig. 70-2 — <b>Publish with authentication.</b> The relay challenges first, then accepts the resent event from its author.</figcaption>173 </figure>174175 <div class="box warn">176 <span class="tag">Warning!</span>177 <p>Protection works only on cooperating relays. Any reader can still copy a protected event and push it to a relay that ignores this NIP. The tag expresses the author's intent; it cannot make republication impossible.</p>178 </div>179180 <h2 class="bar" id="reposts"><span class="num">4</span> Reposts</h2>181 <p>Reposts of protected events MUST NOT embed the reposted event. A <a href="18.html">NIP-18</a> repost normally carries the full reposted event as stringified JSON in <code>content</code>. For a protected event, the repost must leave that copy out.</p>182 <p>If a repost embeds a protected event anyway, relays SHOULD summarily reject the repost. An embedded copy would smuggle the protected event past the author-only publish rule.</p>183184 <h2 class="bar" id="examples"><span class="num">5</span> Worked Example</h2>185 <p>User <code>79be667e…f81798</code> publishes a protected kind-1 note to <code>wss://example.com</code>. The relay demands authentication first. Orange lines go to the relay. Blue lines come from the relay.</p>186 <div class="crt">187 <div class="titlebar">Session transcript - wss://example.com</div>188<pre><span class="c">-- client publishes a protected note --</span>189<span class="send">→ ["EVENT", {"id":"cb8feca582…9eef6f2","pubkey":"79be667ef9…f81798",190 "created_at":1707409439,"kind":1,"tags":[["-"]],191 "content":"hello members of the secret group","sig":"fa163f5c…9fa684c"}]</span>192<span class="c">-- relay refuses and challenges --</span>193<span class="recv">← ["AUTH", "&lt;challenge&gt;"]</span>194<span class="recv">← ["OK", "cb8feca582…9eef6f2", false,195 "auth-required: this event may only be published by its author"]</span>196<span class="c">-- client authenticates (signed kind-22242 event, see NIP-42) --</span>197<span class="send">→ ["AUTH", {<span class="c">…signed auth event…</span>}]</span>198<span class="c">-- client sends the same event again --</span>199<span class="send">→ ["EVENT", {"id":"cb8feca582…9eef6f2", …, "tags":[["-"]], …}]</span>200<span class="recv">← ["OK", "cb8feca582…9eef6f2", true, ""]</span></pre>201 </div>202203 <h2 class="bar" id="why"><span class="num">6</span> Why It Exists</h2>204 <p>Sometimes an author does not want an event to spread to every relay imaginable. The author may target a certain demographic, or a semi-closed community relay. Even public information can make sense to keep compartmentalized across different relays.</p>205 <p>The tag also enables closed-access feeds. The publisher has a relationship with one relay and trusts it not to release the published events to anyone. Only the author can place those events there.</p>206 <p>It is ultimately impossible to restrict the spread of information on the internet. A member of a closed group can copy a restricted event and republish it elsewhere. But most relays are happy to not help these so-called "pirates". Given a clear signal, they gladly reject the republish attempt out of respect for the author's decision. This NIP is that signal.</p>207208 <h2 class="bar" id="history"><span class="num">7</span> Version History</h2>209 <p>NIP-70 is a short spec and has stayed close to its original form. Notable changes, newest first:</p>210 <ul class="patchnotes">211 <li><span class="ver">2026</span><span class="when">2026-05</span>Added the repost rule: reposts must not embed protected events, and relays should reject reposts that do.</li>212 <li><span class="ver">2025</span><span class="when">2025-12</span>Tagged the NIP with the <code>relay</code> category to mark it as relay-enforced behavior.</li>213 <li class="minor"><span class="ver">2024</span><span class="when">2024-2026</span>Housekeeping: relative links and code-fence formatting.</li>214 <li><span class="ver">Origin</span><span class="when">2024-07</span>fiatjaf proposed relay-based event access control with the <code>["-"]</code> tag.</li>215 </ul>216217 <div class="credits">218 <h3 class="cardhead">Original Proposal - Credits</h3>219 <table>220 <tr><td>Author</td><td>fiatjaf</td></tr>221 <tr><td>First commit</td><td>2024-07-10 — “relay-based event access-control with the <code>["-"]</code> tag” (<a href="https://github.com/nostr-protocol/nips/pull/1030">PR #1030</a>)</td></tr>222 <tr><td>Status</td><td>draft - optional — relays reject the tag by default</td></tr>223 <tr><td>Source</td><td><a href="https://github.com/nostr-protocol/nips/blob/master/70.md">70.md on GitHub</a> - <a href="https://github.com/nostr-protocol/nips/commits/master/70.md">full change history</a></td></tr>224 </table>225 </div>226227 <h2 class="bar"><span class="num">8</span> See Also</h2>228 <ul>229 <li><a href="01.html">NIP-01</a> — the event object, tags, and the <code>OK</code> message this NIP builds on.</li>230 <li><a href="42.html">NIP-42</a> — the <code>AUTH</code> flow relays use to verify the author's pubkey.</li>231 <li><a href="18.html">NIP-18</a> — reposts; for protected events they must not embed the event.</li>232 <li><a href="17.html">NIP-17</a> — private direct messages, when you need secrecy rather than publish control.</li>233 <li><a href="29.html">NIP-29</a> — relay-based groups; another pattern for community-scoped content.</li>234 </ul>235 </div>236237 <aside>238 <div class="cartridge">239 <div class="inner">240 <h3 class="cardhead">Spec Card</h3>241 <div class="lights"><span class="led on"></span><span class="led on"></span><span class="led on"></span></div>242 <dl>243 <dt>Status</dt><dd><span class="chip draft">draft</span><span class="chip">optional</span><span class="chip">relay</span></dd>244 <dt>Defines</dt><dd>the <code>["-"]</code> protected tag - author-only publish rule - repost restriction</dd>245 <dt>Kind(s)</dt><dd>none — the tag applies to any kind</dd>246 <dt>Requires</dt><dd><a href="01.html">NIP-01</a> - <a href="42.html">NIP-42</a></dd>247 <dt>Enforced by</dt><dd>relays, at publish time</dd>248 <dt>First commit</dt><dd>2024-07-10</dd>249 <dt>Last updated</dt><dd>2026-06-13</dd>250 </dl>251 </div>252 </div>253 </aside>254 </main>255256 <nav class="navbtns">257 <a href="69.html">◀ NIP-69: Peer-to-peer Order events</a>258 <a href="71.html">NIP-71: Video Events ▶</a>259 </nav>260261 <footer class="pagefoot">262 <a href="../index.html">Nostr Protocol Manual</a>263 <span class="pageno">NIP 70 / F4</span>264 </footer>265</div>266267<script src="../assets/webmcp.js" defer></script>268</body>269</html>