A passwordless authentication system where the server knows absolutely nothing about your users. Zero honeypots, zero breaches, zero regrets.
I built an authentication system where the server stores zero secrets. No password hashes, no emails, no recovery tokens. The server only knows a
user_idderived from the user'smaster_secret, and authentication is proven cryptographically via HMAC. If the database is breached, there's literally nothing to steal.
π₯ The Problem: Your Auth Database is a Ticking Time Bomb
Let's be brutally honest about modern authentication:
Every authentication system is a honeypot.
Even with Argon2id, bcrypt, or scrypt, you're still storing:
- Password hashes (crackable with enough GPU power)
- Email addresses (for credential stuffing attacks)
- Password reset tokens (if stolen, game over)
- Session tokens (if leaked, instant access)
The AI Multiplier
In 2026, AI has made this 10x worse:
- Pattern Recognition: AI can cross-reference leaked databases in seconds, finding correlations humans would miss
- Smart Dictionary Attacks: AI generates context-aware password guesses based on user profiles
- Automated Credential Stuffing: AI tests millions of leaked credentials across platforms simultaneously
- Social Engineering: AI crafts personalized phishing attacks using leaked data
The uncomfortable truth: If a hacker gets your database, it's not a matter of if they'll exploit it, but how fast.
The Real Question
What if we could build an auth system where there's nothing to steal?
π‘ The Solution: CryptoLogin - Zero-Storage Authentication
The time is now ripe for it
CryptoLogin uses a challenge-response mechanism inspired by Zero-Knowledge principles.
The server never stores your secret. Your secret never leaves your device.
I built CryptoLogin, an authentication system based on a radical principle:
The server should never know anything about the user that the user doesn't explicitly share.
Core Principles
- No secrets on the server - No password hashes, no emails, no recovery tokens
-
Client-side derivation - The
user_idis derived locally from themaster_secretusing PBKDF2 -
HMAC-based authentication - The client proves knowledge of the
master_secretvia cryptographic signature -
Zero-knowledge flow - The
master_secretnever leaves the browser
What the Server Actually Stores
-- That's it. Just a user_id and some metadata.
CREATE TABLE users (
user_id TEXT PRIMARY KEY, -- 64-char hex, derived from master_secret
user_data TEXT, -- Optional JSON metadata
created_at TEXT,
updated_at TEXT,
last_activity_at TEXT,
challenge TEXT -- Temporary, for active login sessions only
);
No passwords. No emails. No secrets. If this database is breached, the attacker gets... a bunch of random-looking hex strings. Useless.
π How It Works: The Zero-Knowledge Flow
The Cryptographic Flow
ββββββββββββ ββββββββββββ
β Client β β Server β
ββββββ¬ββββββ ββββββ¬ββββββ
β 1. Derive user_id from master_secret β
β (PBKDF2-SHA512, 100k iterations) β
β β
β 2. POST /auth/login/init {user_id} β
β βββββββββββββββββββββββββββββββββββββββΊ β
β β 3. Generate challenge
β 4. Return challenge β
β βββββββββββββββββββββββββββββββββββββββ β
β β
β 5. Compute HMAC(challenge, user_id) β
β β
β 6. POST /auth/login/verify β
β {user_id, hmac} β
β βββββββββββββββββββββββββββββββββββββββΊ β
β β 7. Verify HMAC
β 8. Return session β
β βββββββββββββββββββββββββββββββββββββββ β
β β
β
Authenticated β
Session created
Why This is Secure
-
The
master_secretnever leaves the browser - It's only used locally to deriveuser_idand compute HMAC -
The server can't impersonate the user - It doesn't know the
master_secret, only the deriveduser_id - Replay attacks are impossible - Each challenge is single-use and expires after login
-
Database breaches are harmless - The attacker gets
user_idvalues, which are useless without themaster_secret
The Cryptographic Standards
| Component | Algorithm | Purpose |
|---|---|---|
| Key Derivation | PBKDF2-SHA512 (100,000 iterations) | Derive user_id from master_secret
|
| Authentication | HMAC-SHA256 | Prove knowledge of master_secret
|
| Comparison | Constant-time comparison | Prevent timing attacks |
No custom crypto. Everything uses industry-standard algorithms via the Web Crypto API (browser) and Python's hashlib/hmac (server).
π Integration in 5 Minutes
Backend (Python/Flask)
pip install cryptologin
from flask import Flask, request, jsonify
from cryptologin import CryptoLogin
from cryptologin.core.user_manager_v2 import UserManagerV2
from cryptologin.storage.sqlite_v2 import SQLiteStorageV2
app = Flask(__name__)
# Initialize CryptoLogin
storage = SQLiteStorageV2(db_path="auth.db", auto_migrate=True)
user_manager = UserManagerV2(storage=storage)
@app.route('/auth/register_v2', methods=['POST'])
def register():
data = request.json
user_id = data['user_id'] # Derived client-side from master_secret
user_manager.register_user_v2(user_id, data.get('user_data', {}))
return jsonify({"success": True, "user_id": user_id})
@app.route('/auth/login/init_v2', methods=['POST'])
def login_init():
data = request.json
user_id = data['user_id']
challenge = user_manager.initiate_login_v2(user_id) # Returns plaintext challenge
return jsonify({"challenge": challenge})
@app.route('/auth/login/verify_v2', methods=['POST'])
def login_verify():
data = request.json
user_id = data['user_id']
hmac_response = data['challenge_response'] # HMAC from client
session = user_manager.complete_login_v2(user_id, hmac_response)
return jsonify({
"session_id": session.session_id,
"user_id": session.user_id,
"expires_at": session.expires_at.isoformat()
})
Frontend (JavaScript)
npm install cryptologin-client
import { createClient } from 'cryptologin-client';
// Initialize the client
const client = createClient({
baseURL: 'https://api.yourapp.com/v1',
timeout: 30000
});
// Registration (user provides master_secret)
async function register(masterSecret) {
// SDK derives user_id automatically
const userId = await client.register(masterSecret, {
name: 'John Doe',
email: 'john@example.com' // Optional metadata
});
console.log('Registered:', userId);
}
// Login (user provides master_secret)
async function login(masterSecret) {
// SDK handles everything:
// 1. Derives user_id
// 2. Gets challenge from server
// 3. Computes HMAC locally
// 4. Sends HMAC to server
const session = await client.login(masterSecret);
console.log('Logged in:', session.sessionId);
}
// Usage
const masterSecret = 'my-super-secret-passphrase-min-32-chars';
await register(masterSecret);
await login(masterSecret);
That's it. The SDK handles all the cryptography. You just pass the master_secret.
β οΈ The Brutal Truth: Trade-offs
I'm not going to sell you a fantasy. CryptoLogin is not for everyone.
What You Lose
β No "Forgot Password" flow - If the user loses their master_secret, they're locked out forever. The server can't help because it doesn't know the secret.
β No email-based recovery - Since we don't store emails, there's no way to send recovery links.
β User responsibility - Users must store their master_secret securely (password manager, hardware key, etc.)
What You Gain
β
Zero breach risk - If your database is leaked, there's nothing to exploit
β
No password hashing costs - No CPU-intensive bcrypt/Argon2 on every login
β
Simplified compliance - No password storage = no PCI-DSS/GDPR headaches for credentials
β
True user sovereignty - Users own their authentication completely
Who Should Use CryptoLogin?
β
High-security applications - Financial apps, healthcare, enterprise tools
β
Privacy-focused products - Where users demand zero-knowledge architecture
β
Developer tools - Where users are technical enough to manage a master_secret
β
Decentralized apps - Where server-side secrets are an anti-pattern
β Consumer apps with non-technical users - If your users will forget their password, this isn't for you
β Apps requiring email recovery - If you need "Forgot Password", stick with traditional auth
The Bitcoin Analogy
CryptoLogin works like a Bitcoin wallet:
"Not your keys, not your crypto."
"Not your master_secret, not your account."
It's the ultimate trade-off: Absolute security vs. Convenience. You choose.
π Performance & Testing
Test Coverage
β tests/crypto.test.js (18 tests)
β deriveUserId (5 tests)
β computeHmac (5 tests)
β isValidUserId (4 tests)
β generateChallenge (4 tests)
β tests/client.test.js (8 tests)
β constructor (4 tests)
β session management (4 tests)
Test Files 2 passed (2)
Tests 26 passed (26)
Performance Benchmarks
| Operation | Time | Notes |
|---|---|---|
deriveUserId |
~150ms | PBKDF2 with 100k iterations |
computeHmac |
~1ms | HMAC-SHA256 is fast |
| Full login flow | ~200ms | Network + crypto |
Note: The 150ms for deriveUserId is intentional. It's a security feature, not a bug. Slow key derivation makes brute-force attacks expensive.
π― Real-World Demo
I've deployed a live demo where you can test CryptoLogin right now:
π Live Demo: https://erabytse.github.io/cryptologin-website/demo_v2.html
Try it:
- Enter a
master_secret(minimum 32 characters) - Click "Register"
- Click "Login"
- Watch the HMAC-based authentication in action
The demo connects to a real API endpoint: https://api.docudeeper.com/api/v1
π Links & Resources
Packages
- Python SDK (Server): cryptologin on PyPI
- JavaScript SDK (Client): cryptologin-client on npm
Source Code
- Backend (Python): github.com/erabytse/CryptoLogin
- Frontend (JavaScript): github.com/erabytse/cryptologin-client
- Demo Website: github.com/erabytse/cryptologin-website
Documentation
- Website: https://erabytse.github.io/cryptologin-website/
- API Docs: See README on GitHub repos
π€ Contributing
CryptoLogin is open-source under the MIT License. Contributions are welcome!
Areas where we need help:
- π§ͺ More test coverage
- π Documentation improvements
- π SDKs for other languages (Rust, Go, PHP)
- π¨ UI/UX improvements for the demo
π¬ Final Thoughts
Authentication doesn't have to be a compromise between security and usability. With CryptoLogin, we've proven that you can build a system where:
- The server knows nothing about the user's secret
- Authentication is cryptographically proven via HMAC
- Database breaches are harmless because there's nothing to steal
- Integration is trivial thanks to well-designed SDKs
Is it for everyone? No. But for the right use case, it's a game-changer.
The future of auth isn't about building better honeypots. It's about removing the honey.
If you found this useful, give the repos a β on GitHub and share it with your network. Let's build a more secure web, one zero-knowledge system at a time.
Questions? Drop them in the comments. I read everything.
Built with β€οΈ by erabytse
Reinventing Authentication. One Secret at a Time.
A quiet rebellion against digital waste.

Top comments (0)