diff --git a/46.md b/46.md new file mode 100644 index 00000000..a9f37c1b --- /dev/null +++ b/46.md @@ -0,0 +1,162 @@ +NIP-46 +====== + +Nostr Connect +------------------------ + +`draft` `optional` `author:tiero` `author:giowe` `author:vforvalerio87` + +## Rationale + +Private keys should be exposed to as few systems - apps, operating systems, devices - as possible as each system adds to the attack surface. + +Entering private keys can also be annoying and requires exposing them to even more systems such as the operating system's clipboard that might be monitored by malicious apps. + + +## Terms + +* **App**: Nostr app on any platform that *requires* to act on behalf of a nostr account. +* **Signer**: Nostr app that holds the private key of a nostr account and *can sign* on its behalf. + + +## `TL;DR` + + +**App** and **Signer** sends ephemeral encrypted messages to each other using kind `24133`, using a relay of choice. + +App prompts the Signer to do things such as fetching the public key or signing events. + +The `content` field must be an encrypted JSONRPC-ish **request** or **response**. + +## Signer Protocol + +### Messages + +#### Request + +```json +{ + "id": , + "method": , + "params": [, ] +} +``` + +#### Response + +```json +{ + "id": , + "result": , + "error": +} +``` + +### Methods + + +#### Mandatory + +These are mandatory methods the remote signer app MUST implement: + +- **describe** + - params [] + - result `{"get_public_key": { params: [], result: anything }}` +- **get_public_key** + - params [] + - result `pubkey` +- **sign_event** + - params [`event`] + - result `signature` + +#### optional + + +- **connect** + - params [`pubkey`] +- **disconnect** + - params [] +- **delegate** + - params [`pubkey`, `conditions query string`] + - result `nip26 delegation token` +- **get_relays** + - params [] + - result `{ [url: string]: {read: boolean, write: boolean} }` +- **nip04_encrypt** + - params [`pubkey`, `plaintext`] + - result `nip4 ciphertext` +- **nip04_decrypt** + - params [`pubkey`, `nip4 ciphertext`] + - result [`plaintext`] + + +NOTICE: `pubkey` and `signature` are hex-encoded strings. + + +### Nostr Connect URI + +**Signer** discovers **App** by scanning a QR code, clicking on a deep link or copy-pasting an URI. + +The **App** generates a special URI with prefix `nostrconnect://` and base path the hex-encoded `pubkey` with the following querystring parameters **URL encoded** + +- `relay` URL of the relay of choice where the **App** is connected and the **Signer** must send and listen for messages. +- `metadata` metadata JSON of the **App** + - `name` human-readable name of the **App** + - `url` (optional) URL of the website requesting the connection + - `description` (optional) description of the **App** + - `icons` (optional) array of URLs for icons of the **App**. + +#### JavaScript + +```js +const uri = `nostrconnect://?relay=${encodeURIComponent("wss://relay.damus.io")}&metadata=${encodeURIComponent(JSON.stringify({"name": "Example"}))}` +``` + +#### Example +```sh +nostrconnect://b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io&metadata=%7B%22name%22%3A%22Example%22%7D +``` + + + +## Flows + +The `content` field contains encrypted message as specified by [NIP04](https://github.com/nostr-protocol/nips/blob/master/04.md). The `kind` chosen is `24133`. + +### Connect + +1. User clicks on **"Connect"** button on a website or scan it with a QR code +2. It will show an URI to open a "nostr connect" enabled **Signer** +3. In the URI there is a pubkey of the **App** ie. `nostrconnect://&relay=&metadata=` +4. The **Signer** will send a message to ACK the `connect` request, along with his public key + +### Disconnect (from App) + +1. User clicks on **"Disconnect"** button on the **App** +2. The **App** will send a message to the **Signer** with a `disconnect` request +3. The **Signer** will send a message to ACK the `disconnect` request + +### Disconnect (from Signer) + +1. User clicks on **"Disconnect"** button on the **Signer** +2. The **Signer** will send a message to the **App** with a `disconnect` request + + +### Get Public Key + +1. The **App** will send a message to the **Signer** with a `get_public_key` request +3. The **Signer** will send back a message with the public key as a response to the `get_public_key` request + +### Sign Event + +1. The **App** will send a message to the **Signer** with a `sign_event` request along with the **event** to be signed +2. The **Signer** will show a popup to the user to inspect the event and sign it +3. The **Signer** will send back a message with the schnorr `signature` of the event as a response to the `sign_event` request + +### Delegate + +1. The **App** will send a message with metadata to the **Signer** with a `delegate` request along with the **conditions** query string and the **pubkey** of the **App** to be delegated. +2. The **Signer** will show a popup to the user to delegate the **App** to sign on his behalf +3. The **Signer** will send back a message with the signed [NIP-26 delegation token](https://github.com/nostr-protocol/nips/blob/master/26.md) or reject it + + diff --git a/README.md b/README.md index e45c531b..25e5861a 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh - [NIP-36: Sensitive Content](36.md) - [NIP-40: Expiration Timestamp](40.md) - [NIP-42: Authentication of clients to relays](42.md) +- [NIP-46: Nostr Connect](46.md) - [NIP-50: Keywords filter](50.md) - [NIP-56: Reporting](56.md) - [NIP-57: Lightning Zaps](57.md) @@ -56,6 +57,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh | 9735 | Zap | [57](57.md) | | 10002 | Relay List Metadata | [65](65.md) | | 22242 | Client Authentication | [42](42.md) | +| 24133 | Nostr Connect | [46](46.md) | | 30023 | Long-form Content | [23](23.md) | | 1000-9999 | Regular Events | [16](16.md) | | 10000-19999 | Replaceable Events | [16](16.md) |