In this case, during signup, based on a password, the client generates an RSA key pair and sends the public key to the server. The private key and password are never sent—they remain on the client.
During login, the client regenerates the RSA key pair using the password. The server then sends a random challenge (binary array), which the client signs with the RSA private key. The resulting signature is sent back to the server, which verifies it using the stored public key.
The browser’s SubtleCrypto API was the first option considered for key generation. Here’s an example of generating an RSA key pair using this API:
For more details, see [https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey](MDN’s SubtleCrypto) documentation.
To address this limitation, we turned to Rust, which supports deterministic RSA key generation via libraries like rsa and rand. Combining Rust with WebAssembly (WASM) allowed us to expose this functionality to the browser.