Proposal 4: Remote signer mode (NIP-46)
Problem / direction
Today keystr is a local signer: the nsec lives in the browser profile
and is only usable by web pages in that browser via window.nostr
(NIP-07). Consequences:
- Every device needs its own copy of the nsec — copied around via plaintext-ish channels, each copy another thing to protect.
- Mobile apps and other browsers can't use the identity unless the key is imported there too.
- The PIN (and proposed passkey) protection only guards the local copy.
The long-term shape: the extension becomes the single place the key lives (passkey-wrapped per proposal 1), and everything else talks to it remotely via NIP-46 (Nostr Connect / remote signing, kind 24133 over relays).
Proposal
Two complementary modes, sharing one policy engine:
4a. Signer mode (bunker) — the differentiator
The extension acts as a NIP-46 signer. Other devices/clients (mobile
apps, other browsers, CLI tools) connect with a nostrconnect:// URI or
bunker string; signing requests arrive over relays, the user approves them
in the existing prompt UI, responses go back over relays. The nsec never
leaves the extension.
- Pairing UX in the options page: show
nostrconnect://URI + QR code; incoming connection requests get an approval prompt (reuseprompt.tsx). - New background module (e.g.
nip46Signer.ts): relay pool management and kind-24133 request handling.nostr-tools^2.7 already ships anip46module — no new dependencies (verify API surface at implementation time). - Requests are encrypted with NIP-44 conversation keys — reuses the existing
nip44code paths andsecretsCache. - Per-client policies: keyed by the client's pubkey, mirroring the
per-site permission levels in
common.ts(PERMISSIONS_REQUIRED) and the policy engine from proposal 2c. "This phone app may sign kind 1 and kind 7, must prompt for kind 3."
4b. Client mode (proxy) — the thin extension
Optionally, window.nostr calls are proxied to an external bunker
(e.g. a hardware-bound signer, a home server, or the extension's own signer
mode on another machine). The browser then holds no key at all; the
extension becomes UI + policy layer + NIP-46 client. This is the answer for
users who don't want key material in any browser.
Suggested order
Signer mode (4a) first — it makes the extension the hub and compounds with passkeys (proposal 1): the strongest-protected copy of the key becomes the one everyone else uses. Client mode (4b) is a smaller follow-up.
Architecture notes
- Both modes sit behind the existing permission layer: NIP-46 request
types (
sign_event,nip04_decrypt,nip44_decrypt, …) map onto the samePERMISSIONS_REQUIREDlevels used for NIP-07 calls, so prompts, batching (proposal 2b), and policies (proposal 2c) apply uniformly. - Combined with proposal 1, high-risk remote operations can require a fresh passkey assertion — the "touch your key to sign remotely" model.
Open questions / challenges
- Awake problem: the extension is not a server. Browser closed (or MV3
service worker asleep, see proposal 3) = signer offline. Kind 24133 events
are ephemeral; requests sent while asleep are missed unless relays retain
them and we catch up with a
sincefilter on reconnect. Decide: best-effort catch-up, "signer is offline" signaling to clients, or documented expectation that the signer machine stays on. MV3 lifecycle (WebSocket keepalive vs. worker idle timeout) must be validated in the proposal-3 spike. - Relay trust & metadata: requests/responses are encrypted, but relays see timing and pubkey pairs. Allow per-session relay selection; consider dedicated/private relays for signing traffic.
- Request authentication: a leaked
nostrconnect://URI or a spammy relay means arbitrary connection attempts — the pairing approval + per-client pubkey policies are the mitigation; rate-limit unknown clients. - This is the mobile story: Firefox Android support was dropped (proposal 3). Signer mode replaces it — mobile Nostr clients (Amethyst et al.) already speak NIP-46, so the phone connects to the desktop extension instead of needing a ported extension. Better security (one key copy, passkey-wrapped) and testable with any NIP-46 mobile client.
- Session auditability: with remote signing, a log of what was signed for which client (ties into proposal 2's audit question) becomes important.
Non-goals
- Not a hosted bunker service — no server component, no key custody.
- Not FROST/threshold signing — Frostr-style key splitting remains a possible later step for multi-device redundancy.
Interactions with other proposals
- Proposal 1 (passkeys): the key being remotely requested is exactly the key that should be hardware-wrapped; fresh-assertion policies gate remote ops.
- Proposal 2 (batching & policies): remote clients are first-class policy subjects alongside web origins; bursts from a mobile app hit the same batched prompt UI.
- Proposal 3 (MV3): the service-worker lifecycle design (3c) is a prerequisite for a reliable always-on signer.