DEV Community

Hassan Magdy
Hassan Magdy

Posted on

How I Built a Zero-Knowledge 2FA Authenticator Using Rust, Tauri, and React

Are you tired of being locked out of your accounts when you reset your phone? I was. I wanted a 2FA authenticator that would sync my codes seamlessly across devices, but I didn't want to hand over my plaintext secrets to a closed-source cloud provider.

So, I built OtpVault β€” an open-source, truly zero-knowledge 2FA application.

In this post, I want to share the architecture, the tech stack, and how I approached the security model.

πŸ› οΈ The Tech Stack
To make this work across Desktop (Windows), Android, and the Web (PWA), I needed a flexible yet highly secure stack:

Backend / Core Logic: Rust (Using aes-gcm, argon2, and totp-rs). Rust ensures memory safety and handles the heavy cryptographic lifting.

Desktop & Android Framework: Tauri v2. It allows wrapping the Rust backend with a web frontend natively and beautifully.

Frontend: React 19 + Vite + Tailwind CSS.

Cloud API: Neon PostgreSQL via Vercel Serverless.

πŸ”’ The Zero-Knowledge Architecture
The core philosophy of OtpVault is simple: The server must never see the plaintext data.

Here is how the email-based authentication flow works:

Local Key Derivation: When you sign up or log in, your password and a randomly generated 32-byte salt are fed into Argon2id strictly on the client side (in Rust). This generates a strong 256-bit AES key.

Vault Encryption: Your entire vault of 2FA secrets is encrypted locally using AES-256-GCM.

Cloud Sync: The application sends a POST request to the Supabase/Neon REST API. The payload only contains your email, the salt, a test payload (to verify passwords later), and the opaque encrypted vault blob.

If the database is ever breached, the attacker gets nothing but meaningless, encrypted strings.

πŸ”„ Solving the Cross-Platform Sync Problem
One of the coolest challenges was keeping the Desktop, Android, and PWA versions in sync without compromising the encryption.

I implemented a real-time polling mechanism (every 10 seconds). The Rust HTTP client fetches the encrypted vault from the Vercel API, decrypts it locally using the master key in memory, parses the JSON, merges any new accounts, re-encrypts, and pushes it back.

I even had to build a format converter on the fly, because the Android version stores secrets as secret_encrypted (base64 salt+nonce+ciphertext), while the PWA handles plaintext secrets in memory before encrypting the entire vault layer.

πŸ›‘οΈ Ironclad Features
Delete Confirmation: To prevent accidental deletion, users must re-enter their master password before removing any 2FA account.

Optimized Mobile QR Scanner: Using jsQR and requestAnimationFrame, the scanner pulls frames at a low JPEG quality (saving battery and processing at ~30KB/frame) while remaining blazing fast.

🀝 Check it Out!
Building OtpVault was an incredible journey into Rust cryptography and Tauri’s cross-platform capabilities. I’d love for the community to check it out, audit the code, or use it to secure your accounts.

GitHub Repository: [https://github.com/Shadow132245/OtpVault]

Website / Try it out: [https://otpvault1.vercel.app]

I'm open to any feedback, feature requests, or contributions. Let me know what you think of the architecture!

Top comments (0)