|
| 1 | +NIP-49 |
| 2 | +====== |
| 3 | + |
| 4 | +Nostr Wallet Auth |
| 5 | +-------------------- |
| 6 | + |
| 7 | +`draft` `optional` |
| 8 | + |
| 9 | +## Rationale |
| 10 | + |
| 11 | +[Nostr Wallet Connect](47.md) is a protocol for talking to a lightning wallet over nostr. It is great but hinges on |
| 12 | +having the user copy-paste a wallet connection URI into the app they wish to connect with. This can be a UX hurdle and |
| 13 | +often has the user handling sensitive information that they may not understand. |
| 14 | + |
| 15 | +As well, Nostr Wallet Connect has lots of different functions that a wallet may or may not support or an app may or may |
| 16 | +not need. This either runs into silent failures or requires the user to understand what functions their wallet supports |
| 17 | +and what functions the app needs. |
| 18 | + |
| 19 | +Finally, Nostr Wallet Connect requires the wallet to generate both key pairs and the app to use these. This limits the |
| 20 | +key management strategies that an app can use and often leads to suboptimal key management. |
| 21 | + |
| 22 | +This NIP proposes a new protocol that solves these problems by having the wallet and app generate the parameters for a |
| 23 | +NWC connection together. This URI is then used to connect the wallet and app. |
| 24 | + |
| 25 | +## Terms |
| 26 | + |
| 27 | +- **app**: Nostr app on any platform that wants to permissioned access to a user's lightning wallet. |
| 28 | +- **wallet**: A nostr wallet connect capable lightning wallet that the user wants to connect to the app. |
| 29 | + |
| 30 | +## Theory of Operation |
| 31 | + |
| 32 | +1. The user wants to connect their wallet to an app. The app provides a QR code or other means of connecting to the app. |
| 33 | + The QR code contains a `nostr+walletauth://` URI that contains the app's public key, the relay to communicate over, |
| 34 | + and a list of functions that the app requires. |
| 35 | +2. The user scans the QR code and their wallet prompts them the required functions and asks them to confirm that they |
| 36 | + want to connect to the app. |
| 37 | +3. On confirmation, the wallet generates a new key pair and sends the public key to the app in a confirmation event. |
| 38 | +4. With the combination of both keys, the wallet and the app both will generate the same connection URI. They can now |
| 39 | + use NWC to communicate. |
| 40 | + |
| 41 | +## Specification |
| 42 | + |
| 43 | +### URI Format |
| 44 | + |
| 45 | +The **app** generates this connection URI with protocol `nostr+walletauth:` and base path it's hex-encoded `pubkey` |
| 46 | +with the following query string parameters: |
| 47 | + |
| 48 | +- `relay` Required. URL of the relay where the **app** is connected and will be listening for events. May be |
| 49 | + more than one. |
| 50 | +- `secret` Required. A random identifier that the **wallet** will use to identify the connection. Without this the |
| 51 | + **app** cannot authenticate they are receiving a message from the user they want, it could be an attacker just sending |
| 52 | + kind `33194` events to the **app**. This should be unique for each connection. This is not a key and should be |
| 53 | + different for every new URI. |
| 54 | +- `required_commands` Required. A space-separated list of commands that the **app** requires from the **wallet**. The |
| 55 | + **wallet** MUST NOT connect if it does not support all of these permissions. |
| 56 | +- `optional_commands` Optional. A space-separated list of commands that the **wallet** can enable to add additional |
| 57 | + functionality. The **wallet** MAY ignore these. |
| 58 | +- `budget` Optional. A budget that the **wallet** will use to limit the amount of funds that the **app** can spend. |
| 59 | + The **app** MUST NOT spend more than this amount. The budget is a string of the form `max_amount/period`. |
| 60 | + The `period` is one of `daily`, `weekly`, `monthly`, `yearly`. The `max_amount` is a satoshi amount. |
| 61 | +- `identity` Optional. The hex-encoded `pubkey` of the *app* that the **wallet** is connecting to. This is used to |
| 62 | + for the wallet to display to the user. The **wallet** MAY ignore this. |
| 63 | + |
| 64 | +#### Example URI |
| 65 | + |
| 66 | +```sh |
| 67 | +nostr+walletauth://b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io&secret=b8a30fafa48d4795b6c0eec169a383de&required_commands=pay_invoice%20pay_keysend%20make_invoice%20lookup_invoice&optional_commands=list_transactions&budget=10000%2Fdaily |
| 68 | +``` |
| 69 | + |
| 70 | +### Event |
| 71 | + |
| 72 | +This NIP only uses one event kind `33194`. We use a parameterized replaceable event to allow for the wallet and app to |
| 73 | +renegotiate the connection if needed and to allow for the wallet being able to look up the connection details later. |
| 74 | + |
| 75 | +The event SHOULD contain one `d` tag, containing the public key of the app from the URI. |
| 76 | + |
| 77 | +The content of the event is encrypted with [NIP04](04.md), and should be a JSON structure as follows: |
| 78 | + |
| 79 | +```jsonc |
| 80 | +{ |
| 81 | + "secret": "b8a30fafa48d4795b6c0eec169a383de", // string, the secret from the URI |
| 82 | + "commands": [ // array of strings, commands that the wallet agrees to support |
| 83 | + "pay_invoice", |
| 84 | + "pay_keysend", |
| 85 | + "make_invoice", |
| 86 | + "lookup_invoice", |
| 87 | + "list_transactions", |
| 88 | + ], |
| 89 | + "relay": "wss://relay.damus.io", // Optional string, alternative relay that the wallet will use |
| 90 | + "lud16": "user@example.com", // Optional string, user's lightning address |
| 91 | +} |
| 92 | +``` |
| 93 | + |
| 94 | +After the user approves the connection, the wallet should send this event to the **app**. |
| 95 | + |
| 96 | +The *app* should validate that the `secret` matches the one in the URI and that the `commands` are a subset of the |
| 97 | +`required_commands` and `optional_commands` from the URI. If the `relay` is present, the *app* should use that instead |
| 98 | +of the one from the URI. |
| 99 | + |
| 100 | +The wallet and app should both then have all the necessary information be able to communicate using NWC. The app will |
| 101 | +have the wallet's key from the event's pubkey. The wallet will have the app's key from the URI. |
0 commit comments