Skip to content

Signers Examples

Real-world usage of signers, key storage, and custom EventSigner implementations from the Snort app.

NIP-46 connect flow with ephemeral PrivateKeySigner

Generate an ephemeral client key for the nostrconnect:// flow:

typescript
// sign-in.tsx
const clientSigner = PrivateKeySigner.random()
const clientPubkey = await clientSigner.getPubKey()
const connectUrl = `nostrconnect://${clientPubkey}?relay=...&secret=${secret}&perms=${NIP46_PERMS}`
const nip46 = new Nip46Signer(connectUrl, clientSigner)
await nip46.init()

// Store the NIP-46 session key with NotEncrypted (no PIN protection)
LoginStore.loginWithPubkey(
  loginPubkey,
  LoginSessionType.Nip46,
  undefined,
  nip46.relays,
  new NotEncrypted(unwrap(nip46.privateKey)),
)

Custom EventSigner implementation (Nip7OsSigner)

The EventSigner interface can be implemented for custom signing backends:

typescript
// Nip7OsSigner.ts
export class Nip7OsSigner implements EventSigner {
  #interface: Nip7os

  get supports(): string[] { return ["nip04"] }
  getPubKey(): string | Promise<string> { return this.#interface.getPublicKey() }
  nip4Encrypt(content: string, key: string): Promise<string> {
    return Promise.resolve(this.#interface.nip04_encrypt(content, key))
  }
  nip4Decrypt(content: string, otherKey: string): Promise<string> {
    return Promise.resolve(this.#interface.nip04_decrypt(content, otherKey))
  }
  sign(ev: NostrEvent): Promise<NostrEvent> {
    const ret = this.#interface.signEvent(JSON.stringify(ev))
    return Promise.resolve(JSON.parse(ret) as NostrEvent)
  }
}

KeyStorage for encrypted key persistence

typescript
// MultiAccountStore.ts
// Deserialize from stored payload
v.privateKeyData = KeyStorage.fromPayload(v.privateKeyData as object)

// Check instance type for serialization
if (v.privateKeyData instanceof KeyStorage) {
  toSave.push({ ...v, privateKeyData: v.privateKeyData.toPayload() })
}