Skip to content

Why host a heavy server when a PWA can do everything locally? Built a zero-server privacy vault.

6 min read By NT²

In the era of massive cloud-first applications, we often overlook a powerful alternative: the Progressive Web App (PWA). Why maintain a heavy, expensive, and potentially vulnerable server infrastructure when the modern browser is capable of running a full-featured, secure, and high-performance application entirely on the user's device?

Why host a heavy server when a PWA can do everything locally?

The modern web application paradigm is heavily biased towards the "cloud-first" model. We are accustomed to applications that require a constant connection, rely on massive server-side databases, and perform complex computations in remote data centers. While this model offers convenience and seamless synchronization, it introduces three critical challenges:

  1. The "Honey Pot" Risk: Centralized servers storing sensitive user data become high-value targets for attackers. A single breach can expose millions of users' most private information.
  2. Operational Complexity: Maintaining a global, highly available, and secure server infrastructure is expensive and operationally intensive. It requires massive scaling, complex database management, and constant security auditing.
  3. Connectivity Dependency: The application becomes unusable the moment the user loses internet access. In a world of mobile connectivity and travel, "offline mode" is often a secondary, degraded experience rather than a primary state.

At NT², we took a different approach. We built a structured digital asset vault that is local-first and zero-knowledge by design. This article explores the technical architecture that allows a Progressive Web App (PWA) to function as a high-performance, secure, and entirely local application.

The Architecture: A Local-First Paradigm

The core philosophy of our architecture is simple: The user's device is the primary source of truth.

By shifting the heavy lifting—storage, indexing, and encryption—from the server to the client, we achieve a "zero-server" model for the core user experience. The server is relegated to an optional, "blind" relay for synchronization, rather than the authoritative owner of the data.

graph TD
    subgraph Browser_System [Browser Primary System]
        UI[SvelteKit UI]
        WASM[wa-sqlite WASM]
        OPFS_Storage[(OPFS Storage)]
        Mem[In-memory CryptoKey]
        
        UI --> WASM
        WASM --> OPFS_Storage
        UI --> Mem
    end

    subgraph Edge_Relay [Cloudflare Edge Optional Relay]
        W[Workers]
        D1[(D1 Metadata)]
        R2[(R2 Blob Storage)]
        
        W --> D1
        W --> R2
    end

    UI -.->|Optional Replica Batch Sync| W
    W -.->|Blind Relay| R2

Technical Deep Dive

1. High-Performance Relational Storage: Beyond IndexedDB

Traditional browser storage like IndexedDB is excellent for simple key-value pairs, but it struggles with complex relational data and large-scale queries. For a vault containing thousands of structured assets, we needed the power of SQL.

We implemented wa-sqlite, a WebAssembly port of SQLite, to bring full relational database capabilities directly into the browser. However, standard WASM-based SQLite often suffers from performance bottlenecks due to the way it interacts with the browser's storage.

To solve this, we leverage the Origin Private File System (OPFS).

OPFS provides a high-performance, low-latency file system specifically designed for web applications. By using the OPFSCoopSyncVFS (Cooperative Sync Virtual File System), wa-sqlite can perform direct, high-speed I/O operations on the user's local disk. This allows the vault to handle large datasets and complex FTS5 (Full-Text Search) queries with performance that rivals native desktop applications.

2. The Cryptographic Foundation: Zero-Knowledge Security

Security is not an afterthought; it is the foundation. Our "zero-knowledge" guarantee means that even if our servers were compromised, the attacker would find nothing but meaningless ciphertext.

We achieve this using the Web Crypto API, a native, high-performance cryptographic interface provided by modern browsers. Our implementation follows a strict hierarchy:

Key Derivation

When a user creates a vault, we don't just store a password. We use PBKDF2 (Password-Based Key Derivation Function 2) with 100,000 iterations of SHA-256 to stretch the user's master password into a high-entropy master key. This process is computationally expensive by design, making brute-force attacks significantly harder.

Mitigating XSS: The "Non-Extractable" Security Guarantee

