nosskey-sdk
v0.2.0
Published
SDK for Passkey-Derived Nostr Identity a.k.a. Nosskey
Downloads
91
Readme
Overview and Purpose of Nosskey
Nosskey (a portmanteau of "Nostr" and "passkey") is a securely managing Nostr private keys and signing events using WebAuthn (passkey) technology. While secure management of private keys has been a challenge in the Nostr protocol, this SDK achieves both high security and excellent user experience by utilizing passkey technology.
This SDK inherits the concept from the previously developed nosskey, but represents a completely different approach thanks to a breakthrough made possible by utilizing the WebAuthn PRF extension.
Benefits of Integrating Passkeys (WebAuthn) with Nostr
Traditional Nostr private key management methods, such as plaintext storage or password-protected format (NIP-49), have presented challenges in terms of security and convenience. Using WebAuthn offers the following benefits:
- Phishing Resistance: Domain validation prevents authentication on fraudulent sites
- Automatic Backup: Entrusting private key management to the platform's passkey synchronization function enables secure cloud backup
- Cross-Device Support: OS passkey synchronization features provide the same experience across multiple devices
Key Features
- 📲 Biometric Authentication: Integration with passkey authentication such as fingerprint and face recognition
- 🔐 Phishing Resistance: Domain validation prevents unauthorized use on phishing sites
- ⚡ Fast Processing: Efficient implementation utilizing WebAuthn PRF extension
- 🔄 Cross-Device Support: Available on multiple devices through OS passkey synchronization
- ✉️ Encrypted Messaging: Built-in NIP-44 (v2) and NIP-04 (legacy) encrypt/decrypt for direct messages
Installation
npm install nosskey-sdkBasic Usage Examples
Creating a Passkey and Generating a New Nostr Key
import { NosskeyManager } from 'nosskey-sdk';
const keyMgr = new NosskeyManager();
// Create a passkey (displays browser's passkey UI)
const credentialId = await keyMgr.createPasskey();
// Use PRF value directly as a Nostr key
const keyInfo = await keyMgr.createNostrKey(credentialId);
keyMgr.setCurrentKeyInfo(keyInfo);
// Get the public key
const publicKey = await keyMgr.getPublicKey();
console.log(`Public key: ${publicKey}`);
// Sign an event
const event = {
kind: 1,
content: 'Hello Nosskey!',
tags: [],
created_at: Math.floor(Date.now() / 1000)
};
const signedEvent = await keyMgr.signEvent(event);Encrypting and Decrypting Messages (NIP-44)
// peerPubkey is the counterparty's public key (32-byte hex)
const ciphertext = await keyMgr.nip44Encrypt(peerPubkey, 'Hello, this is a secret');
const plaintext = await keyMgr.nip44Decrypt(peerPubkey, ciphertext);
// NIP-04 (legacy DM) is also available with the same signature
const legacyCiphertext = await keyMgr.nip04Encrypt(peerPubkey, 'Legacy DM');
const legacyPlaintext = await keyMgr.nip04Decrypt(peerPubkey, legacyCiphertext);Advanced Configuration Examples
// Use nosskey-sdk.pages.dev for development environment
let rpId = location.host;
if (location.host.includes('nosskey-sdk.pages.dev')) {
rpId = 'nosskey-sdk.pages.dev';
// Use 'nosskey.app' instead of subdomains (like 'www.nosskey.app')
} else if (location.host.includes('nosskey.app')) {
rpId = 'nosskey.app';
}
// Initialize NosskeyManager with detailed configuration
const keyMgr = new NosskeyManager({
// Cache options
cacheOptions: {
enabled: true, // Enable caching
timeoutMs: 60 * 1000, // Cache timeout (60 seconds)
},
// Storage options
storageOptions: {
enabled: true, // Enable automatic NostrKeyInfo storage
storageKey: 'nosskey_pwk', // Storage key name
},
// PRF options (can only be set during initialization)
prfOptions: {
rpId, // Relying Party ID (domain)
userVerification: 'required', // Require user verification
},
});API Reference
NosskeyManager Methods
Constructor
constructor(options?)- Initialize NosskeyManager with optional cache and storage options
Key Management
createPasskey(options?)- Create a new passkey with PRF extensioncreateNostrKey(credentialId?, options?)- Generate NostrKeyInfo using PRF value as the private keyexportNostrKey(keyInfo, credentialId?)- Export the private key in hexadecimal format
Key Information Management
setCurrentKeyInfo(keyInfo)- Set the current NostrKeyInfo and save to storage if enabledgetCurrentKeyInfo()- Get the current NostrKeyInfo from memory or storagehasKeyInfo()- Check if NostrKeyInfo exists in memory or storageclearStoredKeyInfo()- Clear NostrKeyInfo from storage and memory
NIP-07 Compatible Methods
getPublicKey()- Get the public key from the current NostrKeyInfosignEvent(event)- Sign a Nostr event using the current NostrKeyInfosignEventWithKeyInfo(event, keyInfo, options?)- Sign a Nostr event with specified NostrKeyInfo
NIP-44 / NIP-04 Encryption Methods
nip44Encrypt(peerPubkey, plaintext)- Encrypt a message for a peer using NIP-44 v2nip44Decrypt(peerPubkey, ciphertext)- Decrypt a NIP-44 v2 message from a peernip04Encrypt(peerPubkey, plaintext)- Encrypt a message for a peer using NIP-04 (legacy, AES-256-CBC)nip04Decrypt(peerPubkey, ciphertext)- Decrypt a NIP-04 (legacy) message from a peer
Cache Management
setCacheOptions(options)- Update cache configurationgetCacheOptions()- Get current cache configurationclearCachedKey(credentialId)- Clear cache for a specific keyclearAllCachedKeys()- Clear all cached keys
Storage Management
setStorageOptions(options)- Update storage configuration for NostrKeyInfogetStorageOptions()- Get current storage configuration
Utility Methods
isPrfSupported()- Check if the PRF extension is supported in the current environment
iframe Mode (Cross-origin Signing)
Nosskey can be embedded as an iframe signing provider so that multiple Nostr
web apps share a single passkey bound to the Nosskey host origin. The
companion package nosskey-iframe ships both the
host-side bridge and a parent-page client. For standalone usage of the
package on its own, see packages/nosskey-iframe/README.md.
Browser Support
| Browser | PRF extension | iframe + WebAuthn | Status | |---------|---------------|-------------------|--------| | Chrome 118+ | ✅ | ✅ (with Permissions Policy) | Supported | | Firefox (latest) | partial | spec-compliant | Limited | | Safari / iOS | partial (Safari 18) | unstable in iframes | Not supported |
Parent-side usage
import { NosskeyIframeClient } from 'nosskey-iframe';
const client = new NosskeyIframeClient({
iframeUrl: 'https://nosskey.app/#/iframe',
});
await client.ready();
window.nostr = {
getPublicKey: () => client.getPublicKey(),
signEvent: (event) => client.signEvent(event),
};NosskeyIframeClient mounts the iframe with
allow="publickey-credentials-get; publickey-credentials-create", which is
required for Chrome to execute WebAuthn inside the embedded frame. The host
server must also return
Permissions-Policy: publickey-credentials-get=*, publickey-credentials-create=*.
For a complete step-by-step guide to embedding the iframe into your own app, see docs/en/iframe-integration.en.md.
See examples/svelte-app (route #/iframe) for a reference host implementation. The host architecture is documented in detail at docs/en/iframe-host.en.md.
Storage partitioning
Chrome 115+ and Firefox's Total Cookie Protection partition third-party
iframe localStorage per top-level origin. A passkey info record saved at
nosskey.app (first-party) is not visible to the iframe embedded in a
different parent origin, so the first call returns NO_KEY.
The reference host (#/iframe) recovers by calling
document.requestStorageAccess({ all: true }) on a user gesture and
auto-toggles the iframe's visibility via a nosskey:visibility postMessage
(handled inside NosskeyIframeClient). See
docs/en/iframe-host.en.md
for details. If you build a custom host, implement the same flow.
Supported Environments
Nosskey SDK works in browser environments that support WebAuthn and the PRF extension. Passkey generation and authentication also require authenticators from compatible OS/devices. The main compatibility status is as follows:
- Chrome and Chromium-based browsers: Supported in version 118 and later
- Safari: Supported in macOS 14.0 (Sonoma) and later, iOS 17 and later
- Firefox: Supports WebAuthn, but PRF extension support is limited
For detailed compatibility information, please refer to the PRF Support Tables.
Sample Application
Details of the sample application can be found in examples/svelte-app. This application provides a demo combining Passkey and Nostr using the features of the Nosskey SDK.
To see it in action, visit the online demo: https://nosskey.app.
License Information
This project is released under the MIT License. For details, please refer to the LICENSE file.
Detailed Documentation
For more detailed implementation and specifications, please refer to the following documents:
- Nosskey Specification - Basic concepts and implementation approaches
- SDK Interface - API details and usage examples
