| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Browser extension for did:nostr and Solid authentication
Podkey is a NIP-07 signer for Nostr and an HTTP-auth signer for Solid pods. It puts a window.nostr provider on every page, signs events with your key, and authenticates to Solid servers over NIP-98 using your did:nostr identity. The private key stays inside the extension and never reaches the page.
git clone https://github.com/JavaScriptSolidServer/podkey.git
cd podkey
npm install
npm run build # bundles the background worker and passkey-enabled popupThen load the podkey directory as an unpacked extension (steps 2–4 above).
Pin the toolbar icon (🔑), open it, and generate or import a 64-character hex key, choosing an encryption passphrase. The key is sealed under that passphrase (see Security model); you unlock it once per browser session. The test page detects the extension and runs live signing checks.
if (window.nostr) {
const pubkey = await window.nostr.getPublicKey()
const signed = await window.nostr.signEvent({
kind: 1,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: 'Hello from Podkey! 🔑'
})
}Returns your public key as 64-character hex. Prompts once for a new origin.
Signs a Nostr event and returns it with id, pubkey and sig populated. A trusted origin signs with no prompt; a new origin prompts once, and approving it grants trust.
NIP-44 (v2) encryption for NIP-17 / NIP-59 direct messages. The private key stays in the background worker; only the base64 payload or decrypted plaintext crosses to the page.
const peer = '<64-char hex pubkey>'
const payload = await window.nostr.nip44.encrypt(peer, 'hello')
const plaintext = await window.nostr.nip44.decrypt(peer, payload)┌─────────────────────────────────────────┐ │ Podkey (MV3 extension) │ │ │ │ Popup UI (popup/) │ │ key generation / import, trusted-site │ │ management, identity display, consent │ │ │ │ Background worker (src/) │ │ encrypted key vault (vault.js) + session│ │ cache (storage.js), signing & NIP-44 │ │ (crypto.js, nip44.js), NIP-98 auth, │ │ per-origin permission gate │ │ │ │ Page bridge (src/injected.js) │ │ injects window.nostr, relays requests │ │ to the worker, whitelists message types│ └─────────────────────────────────────────┘
The private key is read only inside the background worker. The page sees a public key, a signed event, a NIP-44 payload, or a NIP-98 header, never the key itself.
A Podkey public key is a 64-character hex string, so it is also a did:nostr identifier:
const pubkey = await window.nostr.getPublicKey()
const did = `did:nostr:${pubkey}`
// did:nostr:3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459dThat identifier authenticates you to Solid pods and travels across any NIP-07-aware app.
Podkey can bind your Nostr identity to a FIDO2 / WebAuthn passkey instead of a passphrase. Two modes, both requiring an authenticator that supports the WebAuthn PRF (hmac-secret) extension — a phone passkey, a modern security key, or a platform authenticator:
It is an advanced tier aimed at managing agents or working under compliance rules; the Generate/Import flows are unchanged. The construction is specified in site/passkey-identity.html, and the DID layer in site/did-nostr.html.
Podkey sits at the join of two mature, independently-built ecosystems and consolidates them behind one key:
The novel part is the consolidation: one locally-held, encrypted key that is simultaneously your Nostr signer, your did:nostr identity, and your Solid login. Podkey extends what existing Nostr signers do (NIP-07) with did:nostr identity and Solid/NIP-98 authentication, and adds an encrypted-at-rest vault on top.
npm install
npm run build # bundle dependencies into the service worker
npm test # node --test, 169 cases (incl. vault & passkey crypto)
npm run lint # eslint, no-unused-vars as errorpodkey/ ├── manifest.json # MV3 manifest (CSP script-src 'self') ├── src/ │ ├── background.js # service worker: message handling, consent gate │ ├── crypto.js # key generation & Schnorr signing │ ├── passkey.js # FIDO2/WebAuthn PRF identity derive + wrap │ ├── keyformat.js # nsec/npub bech32 encode/decode │ ├── nip44.js # NIP-44 v2 encrypt/decrypt │ ├── nip98-interceptor.js # page-context NIP-98 fetch/XHR auth │ ├── auth-header-utils.js # NIP-98 Authorization header helpers │ ├── vault.js # AES-GCM encrypted-at-rest key vault (scrypt) │ ├── storage.js # session key cache + trusted-origin storage │ ├── injected.js # content-script page bridge │ └── nostr-provider.js # window.nostr implementation ├── popup/ # popup + approval UI ├── test-page/ # install + live-signing test page └── scripts/bundle.js # esbuild bundler
Tests cover the consent flow, NIP-44 against the official spec vectors, NIP-98 token shape, the content-script message whitelist, and signature self-verify. CI runs build, test and lint on every pull request and push to main, and uploads a sideloadable extension zip.
Good first contributions: test coverage, NIP-04, i18n, nsec/npub Bech32 display, and documentation.
window.nostr is undefined. Reload the page after installing, confirm the extension is enabled, and check for another Nostr extension claiming window.nostr.
Events will not sign. Generate or import a key first. If the popup shows Unlock, the vault is locked (e.g. after a browser restart). Enter your passphrase to unlock for the session. Also check the service worker console (the "service worker" link on chrome://extensions) for a blocked consent prompt.
Passkey identity fails right after the biometric. The WebAuthn ceremony reports NotAllowedError ("timed out or was not allowed") when a prompt is cancelled, times out, or the authenticator lacks the PRF (hmac-secret) extension Podkey needs to derive the key. Podkey prompts twice — register, then derive — so confirm both. Use a phone passkey or a modern security key if your local authenticator has no PRF. A fingerprint that scans but is rejected (verify-no-match) is an OS enrolment issue, not Podkey.
Build errors. Reinstall dependencies (npm install) and confirm Node.js 18 or newer.
AGPL-3.0. See LICENSE.
Podkey — your keys, your identity, your data.
| Back | FazBrowse Home | New Git URL |