A secure, zero-knowledge password manager with end-to-end encryption, TOTP-based 2FA support, featuring a web app and browser extension.
- Zero-Knowledge Architecture: All encryption/decryption happens client-side. Server never sees plaintext passwords.
- End-to-End Encryption: AES-256-GCM encryption using Web Crypto API
- Strong Key Derivation: PBKDF2 with 100,000 iterations for master password
- Multi-Factor Authentication: TOTP-based 2FA support
- Secure Password Hashing: Bcrypt with configurable rounds for server-side authentication
- Account Lockout: Protection against brute force attacks
- Rate Limiting: API rate limiting to prevent abuse
- React 18 with TypeScript
- Vite for blazing-fast development
- Shadcn/UI for beautiful, accessible components
- TailwindCSS for styling
- React Router for navigation
- Tanstack Query for data fetching
- Web Crypto API for client-side encryption
- Node.js with Express
- TypeScript for type safety
- MySQL/MariaDB for data persistence
- JWT for stateless authentication
- bcrypt for password hashing
- otplib for TOTP generation/verification
- Manifest V3 for Chromium browsers
- Auto-fill capabilities for login forms
- Auto-lock with configurable timeout
- Zero-knowledge architecture (same as web app)
- Offline decryption (vault cached in memory)
Docker (recommended):
- Docker Engine 20+ with Compose plugin
Manual install:
- Node.js 18+
- MySQL or MariaDB 10+
- npm or yarn
The fastest way to get Keyphra running. One command spins up the frontend, backend, and MySQL database:
git clone https://github.com/ganry/keyphra.git
cd keyphra
docker compose up -dYour vault is live at http://localhost:5173
For production, copy the env template and set secure values:
cp .env.example .envEdit .env:
DB_PASSWORD=your_secure_db_password
JWT_SECRET=your_random_secret_min_32_charsGenerate a secure JWT secret:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Then restart:
docker compose up -d
⚠️ The default setup uses built-in credentials for convenience. Always set your ownDB_PASSWORDandJWT_SECRETvia.envbefore exposing to the internet.
docker compose up -d # Start all services
docker compose down # Stop all services
docker compose logs -f # View logs
docker compose down -v # Stop and remove database volume# Install root dependencies
npm install
# Install all workspace dependencies
npm run install:allCreate a MySQL/MariaDB database:
CREATE DATABASE keyphra_pw_manager CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;Copy the example environment file:
cp backend/.env.example backend/.envEdit backend/.env:
# Server
PORT=3001
NODE_ENV=development
# Database
DB_HOST=localhost
DB_PORT=3306
DB_USER=your_db_user
DB_PASSWORD=your_db_password
DB_NAME=keyphra_pw_manager
# JWT - IMPORTANT: Generate a secure random string!
JWT_SECRET=your_jwt_secret_min_32_chars_long_random_string
JWT_EXPIRES_IN=24h
# Security
BCRYPT_ROUNDS=12
MAX_LOGIN_ATTEMPTS=5
LOCKOUT_DURATION=900000
# CORS
FRONTEND_URL=http://localhost:5173node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Copy the example environment file:
cp frontend/.env.example frontend/.envEdit frontend/.env:
VITE_API_URL=http://localhost:3001/apicd backend
npm run migrateThis will create the necessary tables:
users- User accounts with encrypted master passwordsvault_items- Encrypted password entriesaudit_logs- Security audit trail
Run both frontend and backend concurrently:
npm run devOr run them separately:
# Terminal 1 - Backend
npm run dev:backend
# Terminal 2 - Frontend
npm run dev:frontendThe application will be available at:
- Frontend: http://localhost:5173
- Backend API: http://localhost:3001
- Navigate to http://localhost:5173/register
- Enter your email and create a strong master password
- Important: Your master password cannot be recovered. Store it securely!
- Optionally add a password hint
- Navigate to http://localhost:5173/login
- Enter your email and master password
- If 2FA is enabled, enter your TOTP code
- Add Password: Click "Add Password" button
- View Password: Click the eye icon to reveal
- Copy Password: Click the copy icon
- Edit Password: Click the edit button
- Delete Password: Click the trash icon
- Search: Use the search bar to filter passwords
- After logging in, go to Settings (coming soon in UI)
- Scan the QR code with your authenticator app (Google Authenticator, Authy, etc.)
- Enter the 6-digit code to confirm
keyphra-pw-manager/
├── backend/
│ ├── src/
│ │ ├── config/ # Database and app configuration
│ │ ├── controllers/ # Request handlers
│ │ ├── middleware/ # Express middleware (auth, etc.)
│ │ ├── models/ # Data models
│ │ ├── routes/ # API routes
│ │ ├── services/ # Business logic
│ │ ├── types/ # TypeScript types
│ │ ├── utils/ # Utility functions
│ │ └── server.ts # Express app entry point
│ └── package.json
├── frontend/
│ ├── src/
│ │ ├── components/ # React components
│ │ │ └── ui/ # Shadcn/UI components
│ │ ├── contexts/ # React contexts
│ │ ├── hooks/ # Custom hooks
│ │ ├── pages/ # Page components
│ │ ├── services/ # API services
│ │ ├── types/ # TypeScript types
│ │ ├── utils/ # Utility functions (crypto, etc.)
│ │ ├── App.tsx # Main app component
│ │ └── main.tsx # Entry point
│ └── package.json
├── browser-extension/ # Chrome/Edge extension
│ ├── manifest.json # Extension config
│ ├── background/ # Service worker
│ ├── popup/ # Extension UI
│ ├── content/ # Auto-fill scripts
│ ├── scripts/ # Crypto & API
│ └── README.md # Extension docs
└── package.json
-
Registration:
- User creates master password (never sent to server in plaintext)
- Master password is hashed client-side with SHA-256 for authentication
- Server stores bcrypt hash of the client-side hash
- Encryption key is derived using PBKDF2 (100k iterations)
-
Login:
- User enters master password
- Client hashes password and sends hash to server
- Server verifies hash with bcrypt
- Server returns JWT token
- Master password stays in memory (not localStorage) for encryption
-
Storing Passwords:
- User enters password to store
- Client encrypts password with AES-256-GCM using derived key
- Encrypted data (salt + IV + ciphertext) sent to server
- Server stores encrypted data without decryption capability
-
Retrieving Passwords:
- Client requests encrypted passwords from server
- Client decrypts using master password in memory
- Plaintext passwords never sent over network
- ✅ Master password never leaves the client
- ✅ Server cannot decrypt user passwords
- ✅ End-to-end encryption
- ✅ Secure key derivation (PBKDF2)
- ✅ Strong encryption (AES-256-GCM)
- ✅ Password strength indicators
- ✅ Account lockout protection
- ✅ Rate limiting
- ✅ JWT-based stateless authentication
- ✅ TOTP-based 2FA
cd backend
npm run dev # Start with auto-reload
npm run build # Build for production
npm run start # Start production server
npm run migrate # Run database migrationscd frontend
npm run dev # Start Vite dev server
npm run build # Build for production
npm run preview # Preview production buildcp .env.example .env
# Edit .env with secure DB_PASSWORD and JWT_SECRET
docker compose up -dMigrations run automatically on startup. See the Quick Start with Docker section for details.
npm run buildSet production environment variables:
- Generate secure JWT_SECRET
- Use production database credentials
- Set NODE_ENV=production
- Configure proper CORS origins
Run migrations in production:
cd backend
npm run migrateBackend:
cd backend
npm run startFrontend:
Serve the frontend/dist directory with a static file server (nginx, Apache, etc.)
- Change all default secrets
- Enable HTTPS/TLS
- Configure firewall rules
- Set up regular database backups
- Enable audit logging
- Configure rate limiting
- Set up monitoring and alerts
- Review and harden CORS settings
POST /api/auth/register- Register new userPOST /api/auth/login- Login userPOST /api/auth/totp/setup- Setup TOTP (requires auth)POST /api/auth/totp/enable- Enable TOTP (requires auth)POST /api/auth/totp/disable- Disable TOTP (requires auth)
GET /api/vault- Get all vault items (requires auth)GET /api/vault/:id- Get single vault item (requires auth)POST /api/vault- Create vault item (requires auth)PUT /api/vault/:id- Update vault item (requires auth)DELETE /api/vault/:id- Delete vault item (requires auth)GET /api/vault/search?q=query- Search vault items (requires auth)GET /api/vault/folders- Get all folders (requires auth)
A full-featured Chrome/Edge extension is included for seamless password management across the web.
- 🔐 Auto-fill login forms automatically
- ⏰ Auto-lock with configurable timeout (5min - 4hrs)
- 🌐 Site matching - automatically detect passwords for current website
- 🔒 Zero-knowledge - same security as web app
- ⚙️ Configurable API - connect to your backend
- Navigate to
chrome://extensions/ - Enable Developer mode
- Click "Load unpacked"
- Select the
browser-extensionfolder - Configure API URL in extension settings
- Login and start using!
📖 Full documentation: See browser-extension/README.md
- Master Password: Cannot be recovered. Users must remember it or store it securely.
- Backup: Regular database backups are crucial but won't help users who forget their master password.
- HTTPS: Always use HTTPS in production to protect data in transit.
- JWT Secret: Use a cryptographically secure random string, minimum 32 characters.
- Database Access: Restrict database access to the backend server only.
- Updates: Keep all dependencies updated to patch security vulnerabilities.
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
MIT License - see the LICENSE file for details.
This project is open source and free to use for personal and commercial purposes.
For issues or questions:
- Check the documentation for technical details
- Review error logs
- Open an issue on GitHub
- Built with Shadcn/UI for the component library
- Encryption powered by Web Crypto API
- TOTP implementation using otplib
Remember: This password manager implements zero-knowledge encryption. If you forget your master password, your data cannot be recovered. Store your master password securely!
