From 82aafbef39a4a183fc6b1e8488e4a2db81a3fa90 Mon Sep 17 00:00:00 2001 From: Semisol <45574030+Semisol@users.noreply.github.com> Date: Fri, 16 Dec 2022 01:11:08 +0300 Subject: [PATCH] add nip-41: authentication --- 41.md | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 41.md diff --git a/41.md b/41.md new file mode 100644 index 00000000..56adf3fe --- /dev/null +++ b/41.md @@ -0,0 +1,69 @@ +NIP-41 +====== + +Authentication of clients to relays +----------------------------------- + +`draft` `optional` `author:Semisol` + +This NIP defines a way for clients to authenticate to relays by signing an ephemeral event. + +## Event format + +An event should be signed with `kind: 22241` and `content` being the WebSockets URL of the relay. +The URL MUST: +- Have a trailing slash if the path is `/` +- Not have a port number if protocol is `ws` and port is `80` or protocol is `wss` and port is `443` +- Not include the search/query + +An example event is shown below: +```json +{ + "id": "...", + "pubkey": "...", + "created_at": 1669695536, + "kind": 22223, + "tags": [], + "content": "wss://relay.example.com/", + "sig": "..." +} +``` + +## Commands between the relay and the client + +This NIP defines a new command, `AUTH`, which can be sent by either the relay or the client with different meanings. + +A relay may send `["AUTH", , ]` when it needs authentication (examples: accessing kind 4 events, whitelist only, requiring proof of authorship for `EVENT`). +The human readable reason SHOULD be prefixed with a string in the format `: `. A list of short descriptions is listed below: +- `restricted`: This relay is restricted and requires the pubkey of the client to check if it can access the relay. (requires a whitelist, payment, etc) +- `publish`: The relay requests that the client identify who is sending an `EVENT` command. + This can be used for where only the signer of an event can publish it, or a pay-as-you-go relay allowing for you to publish others' events +- `private`: The client has attempted to access a restricted set of events (example: kind 4 DMs) and should authenticate with the relay to receive them. +- `other`: Any reason not defined here. + +`data object` MUST be a JSON object. It currently has one defined field, but may be extended by amendments to this NIP or other NIPs: +- `subscription_id`: The subscription ID that triggered the `AUTH` request. + +A client may send one of the following to the relay: +- `["AUTH", ]` to indicate it has accepted the request. This may also be sent without an authentication request. +- `["AUTH", null]` to indicate it has rejected the request. + +A relay SHOULD send the [`OK`](https://github.com/nostr-protocol/nips/blob/master/20.md) command after they receive a +non-rejecting authentication response, and use one of the following `message` prefixes if the event sent cannot be verified: +- `too-old:`: The event signed has a too old `created_at` date. +- `invalid-url:`: The URL in `content` is not matching. +- `already-used:`: This event was already used to authenticate to this relay. +- `bad-signature:`: The event has a bad signature. + +Please note that the `OK` message should only be sent as a response to other commands that the client sends instead of the `AUTH` command if the issue is not related to the authentication event being incorrectly signed (example: not on whitelist). + +Relays SHOULD send [`EOSE`](https://github.com/nostr-protocol/nips/blob/master/15.md) when an authentication request is triggered by a `REQ` command, and not send stored events after the `EOSE` when authentication is completed. +Relays SHOULD send `OK` as a response when a command triggers authentication with the reason starting with `auth:`. + +Clients SHOULD retry the action (resending event, resubscribing) after they authenticate if they receive an `AUTH` request. + +## Signed event verification +Relays when processing `AUTH` responses SHOULD verify the following before accepting the response: +- that the `kind` is `22223` +- that the event was recently signed (~10 minutes, by `created_at`) +- that the `content` field matches the relay URL