Signers
Signing via an nsecBunker requires two NDK Signers:
- a local signer
- a remote signer
Local Signer
A local signer is an application key that is NOT tied to the user. The user might as well never see this key.
This local key is the one that will be signing requests for nsecBunker to sign.
A local key doesn't publish events for normal consumption, but rather, it solely exists to communicate with an nsecBunker.
Generating a local signer
The following code will generate a new private key.
const localSigner = NDKPrivateKeySigner.generate()
When creating a real integration, you would want to store this private key. Your users will be granting permissions to this key, so you'll want to reuse this key across your user sessions when it makes sense to do so.
Loading a local signer with a saved private key
If you have already saved a local key you would load it instead, obviously.
const privateKey = localStorage.getItem('localSignerPrivateKey');
const localSigner = new NDKPrivateKeySigner(privateKey);
Loading the remote signer
The remote signer is a NDKNip46Signer
, which communicates with the nsecBunker (over nostr relays, obviously) to exchange event signatures and other things.
Target pubkey
The next and final thing we'll need is the remote pubkey we desired to sign as. We'll ask the user in some way what's the pubkey they want to sign as.
const desiredPubkeyOrToken = prompt(`Enter your npub or token`);
Token
What's that token thing? Is it a shitcoin? Nah.
A token is a one-time-use secret that users can configure in their nsecBunker to confer a set of permissions to an application. For example, a user might give your application permission to only sign kind:1 events, but not kind:0 events.
It looks like: npub#secret
.
Communicating with the nsecBunker
Since the remote signer is accessed via Nostr, we use an NDK
instance to communicate with it.
Now, you can either use the same NDK instance you use for all other nostr communications but, for now, I choose to create a dedicated NDK instance that will just be used to communicate with the nsecBunker.
const bunkerNDK = new NDK({
explicitRelayUrls: [
'wss://relay.nsecbunker.com',
'wss://nostr.vulpem.com',
]
})
bunkerNDK.connect(2000);
const remoteSigner = new NDKNip46Signer(bunkerNDK, desiredPubkeyOrToken, localSigner);
Now that we have both our signers, let's create the generic NDK instance we're going to be using to communicate for normal nostr usage.
const typicalNDK = new NDK({
explicitRelayUrls: [
'wss://relay.damus.io',
'wss://nos.lol',
// ...
],
signer: remoteSigner
})
We're going to pass in to this NDK instance the remote signer.
Connecting
This step is kinda optional, but I think it's a good idea, as it will ensure that the connection has been established/authorized.
It'll send a NIP-46 connect
command to the nsecBunker; the nsecBunker will ok
if/when the local private key is authorized to connect.
await remoteSigner.blockUntilRead();