A secure, self-hosted password vault with encrypted storage. Built with React, FastAPI, and PostgreSQL.
- π Secure password storage with AES-256-GCM encryption
- π Per-user encryption keys derived from master key using HKDF
- π‘οΈ Argon2id password hashing for user authentication
- πͺ HttpOnly cookies for session management
- π¨ Modern, futuristic UI with black/purple theme
- π One-click copy to clipboard
- π Search functionality to quickly find accounts
- π³ Docker-first deployment
- User passwords are hashed using Argon2id with secure parameters
- Sessions are managed via JWT tokens stored in HttpOnly cookies
- SameSite=Lax cookie policy for CSRF protection
- All vault passwords are encrypted using AES-256-GCM (authenticated encryption)
- A master key is provided via environment variable
- Per-user keys are derived from the master key using HKDF with user ID as context
- This limits the blast radius: even if a user's data is compromised, other users' data remains secure
- Each encryption uses a random 12-byte nonce stored alongside the ciphertext
Master Key (env) β HKDF(user_id) β User Key β AES-GCM(password, nonce) β Ciphertext
| Data | Protection |
|---|---|
| User passwords | Argon2id hash (never stored in plaintext) |
| Vault passwords | AES-256-GCM encrypted (never stored in plaintext) |
| Session tokens | HttpOnly cookies (not accessible to JavaScript) |
- Docker and Docker Compose
- Python 3.11+ (for key generation)
cd NyxVault
# Copy environment template
cp .env.example .env# Generate master encryption key (32 bytes, base64)
python -c "import secrets, base64; print(base64.b64encode(secrets.token_bytes(32)).decode())"
# Generate JWT secret key
python -c "import secrets; print(secrets.token_urlsafe(32))"Edit .env and fill in:
VAULT_MASTER_KEY: The base64 key from first commandJWT_SECRET_KEY: The key from second commandPOSTGRES_PASSWORD: A secure database passwordINITIAL_PASSWORD: Initial admin password
docker compose up --build- Frontend: http://localhost:3000
- API Docs: http://localhost:8000/docs
- Login: Use the credentials from
INITIAL_USERNAMEandINITIAL_PASSWORD
cd backend
pip install -r requirements.txt
pytest -vNyxVault/
βββ backend/
β βββ app/
β β βββ auth/ # Authentication module
β β βββ crypto/ # Encryption utilities
β β βββ vault/ # Vault CRUD operations
β β βββ main.py # FastAPI application
β β βββ config.py # Settings from environment
β β βββ db.py # Database configuration
β β βββ models.py # SQLAlchemy models
β β βββ schemas.py # Pydantic schemas
β βββ alembic/ # Database migrations
β βββ tests/ # Pytest tests
β βββ Dockerfile
βββ frontend/
β βββ src/
β β βββ api/ # API client
β β βββ components/ # React components
β β βββ context/ # React contexts
β β βββ pages/ # Page components
β β βββ types/ # TypeScript types
β βββ Dockerfile # Dev Dockerfile
β βββ Dockerfile.prod # Production Dockerfile
βββ docker-compose.yml # Development compose
βββ docker-compose.prod.yml # Production compose
βββ .env.example
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/login |
Login with username/password |
| POST | /api/auth/logout |
Clear session |
| GET | /api/auth/me |
Get current user |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/vault/items |
List all items (with optional ?query=) |
| POST | /api/vault/items |
Create new item |
| GET | /api/vault/items/{id} |
Get item details (password masked) |
| PUT | /api/vault/items/{id} |
Update item |
| DELETE | /api/vault/items/{id} |
Delete item |
| POST | /api/vault/items/{id}/reveal |
Get decrypted password |
Migrations run automatically on backend startup. To run manually:
# Inside backend container
docker compose exec backend alembic upgrade head
# Create new migration
docker compose exec backend alembic revision --autogenerate -m "description"# Build and run production containers
docker compose -f docker-compose.prod.yml up --build -d# Required for production
VAULT_MASTER_KEY=<strong-32-byte-base64-key>
JWT_SECRET_KEY=<strong-secret>
POSTGRES_PASSWORD=<strong-database-password>
INITIAL_PASSWORD=<strong-admin-password>
CORS_ORIGINS=https://your-domain.com
DEBUG=false- Use strong, unique values for all secrets
- Enable HTTPS (use a reverse proxy like Traefik or Caddy)
- Set
CORS_ORIGINSto your actual domain - Change the initial admin password after first login
- Store
.envsecurely (never commit to version control) - Regularly backup the PostgreSQL volume
- FastAPI - Modern Python web framework
- SQLAlchemy 2.0 - ORM with async support
- Alembic - Database migrations
- PostgreSQL - Database
- Argon2 - Password hashing
- Cryptography - AES-GCM encryption
- React 18 - UI library
- TypeScript - Type safety
- Vite - Build tool
- TailwindCSS - Styling
- React Router - Client-side routing
- Docker - Containerization
- Docker Compose - Multi-container orchestration
- Nginx - Production static file serving
MIT License - See LICENSE for details.