NIP-46: Nostr Connect
NIP-46 defines remote signing over Nostr relays. A client talks to a separate signer, often called a bunker, so signing keys can stay outside the app the user is actively using.
How It Works
- The client generates a local keypair used only for the bunker session.
- The connection is established with either a
bunker://ornostrconnect://URI. - Client and signer exchange encrypted kind
24133request and response events over relays. - After connecting, the client calls
get_public_keyto learn the actual user pubkey it is signing for.
Connection Methods
- bunker:// - Signer-initiated connection
- nostrconnect:// - Client-initiated connection via QR code or deep link
nostrconnect:// flows include a required shared secret so the client can verify that the first response really came from the intended signer. That prevents simple connection spoofing.
Supported Operations
sign_event- Sign an arbitrary eventget_public_key- Retrieve the user’s pubkey from the signernip04_encrypt/decrypt- NIP-04 encryption operationsnip44_encrypt/decrypt- NIP-44 encryption operationsswitch_relays- Ask the signer for an updated relay set
Many implementations also use permission strings such as sign_event:1 or nip44_encrypt during setup so the signer can approve a narrow scope instead of full access.
Relay and Trust Model
NIP-46 moves private keys out of the client, but it does not remove trust from the signer. The signer can approve, deny, or delay requests, and it sees every operation the client asks it to perform. Relay choice also matters because the protocol depends on request and response delivery over relays both sides can reach.
The switch_relays method exists so the signer can move the session to a different relay set over time. Clients that ignore it will work less reliably when signer relay preferences change.
Primary sources:
Mentioned in:
- Newsletter #1: Notable Code Changes
- Newsletter #3: December Recap
- Newsletter #4: Primal Android Becomes a Full Signing Hub
- Newsletter #12: NDK Collaborative Events and NIP-46 Timeout
See also: