Decentralized SSO library - Authentication, membership, and profile management
npm install ns-auth-sdk#### Encryption Method
Encrypt an existing private key with a key derived from the passkey’s PRF output. WebAuthn PRF Extension The PRF (Pseudo‑Random Function) extension, part of WebAuthn Level 3, yields deterministic 32‑byte high‑entropy values from an authenticator’s internal private key and a supplied salt. The same credential ID and salt always generate the same PRF output, which never leaves the device except during authentication.
Install from npm:
``bash`
npm install ns-auth-sdkor
pnpm install ns-auth-sdkor
yarn add ns-auth-sdk
`typescript
import { AuthService, RelayService } from 'ns-auth-sdk';
import { EventStore } from 'applesauce-core';
// Initialize auth service
const authService = new AuthService({
rpId: 'your-domain.com',
rpName: 'Your App Name',
storageKey: 'nsauth_keyinfo',
cacheOnCreation: true, // Enable early caching (default: true)
});
// Initialize relay service with EventStore
const relayService = new RelayService({
relayUrls: ['wss://relay.io'],
});
// Initialize with EventStore
const eventStore = new EventStore(/ config /);
relayService.initialize(eventStore);
`
`typescript
import { useAuthStore } from 'ns-auth-sdk';
function App() {
const publicKey = useAuthStore((state) => state.publicKey);
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
const setAuthenticated = useAuthStore((state) => state.setAuthenticated);
// Initialize auth on mount
useAuthInit(authService, setAuthenticated);
// ... rest of your app
}
`
#### Registration Flow
`typescript
import { RegistrationFlow } from 'ns-auth-sdk';
import { useRouter } from 'next/navigation'; // or your router
function RegisterPage() {
const router = useRouter();
return (
setAuthenticated={useAuthStore((state) => state.setAuthenticated)}
onSuccess={() => router.push('/profile')}
/>
);
}
`
#### Login Button
`typescript
import { LoginButton } from 'ns-auth-sdk';
function LoginPage() {
return (
setAuthenticated={useAuthStore((state) => state.setAuthenticated)}
setLoginError={useAuthStore((state) => state.setLoginError)}
onSuccess={() => router.push('/dashboard')}
/>
);
}
`
#### Profile Page
`typescript
import { ProfilePage } from 'ns-auth-sdk';
function ProfilePageComponent() {
const publicKey = useAuthStore((state) => state.publicKey);
return (
relayService={relayService}
publicKey={publicKey}
onUnauthenticated={() => router.push('/login')}
onSuccess={() => router.push('/membership')}
onRoleSuggestion={async (about) => {
// Optional: Provide role suggestion callback
const response = await fetch('/api/suggest-role', {
method: 'POST',
body: JSON.stringify({ about }),
});
const data = await response.json();
return data.role || null;
}}
/>
);
}
`
#### Membership Management
`typescript
import { MembershipPage } from 'ns-auth-sdk';
function MembershipPageComponent() {
const publicKey = useAuthStore((state) => state.publicKey);
return (
relayService={relayService}
publicKey={publicKey}
onUnauthenticated={() => router.push('/login')}
/>
);
}
`
#### Methods
- createPasskey(username?: string): Promise - Create a new passkeycreateNostrKey(credentialId?: Uint8Array): Promise
- - Create Nostr key from passkeygetPublicKey(): Promise
- - Get current public keysignEvent(event: NostrEvent): Promise
- - Sign a Nostr eventgetCurrentKeyInfo(): NostrKeyInfo | null
- - Get current key infosetCurrentKeyInfo(keyInfo: NostrKeyInfo): void
- - Set current key infohasKeyInfo(): boolean
- - Check if key info existsclearStoredKeyInfo(): void
- - Clear stored key infoisPrfSupported(): Promise
- - Check if PRF is supported
#### Configuration Options
`typescript`
interface NosskeyManagerOptions {
cacheOptions?: {
enabled: boolean;
timeoutMs?: number;
cacheOnCreation?: boolean; // Cache key immediately after derivation (default: true)
};
storageOptions?: {
enabled: boolean;
storage?: Storage;
storageKey?: string;
};
prfOptions?: {
rpId?: string;
timeout?: number;
userVerification?: UserVerificationRequirement;
};
}
Cache Options:
- enabled: Enable/disable key cachingtimeoutMs
- : Cache timeout in milliseconds (default: 30 minutes)cacheOnCreation
- : When true, caches the key immediately after createNostrKey() to reduce biometric prompts from 2-3 to 1-2. This is enabled by default for better user experience.
Service for communicating with Nostr relays using applesauce-core.
#### Methods
- initialize(eventStore: EventStore): void - Initialize with EventStoregetRelays(): string[]
- - Get current relay URLssetRelays(urls: string[]): void
- - Set relay URLspublishEvent(event: NostrEvent, timeoutMs?: number): Promise
- - Publish eventfetchProfile(pubkey: string): Promise
- - Fetch profilefetchProfileRoleTag(pubkey: string): Promise
- - Fetch role tagfetchFollowList(pubkey: string): Promise
- - Fetch follow listfetchMultipleProfiles(pubkeys: string[]): Promise
-
All components are framework-agnostic React components that accept callback props for navigation.
#### Common Props
- authService: AuthService - Auth service instancerelayService?: RelayService
- - Relay service instance (required for profile/membership)publicKey?: string | null
- - Current user's public keyonSuccess?: () => void
- - Success callbackonUnauthenticated?: () => void
- - Unauthenticated callback
This library is designed to work seamlessly with applesauce-core. The RelayService uses applesauce's EventStore for all relay operations.
`typescript
import { EventStore } from 'applesauce-core';
import { RelayService } from 'ns-auth-sdk';
const eventStore = new EventStore({
// configuration
});
const relayService = new RelayService();
relayService.initialize(eventStore);
``
- Configure a strict Content Security Policy (CSP) in the host app to restrict script and image sources.
- Add rate limiting or debouncing around profile queries and event publishing in the host app or API layer.
- Avoid surfacing raw error details to end users; log detailed errors in secure logs.