Research report on the most frictionless "sign in with your Nostr signer" flow for node login (NIP-07 extension + NIP-46 QR scan with Amber, password always kept as fallback), and a plan for adding existing Nostr identities (nsec import / npub watch-only / browser extension) to the Nostr Identities screen. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4.3 KiB
Add an existing Nostr identity to the node — UX & implementation plan
Status: plan only (2026-07-16), no code. Companion research: docs/nostr-signer-login-research.md.
Where it lives
The Nostr Identities screen (Web5Identities.vue, backed by identity.list /
identity.create). Today every identity is seed-derived (identity_manager.rs
derives ed25519 + nostr keys from the BIP-39 master seed at an index). "Add existing"
introduces a second class of identity: one whose key material comes from outside the
seed.
Two import kinds (both needed, different guarantees)
- Full import (nsec) — the node holds the secret key. The identity behaves exactly like a seed-derived one (can sign in embedded apps, publish, encrypt). NOT covered by seed backup — flag it visibly and include it in the encrypted node backup.
- Linked signer (npub only) — the node stores just the public key; signing is delegated to the user's own signer (browser extension NIP-07, or a NIP-46 remote signer later). Zero key custody; some features (background publishing) unavailable — the UI should badge what works.
The UX (matching the house style)
Entry point: next to "Create identity" on Nostr Identities, an "Add existing" glass-button. Opens a modal with three tabs (same tab pattern as the send/receive modals):
- Browser extension (default when
window.nostrexists)- One button: "Connect with extension". Flow:
getPublicKey()→ show the npub + resolved profile (kind-0 fetched via the node's relays: avatar, name — instant recognition) → "Add this identity". - Creates a linked signer identity. A challenge signature
(
signEventon a throwaway event) proves key possession before adding — never add an unverified npub as "yours".
- One button: "Connect with extension". Flow:
- Secret key (nsec)
- Paste field (masked,
nsec1…or hex), inline validation + derived npub preview with the same kind-0 profile card before confirming. - Scary-clear copy: "Your key will be stored on this node, encrypted at rest. It is NOT part of your seed backup — back it up separately." Confirm step requires the profile card to load or an explicit "add anyway".
- Creates a full identity.
- Paste field (masked,
- Public key (npub) — watch-only
- Paste an npub for a linked identity without any signer attached yet (useful to reserve the profile, upgrade to extension/NIP-46 signing later).
After adding: the identity appears in the same grid with a small origin badge —
seed / imported / linked — and the imported profile picture/name pulled from
relays. Everything else (picker in apps, rename, avatar) behaves uniformly.
Removal: existing delete flow; for imported identities the confirm dialog warns
the key is destroyed unless exported first (offer "Export nsec" in the identity's detail
sheet, gated behind password re-entry).
Backend work
identity_manager.rs: identity records gainorigin: Seed { index } | Imported | Linked, optionalnostr_secret_hexabsent for Linked. Storage: reuse the existing encrypted identity file; imported secrets included in node backup.- New RPCs:
identity.import-nostr{ nsec | npub, name?, verify_sig? }→ validates, derives npub, rejects duplicates (same pubkey as any existing identity), returns the new identity.identity.fetch-profile{ pubkey }→ kind-0 lookup vianostr_relays.rsfor the preview card (frontend could also do this, but the node already has relay plumbing and avoids CORS).
identity.nostr-sign(used by the iframe NIP-07 bridge): forLinkedidentities return a typed error the bridge translates into "ask the user's extension instead" — phase 2; phase 1 simply hides linked identities from the in-app signer picker.
Demo mode
Mock identity.import-nostr + identity.fetch-profile in mock-backend.js (canned
profile: picture + name for any pasted npub) so the whole add-existing flow is
demoable without real relays.
Phasing
- Phase 1 (small): nsec + npub tabs, origin badges, backup inclusion, mock.
- Phase 2: extension tab with possession-proof + kind-0 preview cards everywhere.
- Phase 3: NIP-46 remote-signer identities + login integration (shares the QR plumbing from the signer-login work).