Session Management
This guide covers saving and restoring authenticated sessions in the Privacy Boost SDK.Overview
Sessions contain the authentication state needed to use the SDK without re-authenticating. This includes:- Wallet address
- JWT token
- MPK (Master Public Key)
- Token expiry time
Export Session
Save the current session:Copy
const session = sdk.auth.exportSession();
// Store securely
localStorage.setItem('privacy_session', JSON.stringify(session));
Session Data Structure
Copy
interface ExportableSession {
walletAddress: string; // Connected wallet
jwt: string; // Authentication token
jwtExpiry: number; // Expiry timestamp
mpk: string; // Master public key
}
Import Session
Restore a saved session:Copy
const savedSession = localStorage.getItem('privacy_session');
if (savedSession) {
try {
const session = JSON.parse(savedSession);
await sdk.auth.importSession(session);
console.log('Session restored');
} catch (error) {
console.log('Session invalid or expired');
localStorage.removeItem('privacy_session');
}
}
Check Session Validity
Before importing, verify the session is still valid:Copy
const sessionInfo = await sdk.auth.getSessionInfo();
if (sessionInfo) {
console.log('Valid:', sessionInfo.valid);
console.log('Expires:', new Date(sessionInfo.expiresAt * 1000));
console.log('Is Auditor:', sessionInfo.isAuditor);
}
Session Flow
Copy
┌─────────────────────────────────────────────────────────┐
│ App Startup │
└────────────────────────┬────────────────────────────────┘
│
▼
┌──────────────────────┐
│ Check saved session │
└──────────┬───────────┘
│
┌─────────────┴─────────────┐
│ │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ Session found │ │ No session │
└───────┬───────┘ └───────┬───────┘
│ │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ Import session│ │ Show login │
└───────┬───────┘ └───────────────┘
│
┌─────┴─────┐
│ │
▼ ▼
┌─────────┐ ┌─────────┐
│ Valid │ │ Invalid │
│ Ready! │ │ Re-auth │
└─────────┘ └─────────┘
Complete Session Management Example
Copy
class SessionManager {
private readonly storageKey = 'privacy_session';
async initialize() {
const session = this.load();
if (!session) return false;
try {
await sdk.auth.importSession(session);
const info = await sdk.auth.getSessionInfo();
if (!info?.valid) {
this.clear();
return false;
}
return true;
} catch {
this.clear();
return false;
}
}
save() {
const session = sdk.auth.exportSession();
localStorage.setItem(this.storageKey, JSON.stringify(session));
}
load(): unknown | null {
const data = localStorage.getItem(this.storageKey);
return data ? JSON.parse(data) : null;
}
clear() {
localStorage.removeItem(this.storageKey);
}
}
// Usage
const sessionManager = new SessionManager();
async function initApp() {
const restored = await sessionManager.initialize();
if (restored) {
console.log('Welcome back!');
} else {
// Show login UI
}
}
// Save after login
await sdk.auth.login();
sessionManager.save();
// Clear on logout
await sdk.auth.logout();
sessionManager.clear();
Secure Storage
Browser (with encryption)
Copy
import CryptoJS from 'crypto-js';
class SecureSessionStorage {
private readonly storageKey = 'privacy_session_encrypted';
save(password: string) {
const session = sdk.auth.exportSession();
const encrypted = CryptoJS.AES.encrypt(
JSON.stringify(session),
password
).toString();
localStorage.setItem(this.storageKey, encrypted);
}
load(password: string): unknown | null {
const encrypted = localStorage.getItem(this.storageKey);
if (!encrypted) return null;
try {
const decrypted = CryptoJS.AES.decrypt(encrypted, password);
const json = decrypted.toString(CryptoJS.enc.Utf8);
return JSON.parse(json);
} catch {
return null;
}
}
clear() {
localStorage.removeItem(this.storageKey);
}
}
React Native
Copy
import * as Keychain from 'react-native-keychain';
class KeychainSessionStorage {
private readonly service = 'privacy-boost';
async save() {
const session = sdk.auth.exportSession();
await Keychain.setGenericPassword(
'session',
JSON.stringify(session),
{ service: this.service }
);
}
async load(): Promise<unknown | null> {
const credentials = await Keychain.getGenericPassword({
service: this.service
});
if (!credentials) return null;
return JSON.parse(credentials.password);
}
async clear() {
await Keychain.resetGenericPassword({ service: this.service });
}
}
Node.js
Copy
import fs from 'fs';
import path from 'path';
import os from 'os';
class FileSessionStorage {
private readonly filePath: string;
constructor() {
const dir = path.join(os.homedir(), '.privacy-boost');
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { mode: 0o700 });
}
this.filePath = path.join(dir, 'session.json');
}
save() {
const session = sdk.auth.exportSession();
fs.writeFileSync(
this.filePath,
JSON.stringify(session),
{ mode: 0o600 }
);
}
load(): unknown | null {
if (!fs.existsSync(this.filePath)) return null;
const data = fs.readFileSync(this.filePath, 'utf-8');
return JSON.parse(data);
}
clear() {
if (fs.existsSync(this.filePath)) {
fs.unlinkSync(this.filePath);
}
}
}
Session Expiration Handling
Copy
class SessionExpirationHandler {
private checkInterval: number | null = null;
start(onExpired: () => void) {
this.checkInterval = window.setInterval(async () => {
const info = await sdk.auth.getSessionInfo();
if (!info?.valid) {
this.stop();
onExpired();
}
}, 60000); // Check every minute
}
stop() {
if (this.checkInterval) {
clearInterval(this.checkInterval);
this.checkInterval = null;
}
}
}
// Usage
const expirationHandler = new SessionExpirationHandler();
expirationHandler.start(() => {
console.log('Session expired!');
// Show re-login prompt
});
Auto-Refresh Sessions
Copy
async function withSessionRefresh<T>(
operation: () => Promise<T>
): Promise<T> {
try {
return await operation();
} catch (error) {
if (error.code === 'SESSION_EXPIRED') {
// Re-authenticate
await sdk.auth.login();
sessionManager.save();
// Retry operation
return await operation();
}
throw error;
}
}
// Usage
const balance = await withSessionRefresh(() =>
sdk.vault.getBalance('0x...')
);
Best Practices
1. Check Session on App Start
Copy
useEffect(() => {
async function checkSession() {
const restored = await sessionManager.initialize();
if (!restored) {
navigate('/login');
}
}
checkSession();
}, []);
2. Save Session After Login
Copy
async function handleLogin() {
await sdk.auth.connect(adapter);
await sdk.auth.login();
sessionManager.save();
}
3. Clear Session on Logout
Copy
async function handleLogout() {
await sdk.auth.logout();
sessionManager.clear();
navigate('/login');
}
4. Handle Account Changes
Copy
window.ethereum?.on('accountsChanged', async (accounts: string[]) => {
const currentAddress = sdk.auth.getAddress();
if (accounts[0]?.toLowerCase() !== currentAddress?.toLowerCase()) {
sessionManager.clear();
navigate('/login');
}
});