1 Overview
Nostr identities are keypairs, not accounts. A relay that restricts a resource still needs proof that the connected client controls a specific key. This NIP defines that proof. The client signs an ephemeral event that contains a challenge string from the relay. The relay verifies the signature and marks the connection as authenticated for that pubkey.
A relay may want this for several jobs. It may accept paid or whitelisted users only, and accept any event those users publish. It may limit kind: 4 direct messages (NIP-04) so only the two chat parties can query them. It may limit subscriptions of any kind to paying or whitelisted users.
Authentication is per connection. It uses one new message type, one new event kind, and two machine-readable status prefixes. All of them are defined below.
Nothing here creates a session token or a cookie. The proof lives and dies with the WebSocket connection. Reconnect, and the relay hands you a fresh challenge.
2 The AUTH Message
This NIP adds one message type, AUTH, to the NIP-01 message set. Both sides can send it, with different payloads:
| Direction | Shape | Purpose |
|---|---|---|
| relay → client | ["AUTH", <challenge-string>] | Offer a challenge. Relays that support authentication can send this. |
| client → relay | ["AUTH", <signed-event-json>] | Prove control of a key by returning the signed challenge event. |
The relay may send its AUTH challenge at any moment. The challenge stays valid for the duration of the connection, or until the relay sends another challenge. The client may send its AUTH event at any point. The authenticated session then stays valid for the rest of the connection.
A client may authenticate more than one pubkey. It sends signed events from multiple pubkeys in a sequence of AUTH messages. The relay must treat all of those pubkeys as authenticated.
The relay must answer every client AUTH message with an OK message, exactly as it answers an EVENT message.
3 The Authentication Event
The proof is an ephemeral event of kind: 22242. It is not meant to be published or queried. It should carry at least two tags: one with the relay URL and one with the challenge string as received from the relay. The created_at field should be the current time.
{
"kind": 22242,
"tags": [
["relay", "wss://relay.example.com/"],
["challenge", "challengestringhere"]
],
// other NIP-01 fields: id, pubkey, created_at, content, sig...
}
| Tag | Value | Rule |
|---|---|---|
| relay | relay URL | The URL of the relay the client authenticates to. |
| challenge | challenge string | The exact string received from the relay in its AUTH message. |
Relays must exclude kind: 22242 events from broadcast to any client. The event proves key control to one relay only. Leaking it serves no one; kind 22242 sits in the ephemeral range, so relays do not store it either.
Verification rules
To verify a client AUTH message, the relay must check all of the following:
- The
kindis22242. - The
created_atis close to the current time. About 10 minutes of tolerance is the suggested window. - The
challengetag matches the challenge the relay sent before. - The
relaytag matches the relay's own URL. URL normalization may apply; for most cases a correct domain name is enough.
4 Status Prefixes and the EOSE Hint
This NIP defines two machine-readable prefixes for the OK and CLOSED messages of NIP-01. OK carries them when the relay rejects an event write. CLOSED carries them when the relay rejects a subscription.
| Prefix | Meaning |
|---|---|
| auth-required: | The client has not performed AUTH. The relay requires it to fulfill this query or write this event. |
| restricted: | The client already performed AUTH, but its key is still not allowed, or exceeds its authorization. |
A relay may also use the "auth" hint in an EOSE message, as defined in NIP-67. The hint tells the client that more results may be available after authentication. In that case the relay must send its AUTH challenge before the EOSE message.
The restricted: prefix also appears in the standard OK prefix list of NIP-01. The two definitions agree, but the rule lives in both documents. Also, the motivation section still cites kind: 4 DMs from NIP-04, which is deprecated in favor of NIP-17; the auth mechanism itself is unaffected.
5 Protocol Flow
A relay usually requires authentication only for certain jobs, such as answering a REQ or accepting an EVENT write. The flows below are the expected common cases.
auth-required in response to a REQ
The client asks for restricted events. The relay closes the subscription with an auth-required message. The client authenticates and repeats the request. The only requirement: the client must hold a stored challenge for that relay before it can react to the CLOSED message. The relay may send its AUTH challenge right when the client connects, or immediately before the CLOSED.
REQ succeeds.auth-required in response to an EVENT
The same flow applies when the client writes an event. The relay answers the write with an OK message set to false and an auth-required prefix, instead of a CLOSED message. The client authenticates and sends the event again. See the transcript in §6.
6 Worked Example
The session below shows both flows on one connection. Orange lines go to the relay. Blue lines come from the relay. Note the two AUTH events from different pubkeys: the relay authenticates both keys.
-- on connect, the relay offers a challenge -- ← ["AUTH", "8bd1a2f9c044"] -- an unauthenticated write is refused -- → ["EVENT", {"id":"012345ab…", "kind":1, …}] ← ["OK", "012345ab…", false, "auth-required: we only accept events from registered users"] -- the client signs the challenge, once per pubkey -- → ["AUTH", {"id":"abcdef01…","pubkey":"22a12a12…","created_at":1756713600, "kind":22242, "tags":[["relay","wss://relay.example.com/"],["challenge","8bd1a2f9c044"]], "content":"","sig":"90cf86e1…"}] → ["AUTH", {"id":"abcde202…","pubkey":"7be44a11…","kind":22242, …}] ← ["OK", "abcdef01…", true, ""] ← ["OK", "abcde202…", true, ""] -- the same write now succeeds -- → ["EVENT", {"id":"012345ab…", "kind":1, …}] ← ["OK", "012345ab…", true, ""] -- restricted queries work too -- → ["REQ", "dms", {"kinds":[4]}] ← ["EVENT", "dms", {…}] ← ["EOSE", "dms"] -- but a key the relay does not allow still gets -- ← ["CLOSED", "sub_9", "restricted: this key has no paid plan"]
7 Version History
NIP-42 began as a simplification of an earlier authentication draft by semisol. fiatjaf rewrote it in January 2023, and it has grown a few capabilities since. Notable changes, newest first:
- 20262026-09Added the
"auth"hint forEOSEmessages, defined in NIP-67. - 20252025-12Added the
relaytag check to the verification checklist. - 20252025-09Allowed multi-user
AUTH: several pubkeys can authenticate on one connection. - 20232023-12Integrated
CLOSEDmessages:auth-requiredandrestrictedprefixes for rejected subscriptions and writes. - 20232023-01Added the relay-generated challenge; clarified
created_atand session duration; switched replies to theOKmessage. - 2023+2023-2026Formatting passes, JSON cleanups, and author-list removal.
- Origin2023-01fiatjaf published the NIP as a drastic simplification of semisol's auth proposal.
Original Proposal - Credits
| Author | fiatjaf (simplifying an earlier draft by semisol) |
| First commit | 2023-01-02 — “drastically simplify @semisol's auth NIP” |
| Status | draft - optional - relay — relays choose whether to require it |
| Source | 42.md on GitHub - full change history |
8 See Also
- NIP-01 — the base protocol:
EVENT,REQ,OK,CLOSED, and the ephemeral kind range that 22242 sits in. - NIP-67 — the
EOSEcompleteness hint, including the"auth"hint used here. - NIP-70 — protected events, which lean on this NIP so only the author can publish them.
- NIP-04 — the deprecated
kind: 4DMs named in the motivation; see NIP-17 for the replacement. - NIP-11 — the relay information document, where a relay can advertise its limits.