nips/46.md
Pablo Fernandez db93c0d05f
Update 46.md
Co-authored-by: Alex Gleason <alex@alexgleason.me>
2024-02-06 23:27:22 +00:00

4.7 KiB

NIP-46

Nostr Connect

draft optional

This NIP describes a method for 2-way communication between a remote signer and a normal Nostr client. The remote signer could be, for example, a hardware device dedicated to signing Nostr events, while the client is a normal Nostr client.

Signer Discovery

The client always starts by generating a random key which is used to communicate with the signer, then it one of the methods below is used to allow the client to know what is the signer public key for the session and which relays to use.

Started by the signer (nsecBunker)

The remote signer generates a connection token in the form

<npub1...>#<optional-secret>?relay=wss://...&relay=wss://...

The user copies that token and pastes it in the client UI somehow. Then the client can send events of kind 24133 to the specified relays and wait for responses from the remote signer.

Started by the client

The client generates a QR code in the following form (URL-encoded):

nostrconnect://<client-key-hex>?relay=wss://...&metadata={"name":"...", "url": "...", "description": "..."}

The signer scans the QR code and sends a connect message to the client in the specified relays.

Using a NIP-05

Clients can choose to connect with a backend with just a NIP-05 for the target user. The user enters a NIP-05 Nostr Address, which the client uses to resolve to a pubkey. NIP-05's nostr.json SHOULD include a nip46 root element of the pubkey and the relays that should be used to communicate with the remote signer for this pubkey.

Event payloads

Event payloads are NIP-04-encrypted JSON blobs that look like JSONRPC messages (their format is specified inside the .content of the event formats nelow).

Events sent by the client to the remote signer have the following format:

{
  "pubkey": "<client-key-hex>"
  "kind": 24133,
  "tags": [
    ["p", "<signer-key-hex>"]
  ],
  "content": "nip04_encrypted_json({id: <random-string>, method: <see-below>, params: [array_of_strings]})",
  ...
}

And the events the remote signer sends to the client have the following format:

  "pubkey": "<signer-key-hex>"
  "kind": 24133,
  "tags": [
    ["p", "<client-key-hex>"]
  ],
  "content": "nip04_encrypted_json({id: <request-id>, result: <string>, error: <reason-string>})",
  ...

The signer key will always be the key of the user who controls the signer device.

Auth URL response

A signer can reply with a result: "auth_url", error: "<url>". This response can provide an easier way for the user to authorize this client to perform an action. Clients can redirect/popup this URL so the user can take an action directly on the signer backend.

When redirecting, the client can choose to add a callbackUrl query string parameter to tell the signer where to send the user after an action has been performed.

Example flow:

  • User goes to a new client
  • Logins by typing their nip-05 "hello@example.com"
  • Client gets example.com/.well-known/nostr.json?name=hello
  • Client finds nip46 relays wss://relay.example.com and pubkey <123>
  • Client sends connect with remote pubkey <123>
  • Signer sends back result: 'auth_url", error: "https://auth.example.com/some-long-secret-path"
  • Client opens popup https://auth.examople.com/ABCD
  • User authorizes the client to sign on behalf of pubkey <123>
  • Client's connect RPC call is acked.

Methods

  • connect
    • params: [pubkey, secret]
    • result: "ack"
  • get_public_key
    • params: []
    • result: pubkey-hex
  • sign_event
    • params: [event]
    • result: json_string(event_with_pubkey_id_and_signature)
  • get_relays
    • params: []
    • result: json_string({[url: string]: {read: boolean, write: boolean}})
  • nip04_encrypt
    • params: [third-party-pubkey, plaintext]
    • result: nip04-ciphertext
  • nip04_decrypt
    • params: [third-party-pubkey, nip04-ciphertext]
    • result: plaintext
  • nip44_get_key
    • params: [third-party-pubkey]
    • result: nip44-conversation-key
  • nip44_encrypt
    • params: [third-party-pubkey, plaintext]
    • result: nip44-ciphertext
  • nip44_decrypt
    • params: [third-party-pubkey, nip44-ciphertext]
    • result: plaintext
  • ping
    • params: []
    • result: "pong"
  • create_account
    • params: `["username", "domain", "email"]
    • result: generated-pubkey

Account creation

This method creates a new key inside the backend. All params are optional. Username+domain can be specified so a NIP-05 record is created to point to this key. Email is an optional parameter that allows the backend to check if this user has already created an account in this backend. The create_account method should be sent to the pubkey of the bunker, which should match the root NIP-05 entry (_@domain).