nip07
v0.0.6
Published
Minimal NIP-07 window.nostr provider. Paste a hex private key, get signing.
Maintainers
Readme
nip07 is a minimal NIP-07 window.nostr provider for the browser. It gives any Nostr web app the ability to sign events — either by pasting a hex private key or by using an existing browser extension.
No build tools. No frameworks. One script tag.
Quick Start
<script src="https://unpkg.com/nip07"></script>A login button appears in the corner. You get three ways to authenticate:
- Browser extension — if a NIP-07 extension is detected, a "Use Browser Extension" button appears at the top of the modal. Click it to delegate all signing to the extension.
- Guest — if the page enables it, a "Continue as Guest" button logs in with a shared well-known keypair. No setup required.
- Hex private key — paste a 64-character hex key and it auto-accepts instantly.
Click the button again when logged in to log out.
Guest Mode
To enable the guest button, add a data-guest attribute with a 64-char hex private key:
<script src="https://unpkg.com/nip07" data-guest="473305b5b39cd679d94bd56f38b939ada5d4827bbf80e7889ad1238e8ebbdd0d"></script>The key is public by design — all guest users share the same identity. This is useful for letting people try a Nostr app without installing an extension or managing keys. Omit the attribute to disable guest login.
Tip: If you're using nip07 alongside other client-side rendering libraries (e.g. solid-shim/mashlib), add the
deferattribute to avoid the page flashing white:<script src="https://unpkg.com/nip07" defer></script>This ensures nip07 loads after the DOM is parsed, preventing conflicts with libraries that render on load.
Live Demo
Try it at nip-07.github.io/nip7
What You Get
A spec-compliant window.nostr with four async methods:
await window.nostr.getPublicKey() // 64-char hex pubkey
await window.nostr.signEvent(event) // signed event with id, pubkey, sig
await window.nostr.nip04.encrypt(pubkey, text) // NIP-04 encrypted DM
await window.nostr.nip04.decrypt(pubkey, text) // NIP-04 decrypted DMHow It Works
- The script saves any existing
window.nostr(from a browser extension) before overwriting - Sets its own
window.nostrsynchronously on load — before your app's scripts run - A small floating button appears (bottom-right, Shadow DOM isolated)
- When an app calls any
window.nostrmethod, the login modal opens automatically if needed - If an extension is detected, the modal offers it as a one-click option
- If
data-guestis set, a guest login button appears in the modal - If a hex key is pasted, signing happens locally using Schnorr/BIP-340
- Click the button again to log out (clears key from memory)
Under the hood:
- Signing — Schnorr/BIP-340 over secp256k1 per NIP-01
- Encryption — ECDH shared secret + AES-256-CBC via Web Crypto API per NIP-04
- Hashing — SHA-256 via the browser's native
crypto.subtle - UI isolation — closed Shadow DOM, zero CSS leakage in or out
- Extension support — detects and proxies to existing NIP-07 extensions
ES Module
For programmatic use without the UI:
npm install nip07import { getPublicKey, signEvent, nip04, init } from "nip07";
// Derive a public key
const pubkey = getPublicKey("abc123...");
// Sign an event
const signed = await signEvent("abc123...", {
created_at: Math.floor(Date.now() / 1000),
kind: 1,
tags: [],
content: "Hello Nostr",
});
// Or wire up window.nostr in one call (no UI)
init("abc123...");| Export | Description |
|--------|------------|
| getPublicKey(privHex) | Returns hex pubkey from a hex private key |
| signEvent(privHex, event) | Returns a complete signed event |
| nip04.encrypt(privHex, pubkey, text) | NIP-04 encrypt a message |
| nip04.decrypt(privHex, pubkey, text) | NIP-04 decrypt a message |
| init(privHex) | Sets up window.nostr using the given key |
Events
The script dispatches nlAuth events on document for login and logout:
document.addEventListener("nlAuth", (e) => {
console.log(e.detail.type); // "login" or "logout"
});Security
| Concern | Approach |
|---------|----------|
| Key storage | Memory only — never touches localStorage, sessionStorage, or disk |
| Page refresh | Clears the key — re-entry required |
| Input masking | Password field — key is never visible on screen |
| Extension mode | Private key never leaves the extension — nip07 proxies calls through |
| CSS isolation | Closed Shadow DOM — host page cannot read or style the widget |
| Dependencies | Single dep: @noble/secp256k1 (audited, pure JS, zero transitive deps) |
Specs Implemented
- NIP-01 — Event signing (Schnorr/secp256k1, SHA-256 event ID)
- NIP-04 — Encrypted direct messages (ECDH + AES-256-CBC)
- NIP-07 —
window.nostrprovider interface
License
MIT — Melvin Carvalho
