upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/46.md
diff options
context:
space:
mode:
authorFrancisco Calderón <fjcalderon@gmail.com>2024-11-04 15:39:21 -0300
committerGitHub <noreply@github.com>2024-11-04 15:39:21 -0300
commit03f3bc39678262ecbd5d870c9da44723023557ff (patch)
treee75ecf32d3bc906a8b26314488a1ae90996169c1 /46.md
parentf72a2f69ed93cf442e83bf9e7e16f6c06da40384 (diff)
parent6bcd89c097e97e65dbc95e7c6b7b8348e8dd6b5c (diff)
Merge branch 'master' into p2p-nip
Diffstat (limited to '46.md')
-rw-r--r--46.md97
1 files changed, 47 insertions, 50 deletions
diff --git a/46.md b/46.md
index 1528116..c356a9c 100644
--- a/46.md
+++ b/46.md
@@ -1,4 +1,12 @@
1# NIP-46 - Nostr Remote Signing 1NIP-46
2======
3
4Nostr Remote Signing
5--------------------
6
7## Changes
8
9`remote-signer-key` is introduced, passed in bunker url, clients must differentiate between `remote-signer-pubkey` and `user-pubkey`, must call `get_public_key` after connect.
2 10
3## Rationale 11## Rationale
4 12
@@ -8,51 +16,53 @@ This NIP describes a method for 2-way communication between a remote signer and
8 16
9## Terminology 17## Terminology
10 18
11- **Local keypair**: A local public and private key-pair used to encrypt content and communicate with the remote signer. Usually created by the client application. 19- **user**: A person that is trying to use Nostr.
12- **Remote user pubkey**: The public key that the user wants to sign as. The remote signer has control of the private key that matches this public key. 20- **client**: A user-facing application that _user_ is looking at and clicking buttons in. This application will send requests to _remote-signer_.
13- **Remote signer pubkey**: This is the public key of the remote signer itself. This is needed in both `create_account` command because you don't yet have a remote user pubkey. 21- **remote-signer**: A daemon or server running somewhere that will answer requests from _client_, also known as "bunker".
22- **client-keypair/pubkey**: The keys generated by _client_. Used to encrypt content and communicate with _remote-signer_.
23- **remote-signer-keypair/pubkey**: The keys used by _remote-signer_ to encrypt content and communicate with _client_. This keypair MAY be same as _user-keypair_, but not necessarily.
24- **user-keypair/pubkey**: The actual keys representing _user_ (that will be used to sign events in response to `sign_event` requests, for example). The _remote-signer_ generally has control over these keys.
14 25
15All pubkeys specified in this NIP are in hex format. 26All pubkeys specified in this NIP are in hex format.
16 27
17## Initiating a connection 28## Initiating a connection
18 29
19To initiate a connection between a client and a remote signer there are a few different options. 30There are two ways to initiate a connection:
20 31
21### Direct connection initiated by remote signer 32### Direct connection initiated by _remote-signer_
22 33
23This is most common in a situation where you have your own nsecbunker or other type of remote signer and want to connect through a client that supports remote signing. 34_remote-signer_ provides connection token in the form:
24
25The remote signer would provide a connection token in the form:
26 35
27``` 36```
28bunker://<remote-user-pubkey>?relay=<wss://relay-to-connect-on>&relay=<wss://another-relay-to-connect-on>&secret=<optional-secret-value> 37bunker://<remote-signer-pubkey>?relay=<wss://relay-to-connect-on>&relay=<wss://another-relay-to-connect-on>&secret=<optional-secret-value>
29``` 38```
30 39
31This token is pasted into the client by the user and the client then uses the details to connect to the remote signer via the specified relay(s). 40_user_ pastes this token on _client_, which then uses the details to connect to _remote-signer_ via the specified relays. Optional secret can be used for single successfully established connection only, _remote-signer_ SHOULD ignore new attempts to establish connection with old optional secret.
32 41
33### Direct connection initiated by the client 42### Direct connection initiated by the client
34 43
35In this case, basically the opposite direction of the first case, the client provides a connection token (or encodes the token in a QR code) and the signer initiates a connection to the client via the specified relay(s). 44In this case, basically the opposite direction of the first case, _client_ provides a connection token (or encodes the token in a QR code) and _remote-signer_ initiates a connection via the specified relays.
36 45
37``` 46```
38nostrconnect://<local-keypair-pubkey>?relay=<wss://relay-to-connect-on>&metadata=<json metadata in the form: {"name":"...", "url": "...", "description": "..."}> 47nostrconnect://<client-pubkey>?relay=<wss://relay-to-connect-on>&metadata=<json metadata in the form: {"name":"...", "url": "...", "description": "..."}>
39``` 48```
40 49
41## The flow 50## The flow
42 51
431. Client creates a local keypair. This keypair doesn't need to be communicated to the user since it's largely disposable (i.e. the user doesn't need to see this pubkey). Clients might choose to store it locally and they should delete it when the user logs out. 521. _client_ generates `client-keypair`. This keypair doesn't need to be communicated to _user_ since it's largely disposable. _client_ might choose to store it locally and they should delete it on logout;
442. Client gets the remote user pubkey (either via a `bunker://` connection string or a NIP-05 login-flow; shown below) 532. _client_ gets `remote-signer-pubkey` (either via a `bunker://` connection string or a NIP-05 login-flow; shown below);
453. Clients use the local keypair to send requests to the remote signer by `p`-tagging and encrypting to the remote user pubkey. 543. _client_ use `client-keypair` to send requests to _remote-signer_ by `p`-tagging and encrypting to `remote-signer-pubkey`;
464. The remote signer responds to the client by `p`-tagging and encrypting to the local keypair pubkey. 554. _remote-signer_ responds to _client_ by `p`-tagging and encrypting to the `client-pubkey`.
47 56
48### Example flow for signing an event 57### Example flow for signing an event
49 58
50- Remote user pubkey (e.g. signing as) `fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52` 59- `remote-signer-pubkey` is `fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52`
51- Local pubkey is `eff37350d839ce3707332348af4549a96051bd695d3223af4aabce4993531d86` 60- `user-pubkey` is also `fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52`
61- `client-pubkey` is `eff37350d839ce3707332348af4549a96051bd695d3223af4aabce4993531d86`
52 62
53#### Signature request 63#### Signature request
54 64
55```json 65```js
56{ 66{
57 "kind": 24133, 67 "kind": 24133,
58 "pubkey": "eff37350d839ce3707332348af4549a96051bd695d3223af4aabce4993531d86", 68 "pubkey": "eff37350d839ce3707332348af4549a96051bd695d3223af4aabce4993531d86",
@@ -66,13 +76,13 @@ nostrconnect://<local-keypair-pubkey>?relay=<wss://relay-to-connect-on>&metadata
66 created_at: 1714078911 76 created_at: 1714078911
67 }>)] 77 }>)]
68 }), 78 }),
69 "tags": [["p", "fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52"]], // p-tags the remote user pubkey 79 "tags": [["p", "fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52"]], // p-tags the remote-signer-pubkey
70} 80}
71``` 81```
72 82
73#### Response event 83#### Response event
74 84
75```json 85```js
76{ 86{
77 "kind": 24133, 87 "kind": 24133,
78 "pubkey": "fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52", 88 "pubkey": "fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52",
@@ -80,7 +90,7 @@ nostrconnect://<local-keypair-pubkey>?relay=<wss://relay-to-connect-on>&metadata
80 "id": <random_string>, 90 "id": <random_string>,
81 "result": json_stringified(<signed-event>) 91 "result": json_stringified(<signed-event>)
82 }), 92 }),
83 "tags": [["p", "eff37350d839ce3707332348af4549a96051bd695d3223af4aabce4993531d86"]], // p-tags the local keypair pubkey 93 "tags": [["p", "eff37350d839ce3707332348af4549a96051bd695d3223af4aabce4993531d86"]], // p-tags the client-pubkey
84} 94}
85``` 95```
86 96
@@ -90,20 +100,18 @@ nostrconnect://<local-keypair-pubkey>?relay=<wss://relay-to-connect-on>&metadata
90 100
91## Request Events `kind: 24133` 101## Request Events `kind: 24133`
92 102
93```json 103```js
94{ 104{
95 "id": <id>,
96 "kind": 24133, 105 "kind": 24133,
97 "pubkey": <local_keypair_pubkey>, 106 "pubkey": <local_keypair_pubkey>,
98 "content": <nip04(<request>)>, 107 "content": <nip04(<request>)>,
99 "tags": [["p", <remote_user_pubkey>]], // NB: in the `create_account` event, the remote signer pubkey should be `p` tagged. 108 "tags": [["p", <remote-signer-pubkey>]],
100 "created_at": <unix timestamp in seconds>
101} 109}
102``` 110```
103 111
104The `content` field is a JSON-RPC-like message that is [NIP-04](https://github.com/nostr-protocol/nips/blob/master/04.md) encrypted and has the following structure: 112The `content` field is a JSON-RPC-like message that is [NIP-04](04.md) encrypted and has the following structure:
105 113
106```json 114```jsonc
107{ 115{
108 "id": <random_string>, 116 "id": <random_string>,
109 "method": <method_name>, 117 "method": <method_name>,
@@ -121,15 +129,16 @@ Each of the following are methods that the client sends to the remote signer.
121 129
122| Command | Params | Result | 130| Command | Params | Result |
123| ------------------------ | ------------------------------------------------- | ---------------------------------------------------------------------- | 131| ------------------------ | ------------------------------------------------- | ---------------------------------------------------------------------- |
124| `connect` | `[<remote_user_pubkey>, <optional_secret>, <optional_requested_permissions>]` | "ack" | 132| `connect` | `[<user_pubkey>, <optional_secret>, <optional_requested_permissions>]` | "ack" |
125| `sign_event` | `[<{kind, content, tags, created_at}>]` | `json_stringified(<signed_event>)` | 133| `sign_event` | `[<{kind, content, tags, created_at}>]` | `json_stringified(<signed_event>)` |
126| `ping` | `[]` | "pong" | 134| `ping` | `[]` | "pong" |
127| `get_relays` | `[]` | `json_stringified({<relay_url>: {read: <boolean>, write: <boolean>}})` | 135| `get_relays` | `[]` | `json_stringified({<relay_url>: {read: <boolean>, write: <boolean>}})` |
128| `get_public_key` | `[]` | `<hex-pubkey>` | 136| `get_public_key` | `[]` | `<user-pubkey>` |
129| `nip04_encrypt` | `[<third_party_pubkey>, <plaintext_to_encrypt>]` | `<nip04_ciphertext>` | 137| `nip04_encrypt` | `[<third_party_pubkey>, <plaintext_to_encrypt>]` | `<nip04_ciphertext>` |
130| `nip04_decrypt` | `[<third_party_pubkey>, <nip04_ciphertext_to_decrypt>]` | `<plaintext>` | 138| `nip04_decrypt` | `[<third_party_pubkey>, <nip04_ciphertext_to_decrypt>]` | `<plaintext>` |
131| `nip44_encrypt` | `[<third_party_pubkey>, <plaintext_to_encrypt>]` | `<nip44_ciphertext>` | 139| `nip44_encrypt` | `[<third_party_pubkey>, <plaintext_to_encrypt>]` | `<nip44_ciphertext>` |
132| `nip44_decrypt` | `[<third_party_pubkey>, <nip44_ciphertext_to_decrypt>]` | `<plaintext>` | 140| `nip44_decrypt` | `[<third_party_pubkey>, <nip44_ciphertext_to_decrypt>]` | `<plaintext>` |
141| `create_account` | `[<username>, <domain>, <optional_email>, <optional_requested_permissions>]` | `<newly_created_user_pubkey>` |
133 142
134### Requested permissions 143### Requested permissions
135 144
@@ -141,14 +150,14 @@ The `connect` method may be provided with `optional_requested_permissions` for u
141{ 150{
142 "id": <id>, 151 "id": <id>,
143 "kind": 24133, 152 "kind": 24133,
144 "pubkey": <remote_signer_pubkey>, 153 "pubkey": <remote-signer-pubkey>,
145 "content": <nip04(<response>)>, 154 "content": <nip04(<response>)>,
146 "tags": [["p", <local_keypair_pubkey>]], 155 "tags": [["p", <client-pubkey>]],
147 "created_at": <unix timestamp in seconds> 156 "created_at": <unix timestamp in seconds>
148} 157}
149``` 158```
150 159
151The `content` field is a JSON-RPC-like message that is [NIP-04](https://github.com/nostr-protocol/nips/blob/master/04.md) encrypted and has the following structure: 160The `content` field is a JSON-RPC-like message that is [NIP-04](04.md) encrypted and has the following structure:
152 161
153```json 162```json
154{ 163{
@@ -180,18 +189,6 @@ Clients should display (in a popup or new tab) the URL from the `error` field an
180 189
181![signing-example-with-auth-challenge](https://i.nostr.build/W3aj.png) 190![signing-example-with-auth-challenge](https://i.nostr.build/W3aj.png)
182 191
183## Remote Signer Commands
184
185Remote signers might support additional commands when communicating directly with it. These commands follow the same flow as noted above, the only difference is that when the client sends a request event, the `p`-tag is the pubkey of the remote signer itself and the `content` payload is encrypted to the same remote signer pubkey.
186
187### Methods/Commands
188
189Each of the following are methods that the client sends to the remote signer.
190
191| Command | Params | Result |
192| ---------------- | ------------------------------------------ | ------------------------------------ |
193| `create_account` | `[<username>, <domain>, <optional_email>, <optional_requested_permissions>]` | `<newly_created_remote_user_pubkey>` |
194
195## Appendix 192## Appendix
196 193
197### NIP-05 Login Flow 194### NIP-05 Login Flow
@@ -200,7 +197,7 @@ Clients might choose to present a more familiar login flow, so users can type a
200 197
201When the user types a NIP-05 the client: 198When the user types a NIP-05 the client:
202 199
203- Queries the `/.well-known/nostr.json` file from the domain for the NIP-05 address provided to get the user's pubkey (this is the **remote user pubkey**) 200- Queries the `/.well-known/nostr.json` file from the domain for the NIP-05 address provided to get the user's pubkey (this is the `user-pubkey`)
204- In the same `/.well-known/nostr.json` file, queries for the `nip46` key to get the relays that the remote signer will be listening on. 201- In the same `/.well-known/nostr.json` file, queries for the `nip46` key to get the relays that the remote signer will be listening on.
205- Now the client has enough information to send commands to the remote signer on behalf of the user. 202- Now the client has enough information to send commands to the remote signer on behalf of the user.
206 203
@@ -212,9 +209,9 @@ In this last case, most often used to facilitate an OAuth-like signin flow, the
212 209
213First the client will query for `kind: 31990` events that have a `k` tag of `24133`. 210First the client will query for `kind: 31990` events that have a `k` tag of `24133`.
214 211
215These are generally shown to a user, and once the user selects which remote signer to use and provides the remote user pubkey they want to use (via npub, pubkey, or nip-05 value), the client can initiate a connection. Note that it's on the user to select the remote signer that is actually managing the remote key that they would like to use in this case. If the remote user pubkey is managed on another remote signer, the connection will fail. 212These are generally shown to a user, and once the user selects which remote signer to use and provides the `user-pubkey` they want to use (via npub, pubkey, or nip-05 value), the client can initiate a connection. Note that it's on the user to select the _remote-signer_ that is actually managing the `user-keypair` that they would like to use in this case. If the `user-pubkey` is managed on another _remote-signer_ the connection will fail.
216 213
217In addition, it's important that clients validate that the pubkey of the announced remote signer matches the pubkey of the `_` entry in the `/.well-known/nostr.json` file of the remote signer's announced domain. 214In addition, it's important that clients validate that the pubkey of the announced _remote-signer_ matches the pubkey of the `_` entry in the `/.well-known/nostr.json` file of the remote signer's announced domain.
218 215
219Clients that allow users to create new accounts should also consider validating the availability of a given username in the namespace of remote signer's domain by checking the `/.well-known/nostr.json` file for existing usernames. Clients can then show users feedback in the UI before sending a `create_account` event to the remote signer and receiving an error in return. Ideally, remote signers would also respond with understandable error messages if a client tries to create an account with an existing username. 216Clients that allow users to create new accounts should also consider validating the availability of a given username in the namespace of remote signer's domain by checking the `/.well-known/nostr.json` file for existing usernames. Clients can then show users feedback in the UI before sending a `create_account` event to the remote signer and receiving an error in return. Ideally, remote signers would also respond with understandable error messages if a client tries to create an account with an existing username.
220 217
@@ -224,4 +221,4 @@ Coming soon...
224 221
225## References 222## References
226 223
227- [NIP-04 - Encryption](https://github.com/nostr-protocol/nips/blob/master/04.md) 224- [NIP-04 - Encryption](04.md)