Session Management
The session system provides a unified way to handle different authentication methods:
- Secret Key NIP-01
- Nostr Extensions NIP-07
- Bunker URL NIP-46
- Amber or in-device NIP-55
while managing user state and encryption capabilities.
Overview
Sessions are stored in local storage and can be:
- Persisted across page reloads
- Used with multiple accounts
- Switched dynamically
- Backed by different signing methods
Basic Usage
typescript
import {ctx, setContext} from '@welshman/lib'
import {
getDefaultNetContext,
getDefaultAppContext,
pubkey,
sessions,
session,
addSession,
getNip07
} from '@welshman/app'
// Set up app config
setContext({
net: getDefaultNetContext(),
app: getDefaultAppContext(),
})
// Log in via NIP-07 extension (browser wallet)
if (await getNip07()) {
addSession({
method: 'nip07',
pubkey: await getNip07().getPublicKey()
})
}
// Get current session
console.log(session.get()) // Current active session
console.log(pubkey.get()) // Current pubkey
Multiple Sessions
typescript
import {sessions, pubkey, addSession, dropSession} from '@welshman/app'
// Add multiple sessions
addSession({method: 'nip07', pubkey: 'abc...'})
addSession({method: 'nip46', pubkey: 'def...', secret: '123'})
// Switch between sessions
pubkey.set('abc...') // Activates that session
// Remove a session
dropSession('abc...')
// List all sessions
console.log(sessions.get())
NIP-46 (Bunker) Authentication
typescript
import {Nip46Broker, Nip46Signer} from '@welshman/signer'
import {addSession} from '@welshman/app'
// Connect to a bunker
const clientSecret = makeSecret()
const relays = ['wss://relay.damus.io']
const broker = Nip46Broker.get({relays, clientSecret})
// Generate nostrconnect URL for the bunker
const connectUrl = await broker.makeNostrconnectUrl({
name: "My App",
url: "https://myapp.com"
})
// Wait for user to approve in bunker
const response = await broker.waitForNostrconnect(connectUrl)
// Create session
addSession({
method: 'nip46',
pubkey: response.event.pubkey,
secret: clientSecret,
handler: {
pubkey: response.event.pubkey,
relays
}
})
Using Session Signer
typescript
import {signer, session} from '@welshman/app'
import {createEvent, NOTE} from '@welshman/util'
// Current session's signer is always ready to use
const event = await signer.get().sign(
createEvent(NOTE, {content: "Hello Nostr!"})
)
// Encrypt content for private notes
const encrypted = await signer.get().nip44.encrypt(
pubkey,
"Secret message"
)
Session Persistence
Sessions are automatically persisted to local storage. On page load:
typescript
import {pubkey, sessions} from '@welshman/app'
// Sessions load automatically from local storage
console.log(sessions.get()) // All stored sessions
// the current active session
console.log(session.get())
// Last active pubkey is restored
console.log(pubkey.get())
Session Types
typescript
type SessionNip07 = {
method: "nip07"
pubkey: string
}
type SessionNip46 = {
method: "nip46"
pubkey: string
secret: string
handler: {
pubkey: string
relays: string[]
}
}
type SessionNip01 = {
method: "nip01"
pubkey: string
secret: string
}
Error Handling
typescript
import {tryCatch} from '@welshman/lib'
import {addSession, getNip07} from '@welshman/app'
const login = async () => {
const nip07 = await tryCatch(getNip07)
if (!nip07) {
throw new Error("No NIP-07 extension found")
}
const pubkey = await tryCatch(
() => nip07.getPublicKey()
)
if (!pubkey) {
throw new Error("Failed to get public key")
}
addSession({method: 'nip07', pubkey})
}