NIP 67: Nostr Wallet Auth
There are a lot of technical and UX problems with NWC connection strings, this defines a better way to establish a wallet connection.
Naming and wording can definitely be improved, putting up for review now as I work on an implementation.
I am confused about the name Auth. The current text doesn't seem to define Authentication mechanisms for clients to follow. Is it coming at a later date or is this just about declaring and identifying compatibility of available commands?
@vitorpamplona auth is the best name someone has told me. Happy for suggestions
I think you're not understanding what the purpose of this is. This is for when you want to connect your wallet to a service (something like ZapplePay). Currently, pasting nwc strings causes too much friction and has a lot of downsides that I mention in the intro of the NIP.
It would be better if the user can just scan a QR from their wallet to connect it to the service instead of having proprietary buttons for every wallet or requiring the user to create the connection themself and paste the string into the service.
What we want is a user to know exactly what they are authorizing in their wallet, similar to what you get when you authorize a service with a github account, you get a list of permissions you are giving up in the connection.
I think you're not understanding what the purpose of this is.
Agree. This whole thing is very confusing. I suggest reviewing the terms and mentions to a "Wallet", the "Nostr Client", "NWC Service" and any other "Service", like ZapplePay (I suppose you are not calling ZapplePay a Nostr client); and clearly identify who does what and when in this protocol. A full example of a complete setup between all these elements and where each string should be used could be very helpful.
This is for when you want to connect your wallet to a service (something like ZapplePay)
Ohhhhh... that should be the first line of this NIP, then. It's really not clear that this is between the Lightning Wallet and the Wallet Connect service.
Currently, pasting nwc strings causes too much friction and has a lot of downsides that I mention in the intro of the NIP.
See, now I am confused again. Why you are using NWC strings to connect to the wallet? Those are for the Nostr client only.
What we want is a user to know exactly what they are authorizing in their wallet
Is a NIP really the best place to document this if this is between the Wallet and the Service?
I removed all mentions of nostr clients, I think this is what you're getting hung up on. Nostr is not limited to social media use cases and I think that is what you're getting hung up on.
See, now I am confused again. Why you are using NWC strings to connect to the wallet? Those are for the Nostr client only.
That is the problem today, is you have to generate the nwc from the wallet and take it to the app you want to connect to, it makes it very confusing to users (people often have a very hard time connecting to Amethyst from our experience)
Is a NIP really the best place to document this if this is between the Wallet and the Service?
Yes, this should be the standard way to setup a NWC
Why not add this as an optional pre-step to NIP-47?
It's about your terms, not the social media clients. You are mixing them together or using them interchangeably, which makes it confusing. Probably because on Mutiny they are together, but those are all separate systems for everyone else.
That is the problem today, is you have to generate the nwc from the wallet
See, you did it again. It's not from the Wallet (the lightning wallet doesn't even know nostr exists), it's from the NWC service.
If this PR is between the nostr client and the NWC service, then I go back to my original impression. There is no auth happening here. You are just making a QR to declare which commands are available in the NWC service. The client must read the QR, and somehow send the request for the commands it will use. Then the NWC displays on screen the permission request and, if approved, it creates the access point, and returns the usual uri to be pasted in the app.
Did I get this right?
Why not add this as an optional pre-step to NIP-47?
I guess this could be done. It seems I need to get alby to implement anything to get merged into the NIP and they've been really slow.
This flow isn't strictly required for NWC so I think it makes sense as a separate NIP.
It's not from the Wallet (the lightning wallet doesn't even know nostr exists), it's from the NWC service.
If the wallet doesn't know nostr exists then payments can't happen. Frankly, it doesn't seem like you understand how NWC works. You keep saying "nostr client" but this term is way to broad, everyone is a nostr client, so this term means nothing.
I think I make it pretty clear, there is a wallet and a service. The wallet is someone like alby, mutiny, nostr-wallet-connect-lnd, something that receives nwc requests and makes payments. The service is someone like Amethyst, Damus, Zapple Pay, who makes requests to the wallet.
Well, you are definitely the first one to ever call Amethyst a "service". And now I am more confused than ever.
I don't know who does what in this PR.
Renamed service to app and added a terms section.
Much better text! Thanks!
So, the app generates the QR and the Wallet or NWC service now needs a QR Reader.
The issue that I see now is that the app doesn't know beforehand which relay the wallet is using. So generating a QR with the relay string in it is not possible. Or is this a separate relay that should not be used to send Payment Requests in NIP-47?
What happens after the user grants permissions in the Wallet? Does it generate the usual NIP-47 QR? If so, then the QR will contain the private relay the NWC is using and the app can connect to it. That can work.
The issue that I see now is that the app doesn't know beforehand which relay the wallet is using. So generating a QR with the relay string in it is not possible. Or is this a separate relay that should not be used to send Payment Requests in NIP-47?
The app picks the relay, so the wallet can just use that relay. This is the relay used throughout.
What happens after the user grants permissions in the Wallet? Does it generate the usual NIP-47 QR? If so, then the QR will contain the private relay the NWC is using and the app can connect to it. That can work.
No, the whole point is to get around the NIP 47 connection string. After the wallet grants permission both sides will have the information they need to do full NIP 47 communication
After the wallet grants permission both sides will have the information they need to do full NIP 47 communication
How do I get the secret if the NWC generated one for me? What if the NWC only operates on their private relay? Is there a way to send that info back to the app.
How do I get the secret if the NWC generated one for me?
both sides generate their own keys
What if the NWC only operates on their private relay? Is there a way to send that info back to the app.
I guess we could add a relay to the confirmation event
From the URI, The wallet doesn't know which PubKey is requesting access. So, how can It know which key is the app using?
It is the first part of the URI??
The app generates this connection URI with protocol
nostr+walletauth:and base path it's hex-encodedpubkey
Ohh, I see. I thought that would be the users main key so that the permission screen can bring the users picture to confirm.
I would add that the key is from the secret to the text. So the wallet app can't see which nostr user is requesting access.
So the wallet app can't see which nostr user is requesting access.
I guess we could, would need a signature as well then otherwise you could put any npub in there, which is going to make the QR really big. The user should know where this is coming from, they scanned it from their wallet.
I guess we could, would need a signature as well then otherwise you could put any npub in there, which is going to make the QR really big. The user should know where this is coming from, they scanned it from their wallet.
It builds confidence to let the user know they are doing the right thing and no one got in between. In the same way we verify the address and amount in Bitcoin invoices even though we created it ourselves, the requester's info should also be verifiable by the user in the permission's screen maximize UI goodness.
This can also be used as a QR.
The problem is this means you have to start in the wallet. So you have to go back and forth many times which is terrible UX and needless.
I do not see the issue with users not understanding their connection URI's confidentiality, since it is the wallet's responsibility to inform that this is sensitive information that can get their funds stolen.
You can inform users all you want but many are stupid, would be better to not have them handle these at all.
There's an info event...
The info event is created after the connection is made. You could have the app check if the user created a correct NWC but that just leads to tedious back and forth.
How?
For things like Zapple Pay, I have to use the keys the user generates for me and store them in a database. With this I can use an extended private key and just store a derivation path per user so I don't need to keep key material in a database.
The info event is created after the connection is made. You could have the app check if the user created a correct NWC but that just leads to tedious back and forth.
It should be available at the moment then. But I get your point, that doesn't tell you anything about what privileges you have.
For things like Zapple Pay, I have to use the keys the user generates for me and store them in a database. With this I can use an extended private key and just store a derivation path per user so I don't need to keep key material in a database.
A database is in most production scenarios not any less secure than the storage for your key material (the machine your server runs on). It is way more likely an app flaw would compromise secrets than a database one in my opinion.
Also, :// should not be used instead of : as it indicates an authority and also has a path.
A database is in most production scenarios not any less secure than the storage for your key material (the machine your server runs on). It is way more likely an app flaw would compromise secrets than a database one in my opinion.
For now, yeah. But eventually people could be using things like HSMs
Oh and I also think this should be an optional pre-step to nip-47 like fiatjaf said. Regarding that you are waiting for us to implement something before something can be merged I don't get it. You and us are both wallet developers. So if you develop it, and you find a nostr app to develop the other side (eg. your own zapplepay), you have a working setup that doesn't require us to develop anything, right?
I think that this NIP should support one wallet pubkey servicing multiple client pubkeys. That was one motivation for the UNAUTHORIZED error code.
Changed to parameterized replaceable events so keys can be reused by a wallet.
However, I do kind of agree with the https://github.com/nostr-protocol/nips/pull/792#issuecomment-1742012546 raised in the other PR in that this can be a potential footgun.
This doesn't really make sense and was refuted in the further comments.
I feel that the traditional apps that already have access to the users private key (Damus/Amethyst) are still better of using a wallet-generated secret and receiving it back through a deeplink. These apps themselves linking to the wallets with a standardized link scheme is fine obviously.
While they only use it for one-tap zaps I can see the case, but as apps use more commands they will run into this negotiation problem and nwc uris will not hold up.
This could go as an optional pre-step to nip 47, but this nip is already about the same length. Imo since it is optional it makes more sense as a separate nip.
First - thank you @benthecarman. We love the addition of NWA as it makes it much easier to onboard users for recurring payment requests.
Should the pubkey we use on the app/client side when generating the URI/QR-code be unique per user/connection or should that just be a recognizable pubkey of ours that we use for every connection? I am thinking the latter makes the most sense for services like ours but curious if there is a reason to use unique pubkeys instead.
The reason to use unique keys would be for privacy, so someone couldn't just count how many events are tied to your key and get a user count. However it does make the implementation much simpler and more efficient if you use a static key