A self-hosted, zero-knowledge, multi-user 2FA/TOTP authenticator. The Google Authenticator replacement that you own and control. Every OTP secret is encrypted on your device before it ever reaches the server.
Kripta is a private vault for your two-factor authentication codes. Add accounts by scanning a QR code, uploading a QR image, or entering the secret manually, then generate TOTP and HOTP codes on any device you sign in from.
Unlike most authenticators, Kripta is zero-knowledge: your master password, encryption keys, and OTP secrets never leave the browser in plaintext. The server only ever stores hashes and ciphertext, so even a compromised server, or a curious administrator, cannot read your codes.
Most authenticators either lock your secrets to a single device or hand your data to a third-party cloud. Kripta gives you both convenience and control:
- Zero-knowledge by design. Secrets are encrypted client-side with a key derived from your password. The server sees only ciphertext.
- Self-hosted. Run it on your own infrastructure with Docker and PostgreSQL.
- Multi-user. One installation for your whole team, with invite-based provisioning and role-based access.
- Synced across devices. Open the same vault from anywhere by signing in. No manual export or import.
- Flexible entry. Add accounts via QR scan (camera), QR image upload, or manual input. Supports TOTP and HOTP, SHA-1/256/512, 6 to 8 digits, and custom periods.
- Fast day-to-day use. Real-time codes with a countdown ring, one-click copy, drag-to-reorder, and a command palette (
Cmd/Ctrl+K) for instant search and copy. - First-run setup wizard. Create the superadmin account the first time you deploy.
- Invitations. Add users with optional email pinning, User or Superadmin roles, and link expiry.
- Mandatory recovery codes. The only way to recover access if you forget your password. The server cannot reset it for you.
- Admin dashboard. Manage users, invitations, and a full audit log.
- Account management. Change your password without re-encrypting items, review and revoke active sessions.
- Polished UI. English and Bahasa Indonesia, light and dark themes, responsive layout (desktop sidebar, mobile bottom navigation).
| Vault (light) | Command palette |
![]() |
![]() |
| Settings and language | Admin audit log |
![]() |
![]() |
Kripta uses a Bitwarden-style key hierarchy, derived entirely on the client:
flowchart TD
PW["Master password"] -->|"Argon2id + salt"| MK["masterKey"]
MK -->|"HKDF"| SK["stretchedKey"]
MK -->|"SHA-256"| AH["authHash"]
RC["Recovery code"] -->|"HKDF"| RK["recoveryKey"]
VK(["vaultKey (random 32 bytes)"])
SK -->|"AES-GCM wrap"| PVK["protectedVaultKey"]
VK --> PVK
RK -->|"AES-GCM wrap"| PVKR["protectedVaultKeyByRecovery"]
VK --> PVKR
VK -->|"AES-GCM, per item"| CT["OTP ciphertext"]
AH --> AHH["Argon2id(authHash)"]
subgraph SERVER["Stored on the server: ciphertext and hashes only"]
AHH
PVK
PVKR
CT
end
What the server stores: Argon2id(authHash), Argon2id(recoveryAuthHash), KDF salt and parameters (public), protectedVaultKey, protectedVaultKeyByRecovery, and item ciphertext. It never stores passwords, secrets, or keys in plaintext.
Additional hardening:
- Database-backed sessions that can be revoked, with
httpOnly+Secure+SameSite=Strictcookies and idle plus absolute timeouts. - CSRF protection with a session-bound double-submit token, plus origin checks.
- Rate limiting and exponential account lockout on login, invites, and recovery, with user-enumeration mitigation at prelogin.
- Strict security headers including a nonce-based Content Security Policy, HSTS,
X-Frame-Options,X-Content-Type-Options, andReferrer-Policy. - Argon2id for server hashing and client KDF (at least 64 MiB memory),
zodinput validation, ownership checks on every endpoint, and an audit log that never records secrets.
Accepted trade-off: codes are generated only in the browser, and forgetting your password without a recovery code means the data is permanently lost. That is the price of true zero-knowledge.
Prerequisites: Docker and Docker Compose.
git clone https://github.com/idhin/kripta.git
cd kripta
# Create the .env file used by docker compose (change the password!)
cat > .env <<'EOF'
POSTGRES_USER=kripta
POSTGRES_PASSWORD=change-this-to-a-strong-password
POSTGRES_DB=kripta
APP_URL=http://localhost:28347
AUTH_COOKIE_SECURE=false
APP_PORT=28347
EOF
docker compose up -d --buildOpen http://localhost:28347. You will be redirected to /install to create the superadmin. Save the recovery code that is shown.
The default host port is intentionally uncommon (
28347) so it will not clash with other services on your server. ChangeAPP_PORT(andAPP_URLto match) to anything you like. The containers are namedkripta-appandkripta-db.
Production: put Kripta behind an HTTPS reverse proxy (Caddy, Nginx, or Traefik), then set
APP_URL=https://your-domainandAUTH_COOKIE_SECURE=true.
Prerequisites: Node 20+, and PostgreSQL (or the docker run command below).
npm install
# Run a local Postgres
docker run -d --name kripta-pg \
-e POSTGRES_USER=kripta -e POSTGRES_PASSWORD=kripta -e POSTGRES_DB=kripta \
-p 5432:5432 postgres:16-alpine
cp .env.example .env # adjust DATABASE_URL if needed
npm run db:migrate # apply migrations
npm run dev # http://localhost:3000Useful scripts: npm run db:studio (Prisma Studio), npm run db:deploy (production migrations), npm run build && npm start.
| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | postgresql://kripta:kripta@localhost:5432/kripta?schema=public |
APP_URL |
Public app URL, used for origin checks and invite links | http://localhost:3000 |
AUTH_COOKIE_SECURE |
Set to true only when served over HTTPS |
false |
SESSION_ABSOLUTE_TTL |
Absolute session lifetime, in seconds | 2592000 (30 days) |
SESSION_IDLE_TTL |
Idle session lifetime, in seconds | 43200 (12 hours) |
APP_PORT |
Host port published by Docker Compose (container listens on 3000) | 28347 |
Just back up the database. It only contains ciphertext and hashes:
docker compose exec db pg_dump -U kripta kripta > kripta-backup.sqlNext.js 14 (App Router), React, TypeScript, Tailwind CSS, Zustand, Prisma, PostgreSQL, @node-rs/argon2 (server), hash-wasm and Web Crypto (client), otpauth, qr-scanner, and zod.
Issues and pull requests are welcome. If you find a security concern, please open a private report rather than a public issue.
MIT © Khulafaur Rasyidin. See LICENSE.



