Open source, self-hosted alternative to Google Authenticator, Authy, 2FAS & Aegis. Privacy-focused TOTP / HOTP authenticator with encrypted sync across Windows, macOS, Linux, iOS, Android & browser — you own the server, you own the data.
SelfHostAuth is a self-hosted 2FA authenticator that syncs your TOTP & HOTP one-time codes across every device without trusting Google, Authy, or any third-party cloud. Run the lightweight Node.js + SQLite sync server on your home server, NAS, Raspberry Pi, or VPS, and access your 2FA codes from a browser Web UI, native desktop app (Electron), mobile app (iOS/Android via bare React Native — 100% OSS, no Expo), and browser extension (Chrome/Edge/Firefox MV3) — all offline-capable and end-to-end encrypted at rest.
Keywords: self-hosted authenticator, self-hosted 2FA, open source 2FA, TOTP server, HOTP, OTP authenticator, 2FA sync, privacy authenticator, Google Authenticator alternative, Authy alternative
| Feature | SelfHostAuth (self-hosted) | Google Authenticator | Authy (Twilio) | 2FAS / Aegis |
|---|---|---|---|---|
| Own your data | ✅ Your server, your SQLite DB | ❌ Google cloud | ❌ Twilio cloud | |
| Cross-device sync | ✅ Encrypted, revision-based | ✅ (since 2023) | ✅ | |
| Open source | ✅ MIT, fully auditable | ❌ | ❌ | ✅ |
| Offline codes | ✅ Cached + local TOTP | ✅ | ✅ | ✅ |
| Desktop (Win/Mac/Linux) | ✅ Electron (NSIS/DMG/AppImage, deb, rpm) | ❌ | ❌ (discontinued) | ❌ |
| Browser extension | ✅ MV3 (Chrome/Edge/Firefox) | ❌ | ❌ | ❌ |
| Web UI | ✅ Served from your server at / |
❌ | ❌ | ❌ |
| Self-host anywhere | ✅ Docker, bare metal, Raspberry Pi, NAS | — | — | — |
Perfect for: homelabbers, privacy advocates, teams that need a self-hosted OTP / 2FA server, and anyone searching for a Google Authenticator self-hosted alternative or Authy replacement.
- RFC-compliant TOTP / HOTP — RFC 4226 / RFC 6238, SHA-1 / SHA-256 / SHA-512, 6–8 digits, any period
- Import via QR / otpauth:// — scan or paste a QR-code URI or raw base32 secret
- AES-256-GCM vault encryption at rest — every secret encrypted on your server; key in a file you control (
ENCRYPTION_KEY) - Secure auth —
scryptpasswords, SHA-256 hashed tokens, sliding sessions, rate limiting, optional TOTP 2FA on the account itself - Revision-based sync — push/pull with last-write-wins + tombstones, so delete on one device deletes everywhere
- Offline-first — clients cache the vault locally and compute TOTP without the server (pure-JS HMAC fallback for React Native)
- Zero native deps on the server — Node 22+ built-in
node:sqlite+node:crypto; <50 MB Docker image - Web vault — full TOTP vault at
https://your-host/— no install needed, served directly from your Docker image - Runs anywhere — Docker Compose, systemd, bare metal on Windows, macOS, and 8+ Linux distros (Ubuntu, Debian, Fedora, Arch, etc. via AppImage/deb/rpm)
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌─────────────┐
│ Desktop │ │ Mobile │ │ Extension │ │ Mobile │ │ Desktop │
│ (Electron) │ │ (iOS/Android)│ │ Chrome/FF │ │ (iOS) │ │ (macOS/Linux)│
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘
│ │ │ │ │
└───────────────┴───────────────┴───────────────┴───────────────┘
▲ HTTPS (Caddy / reverse proxy)
│
┌─────────┴──────────┐
│ Your 2FA Server │
│ Node + SQLite │
│ AES-256-GCM at rest│
│ scrypt passwords │
└────────────────────┘
| Path | What it is |
|---|---|
packages/core |
TOTP/HOTP engine, otpauth parsing, AES-GCM crypto, types — zero deps, runs everywhere |
packages/client |
Typed TypeScript API client for the sync server |
apps/server |
Self-hosted 2FA sync server (Fastify + SQLite) — the brain |
apps/desktop |
Desktop authenticator — Electron for Windows / macOS / Linux |
apps/extension |
Browser extension — Chrome / Edge / Firefox (Manifest V3) |
apps/mobile |
Mobile 2FA app — bare React Native 0.76 for iOS & Android (fully OSS) |
apps/web |
Web vault — Vite SPA served from the server at / (no separate deploy) |
docker |
Dockerfile, docker-compose.yml, Caddyfile, systemd unit |
Prereqs: Node.js ≥ 22 and pnpm ≥ 9 (corepack enable).
# 1. Install, build, and test (validates RFC 4226/6238 vectors)
pnpm install
pnpm build
pnpm test
# 2. Start the self-hosted server
cd apps/server
pnpm start # http://0.0.0.0:8787 • data in ./dataVerify your self-hosted TOTP server is up:
curl http://127.0.0.1:8787/api/v1/info
# {"name":"selfhostauth","version":"0.1.6","features":{"sync":true,...}}
# Web vault is at http://127.0.0.1:8787/ (served from the same container)Docker already includes the Web UI —
https://your-host/is your vault. No separate frontend deployment.
pnpm dev:desktop # dev with HMR
pnpm build:desktop # production build
cd apps/desktop
pnpm package:win # → NSIS .exe (Windows)
pnpm package:mac # → DMG (macOS, run on Mac)
pnpm package:linux # → AppImage + .deb + .rpm (run on Linux)
# Or download prebuilt installers from ReleasesOpen the app → point it at your server URL → Register → start adding your 2FA codes.
Just open https://your-host/ — the Docker image serves apps/web at /. Log in, search, add via otpauth:// or base32, copy codes with one click, and sync. Works on any browser; data stays in your server's SQLite + your browser's localStorage cache. No separate deploy.
# Local dev (proxies /api to the server):
cd apps/web && pnpm dev # → http://localhost:5174cd apps/extension
pnpm build # → dist/
# pnpm package → selfhostauth-extension.zip- Chrome / Edge:
chrome://extensions→ Developer mode → Load unpacked →apps/extension/dist - Firefox:
about:debugging→ This Firefox → Load Temporary Add-on →manifest.json - Click the toolbar icon → ⚙ → enter your server URL + credentials.
Requests host permission for your server origin on first connect (MV3 security model).
No Expo, no vendor lock-in — pure React Native 0.76 + @react-native-clipboard/clipboard. Requires Xcode (iOS) or Android Studio + JDK 17.
cd apps/mobile
pnpm install
# iOS — install pods, then run on simulator/device
cd ios && pod install && cd ..
pnpm run ios # or: npx react-native run-ios
# Android — builds an APK with Gradle
pnpm run android # or: npx react-native run-android
# Or build release artifacts directly
cd android && ./gradlew assembleRelease # → app/build/outputs/apk/release/
cd ios && xcodebuild -workspace selfhostauth.xcworkspace -scheme selfhostauth -configuration Release -sdk iphonesimulator -derivedDataPath ../build CODE_SIGNING_ALLOWED=NO buildNative projects (android/ / ios/) are committed (no Expo prebuild). CI builds both on every workflow_dispatch via .github/workflows/mobile-local.yml. TOTP works offline via the pure-JS HMAC fallback in packages/core.
cd docker
# Generate a stable vault key (keep it safe — lose it and the vault is unrecoverable)
export ENCRYPTION_KEY=$(node -e "console.log(require('crypto').randomBytes(32).toString('base64'))")
docker compose up -dYour self-hosted 2FA server is now at http://localhost:8787. Put it behind Caddy (see docker/Caddyfile) or any reverse proxy for HTTPS — required for mobile apps and browser extensions on non-localhost.
cd apps/server
npm i -g pnpm && pnpm install && pnpm build
ENCRYPTION_KEY=<32-byte-base64> DATA_DIR=/var/lib/selfhostauth PORT=8787 pnpm startA systemd unit is included at docker/selfhostauth.service:
sudo cp docker/selfhostauth.service /etc/systemd/system/
sudo systemctl enable --now selfhostauth| Variable | Default | Purpose |
|---|---|---|
PORT |
8787 |
HTTP port |
HOST |
0.0.0.0 |
Bind address |
DATA_DIR |
./data |
SQLite DB + auto-generated encryption.key |
ENCRYPTION_KEY |
auto-generated | 32-byte base64 AES key — set it for multi-instance / backup stability |
ALLOW_REGISTRATION |
true |
Set false to disable open signup (private server) |
SESSION_TTL_DAYS |
30 |
Session lifetime (sliding) |
RATE_LIMIT_PER_MINUTE |
20 |
Per-IP auth rate limit |
Every finding is disclosed in VULNERABILITIES.md — source deps, built executables, and Docker image — updated on every push and weekly by CI (.github/workflows/vuln.yml). No finding is hidden. Run pnpm vuln:check locally for the same report.
- Passwords:
scrypt(N=16384, r=8, p=1) with per-user salt — resistant to GPU cracking. - Vault at rest: AES-256-GCM per item; key is the server's
encryption.key(file orENCRYPTION_KEYenv). Stealing the DB without the key is useless. - Sessions: 64-char random tokens, stored only as SHA-256 hashes, sliding expiry.
- Account 2FA: optional TOTP required at login when enabled.
- In transit: TLS via your reverse proxy; no unauthenticated API.
- Local computation: clients compute TOTP locally — the server is never asked for codes during normal use (
/verifyexists only for testing/CI).
Roadmap: client-side E2E encryption (master password), WebAuthn passkeys, family sharing, additional OTP types, push notifications. PRs welcome.
pnpm build # build all packages/apps (topological order)
pnpm typecheck # desktop + mobile + extension
pnpm test # core RFC vectors (12) + server API (9) = 21 tests
pnpm dev:server # server watch mode
pnpm dev:desktop # Electron + Vite HMR
pnpm dev:extension # rebuild extension on change
pnpm --filter @selfhostauth/mobile start # bare React Native MetroThe core library is validated against official RFC 4226 (HOTP), RFC 6238 (TOTP) and RFC 4231 (HMAC) test vectors for SHA-1, SHA-256 and SHA-512, including the pure-JS fallback path used on React Native (no WebCrypto).
Every push runs on Ubuntu / Windows / macOS × Node 22 & 24: build → typecheck → test → live smoke test. Tags v* publish:
- Desktop installers to the GitHub Release (Win NSIS, macOS DMG, Linux AppImage/deb/rpm)
- Server Docker image to
ghcr.io/wildfirebill-security/selfhostauth - Extension zip + mobile APK / iOS simulator build via bare React Native (Gradle / Xcode) — no Expo required
See .github/workflows/ for details.
Is this a Google Authenticator alternative I can self-host?
Yes — SelfHostAuth is a drop-in, open source alternative to Google Authenticator and Authy that you host yourself for full privacy and no vendor lock-in. Import your existing otpauth:// URIs in one paste.
Can I self-host my 2FA codes? Is it safe?
Yes. Your TOTP secrets never leave your infrastructure unencrypted. They are AES-256-GCM encrypted at rest and your server is the only copy unless you enable backups. Use HTTPS + a strong ENCRYPTION_KEY.
What platforms are supported?
Server: Windows, macOS, and 8+ Linux distros (anywhere Node 22+ runs, via Docker or bare metal). Clients: Web vault (any browser at https://your-host/), Windows, macOS, Linux desktop; iOS & Android mobile; Chrome, Edge, Firefox extension.
Does it work offline? Yes. All clients (including the Web vault) cache the vault in localStorage and compute TOTP offline. You only need the server to add/sync/delete codes across devices.
How do I migrate from Google Authenticator / Authy / 2FAS / Aegis?
Export your codes as otpauth:// URIs (Google Authenticator: Transfer → Export; Aegis: Export → plain JSON; 2FAS: backup file). In any SelfHostAuth client: Add → paste the URI → sync.
What about Authy shutting down its desktop app? SelfHostAuth is an ideal Authy replacement with a real desktop app plus browser and mobile clients — and you won't lose access if a vendor sunsets a product again.
Is there a hosted version? No. SelfHostAuth is self-hosted only by design. If you want zero ops, run the one-command Docker Compose on a $5 VPS or Raspberry Pi.
MIT — see LICENSE.
Keywords for discoverability: self-hosted authenticator, self-hosted 2FA, open source authenticator, TOTP authenticator, HOTP, OTP manager, 2FA sync server, private 2FA, Google Authenticator alternative, Authy alternative, 2FAS alternative, Aegis alternative, self-hosted OTP, self-hosted 2FA server, privacy 2FA, homelab 2FA