One of the most critical security features we implement is the use of non-extractable keys.

In a typical web application, if a malicious script (XSS) manages to execute in the user's session, it can often access sensitive data or even the keys used to encrypt it. We mitigate this by setting the extractable parameter to false when deriving the vault's AES-GCM encryption key using crypto.subtle.deriveKey.

// Conceptual implementation
const vaultKey = await crypto.subtle.deriveKey(
  {
    name: "PBKDF2",
    salt: salt,
    iterations: 100000,
    hash: "SHA-256"
  },
  passwordKey,
  { name: "AES-GCM", length: 256 },
  false, // <--- CRITICAL: The key cannot be exported from the browser
  ["encrypt", "decrypt"]
);

By setting extractable: false, the resulting CryptoKey object exists only within the browser's memory. Even if a malicious script manages to execute, it cannot "steal" the key by calling exportKey(). The key is physically un-exportable by the JavaScript environment, providing a powerful layer of defense-in-depth.

Authenticated Encryption

Every piece of sensitive data is encrypted using AES-GCM (Advanced Encryption Standard with Galois/Counter Mode). AES-GCM provides both confidentiality (hiding the data) and integrity (ensuring the data hasn't been tampered with) through an authentication tag. We generate a unique, random Initialization Vector (IV) for every single encryption operation, ensuring that encrypting the same data twice results in different ciphertexts.

sequenceDiagram
    participant User
    participant Browser
    participant Storage

    User->>Browser: Enter Master Password
    Browser->>Browser: PBKDF2
    Browser->>Browser: deriveKey
    Note over Browser: Vault Key in Memory
    User->>Browser: Save Sensitive Item
    Browser->>Browser: AES-GCM
    Browser->>Storage: Store Ciphertext and IV

3. The PWA Advantage: Performance and Resilience

By using SvelteKit to build our PWA, we gain the ability to treat the web application as a first-class citizen on any device.

  • Service Workers: We use Service Workers to cache the application shell and assets. This allows the vault to load instantly, even when offline.
  • Offline-First UX: Because the entire database and encryption logic reside locally, the user experience is seamless. There are no "loading" spinners while waiting for a server to respond to a search query or a vault unlock.
  • Native-like Performance: The combination of SvelteKit's efficient reactivity and the high-speed I/O of wa-sqlite + OPFS provides a responsive, "snappy" interface that feels like a native desktop or mobile app.

The Zero-Knowledge Guarantee: Why it matters

The "zero-server" model is not just about reducing costs; it's about fundamentally changing the trust model. In a traditional cloud-first application, you trust the provider to:

  1. Securely store your data.
  2. Not access your data.
  3. Not lose your data.

In the NT² architecture, the server is blind. It only sees encrypted blobs and non-sensitive metadata. It cannot see your items, your attachments, or even your identity (which is managed via a cryptographic Key DID). This eliminates the "Honey Pot" risk entirely—there is no central database of plaintext secrets to steal.

Security design notes (NT² Vault)

  • Master password never leaves the client: all key derivation and encryption/decryption happen in the browser, and the CryptoKey is set to non-extractable (extractable: false).
  • Auto-lock: after 5 minutes of inactivity or when the tab is closed, the in-memory key and decrypted data are immediately wiped.
  • Salt stored locally: each vault keeps a unique salt and verifier in vault_meta; it is never requested from or uploaded to Workers.
  • Attachments encrypted and separated: attachments are encrypted as binary and stored in the OPFS or the Tauri local filesystem, read through the BlobStore only when needed.

Conclusion

The "heavy server" model is a solution to a problem that shouldn't exist for privacy-centric applications. By embracing the power of the modern browser—WASM, OPFS, and the Web Crypto API—we have demonstrated that it is possible to build a high-performance, feature-rich, and incredibly secure vault that requires zero trust in a central server.

NT² is built on the principle that you should own your data, and you should own the keys to it. By moving the complexity to the edge (the user's device), we've created a system that is more secure, more resilient, and more scalable than the traditional cloud-centric alternatives.

Last updated 2026-07-09

Related stories