Building Private Web Applications Without Passwords
Eliminate credential databases by combining client-side Secure Remote Password (SRP) protocols with encrypted local state. Learn how to build zero-trust web applications that never store server-side secrets.
The Death of the Credential Database
For decades, the standard security architecture for web applications has relied on a fundamentally flawed primitive: storing hashed and salted user passwords in a centralized relational database. Whether using bcrypt, Argon2id, or PBKDF2, maintaining a table of password verifiers creates a catastrophic honeypot. If an attacker breaches the perimeter and exfiltrates the database, credential stuffing, rainbow table attacks, and offline brute-forcing become matters of compute time rather than possibility.
Passing plaintext credentials over Transport Layer Security to a backend that verifies them against a static store is an outdated design pattern. It places the burden of security on the server, requiring complex rate limiting, account lockout policies, and credential rotation workflows that degrade user experience. It violates the zero-trust principle of modern distributed systems. The server should never possess the secret, nor should it possess the cryptographic material required to impersonate the user.
Moving away from this model requires an architectural shift toward client-side cryptographic protocols and zero-knowledge authentication. By redesigning the authentication boundary, applications can eliminate the password database entirely. The backend transitions from a trusted custodian of secrets to an untrusted verifier of cryptographic proofs. Stripping unnecessary state from the database layer drastically reduces your attack surface and limits blast radii when a perimeter is breached.
The Secure Remote Password Architecture
To eliminate password storage without forcing users to manage hardware tokens or passkeys, production systems can implement the Secure Remote Password protocol, specifically SRP-6a. This protocol allows a client to prove to a server that it knows a password without ever sending the password, or any derivative of it, across the network.
The workflow begins during user registration. The client takes the user's password and a randomly generated salt, computes a verifier using a secure hashing algorithm, and sends only the salt and the verifier to PostgreSQL. The plaintext password is immediately discarded from memory. The server stores the salt and the verifier in a schema that cannot be used to authenticate against other systems, even if leaked.
System Architecture TopologyMermaid Engine
Rendering system architecture diagram...
During authentication, the client initiates a handshake by sending its username. The server responds with its public ephemeral value and the user's salt. Both parties independently compute a shared session key using the password, the salt, and their respective ephemeral values. The client proves possession of the key by sending a cryptographic proof, which the server verifies. At no point during this exchange does the password or a static password hash traverse the wire.
In production deployments using Node.js or Go backends, this avoids the overhead of server-side key derivation functions during high-concurrency login spikes. CPU utilization shifts entirely to the edge clients, protecting the backend cluster from denial-of-service attacks targeting the authentication endpoint. You see direct relief on connection pool exhaustion metrics because bad actors cannot spam CPU-heavy hashing loops on your primary database nodes.
Managing Sessions Without a Password Database
When the server no longer maintains a stateful user table containing passwords, session management and user state isolation require a redesigned architecture. Authentication must transition from session cookies tied to database lookups to cryptographically signed tokens bound to encrypted local storage.
Upon successful completion of the SRP handshake, the server issues a short-lived JSON Web Token signed with an asymmetric Elliptic Curve Digital Signature Algorithm key pair. This token contains user metadata and permission scopes but requires no database validation check on subsequent HTTP requests. Instead, API gateways and Envoy proxies validate the JWT signature at the network edge, dropping unauthorized traffic before it reaches internal microservices.
For user-specific application data, the backend ceases to be the decryption authority. The shared session key derived during the SRP handshake or a secondary key derived via the Web Crypto API is used to encrypt local state within IndexedDB on the client browser. If an attacker compromises the PostgreSQL database, they find only encrypted blobs and SRP verifiers, rendering the data completely opaque without the client-side master key.
This architecture introduces specific failure modes. If a user clears their browser storage, their local encryption keys are lost, requiring account recovery workflows that do not rely on traditional password resets. Recovery must rely on cryptographically secure recovery phrases generated at registration, stored by the user, and verified via zero-knowledge proofs during recovery attempts. If you lose that browser profile, the data is gone. Accept this reality and design your backup UX around it.
Performance Trade-Offs of Client-Side Cryptography
Offloading cryptographic operations to the client browser introduces distinct engineering challenges. SRP calculations, key derivations, and client-side encryption require significant CPU cycles on the user device. On modern desktop hardware, computing an SRP ephemeral proof takes milliseconds. On low-end mobile devices or older smartphones, running heavy cryptographic operations on the main execution thread can freeze the user interface, causing jank and degraded responsiveness.
To mitigate this performance penalty, client-side cryptographic routines must be isolated inside Web Workers. Offloading the heavy lifting of key derivation and proof generation to a background thread keeps the main DOM thread free to render UI updates. However, marshalling data back and forth across the Web Worker boundary introduces serialization latency that must be accounted for in the overall authentication timeout budgets. If your worker hangs past 3000ms, your edge proxies will drop the request with an HTTP 504 Gateway Timeout.
Another trade-off involves network payload sizes and round-trip times. The SRP protocol requires multiple handshake messages between the client and the server before a session is established, unlike a single POST request containing a username and password hash. In environments with high network latency or unstable mobile connections, these additional round trips can noticeably increase time-to-interactive metrics.
Engineers building zero-knowledge web applications must balance absolute cryptographic isolation against user experience constraints. By utilizing optimized WebAssembly modules for underlying cryptographic primitives rather than pure JavaScript implementations, teams can achieve near-native execution speeds on the client side, neutralizing the performance penalties of zero-knowledge architectures while permanently removing the password database from the attack surface.