Type: On-premise web-based TOTP (Time-based One-Time Password) authenticator Purpose: Google Authenticator alternative accessible via web browser Scale: Max 10 concurrent users Priority: Fast development + Beautiful UI + Simple deployment
-
Authentication
- 2 hardcoded user accounts:
adminandviewer - Session-based authentication
- No user registration/management needed
- 2 hardcoded user accounts:
-
TOTP Management
- Add accounts via QR code image upload
- Add accounts via manual secret key input
- Display multiple accounts with auto-refreshing 6-digit codes
- Each code refreshes every 30 seconds (standard TOTP)
- Label/name each account (e.g., "Gmail - Work", "AWS - Production")
-
User Permissions
- Admin: Full access (view, add, delete accounts)
- Viewer: Read-only access (view codes only)
-
User Experience
- One-click copy to clipboard
- Responsive design (desktop + mobile)
- Real-time code countdown indicator
- Clean, modern interface
- Performance: Handle 10 concurrent users smoothly
- Security: Moderate security (on-premise deployment)
- Deployment: Single Docker container
- Maintainability: Simple, lean architecture
Frontend:
- React 18+ (with Hooks)
- Tailwind CSS (styling)
- shadcn/ui (component library)
- Vite (build tool)
Backend:
- Node.js 20+ LTS
- Express.js (web framework)
- better-sqlite3 (database driver)
Database:
- SQLite with @journeyapps/sqlcipher (encryption)
Deployment:
- Docker + Docker Compose
- Single container architecture
βββββββββββββββββββββββββββββββββββββββββββ
β Docker Container β
β β
β ββββββββββββββββ ββββββββββββββββ β
β β React SPA βββββΊβ Express β β
β β (Frontend) β β (Backend) β β
β ββββββββββββββββ ββββββββ¬ββββββββ β
β β β
β βββββββββΌβββββββ β
β β SQLite DB β β
β β (Encrypted) β β
β ββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββ
β²
β HTTPS (recommended)
β
ββββββΌββββββ
β Users β
ββββββββββββ
-- Accounts table (stores TOTP secrets)
CREATE TABLE accounts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
label TEXT NOT NULL, -- User-defined name (e.g., "Gmail - Work")
issuer TEXT, -- Service name (e.g., "Google")
secret TEXT NOT NULL, -- Base32 encoded secret (encrypted)
algorithm TEXT DEFAULT 'SHA1', -- TOTP algorithm
digits INTEGER DEFAULT 6, -- Code length
period INTEGER DEFAULT 30, -- Refresh interval in seconds
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now'))
);
-- Sessions table (user authentication)
CREATE TABLE sessions (
id TEXT PRIMARY KEY, -- Session ID
username TEXT NOT NULL, -- 'admin' or 'viewer'
expires_at TEXT NOT NULL,
created_at TEXT DEFAULT (datetime('now'))
);- Hardcoded credentials stored in environment variables:
ADMIN_USERNAME/ADMIN_PASSWORDVIEWER_USERNAME/VIEWER_PASSWORD
- Passwords hashed with bcrypt (pre-generated hashes)
- Session-based auth with httpOnly cookies
- Session timeout: 24 hours (configurable)
- TOTP secrets encrypted at rest using SQLCipher
- Encryption key stored in environment variable:
DB_ENCRYPTION_KEY - HTTPS recommended for production (user's responsibility)
- CSRF protection via tokens
- Rate limiting on login endpoint (5 attempts per 15 minutes)
- Middleware checks user role before sensitive operations:
viewer: GET requests onlyadmin: Full CRUD access
1. Login Page (/login)
- Username input
- Password input
- "Remember me" checkbox (optional)
- Error messages for invalid credentials
2. Dashboard (/)
- Header with username + logout button
- "Add Account" button (admin only)
- Grid/list of TOTP accounts showing:
- Account label/issuer
- Current 6-digit code (large, prominent)
- Countdown progress bar (30s cycle)
- Copy button (click to copy code)
- Delete button (admin only, with confirmation)
- Empty state when no accounts exist
3. Add Account Modal
- Two input methods (tabs):
- QR Code Upload: Drag-drop or browse
- Manual Entry: Text input for secret key + label
- Parse
otpauth://URLs automatically - Form validation and error handling
Button,Input,Card,Dialog,Progress,ToastTabs,Label,Alert,DropdownMenu
- Modern & Clean: Minimal clutter, focus on codes
- Accessible: WCAG 2.1 AA compliance
- Responsive: Mobile-first design (320px - 4K)
- Fast: Optimistic UI updates, smooth animations
POST /api/auth/login - Login with username/password
POST /api/auth/logout - Logout and destroy session
GET /api/auth/me - Get current user info
GET /api/accounts - List all accounts
POST /api/accounts - Add new account (admin only)
DELETE /api/accounts/:id - Delete account (admin only)
GET /api/accounts/:id/otp - Get current TOTP code
POST /api/accounts
{
"label": "Gmail - Work",
"secret": "JBSWY3DPEHPK3PXP", // Base32 secret
"issuer": "Google", // Optional
"algorithm": "SHA1", // Optional (default: SHA1)
"digits": 6, // Optional (default: 6)
"period": 30 // Optional (default: 30)
}GET /api/accounts
{
"accounts": [
{
"id": 1,
"label": "Gmail - Work",
"issuer": "Google",
"algorithm": "SHA1",
"digits": 6,
"period": 30,
"current_code": "123456",
"time_remaining": 12 // seconds until refresh
}
]
}authenticator/
βββ docker-compose.yml
βββ Dockerfile
βββ .env.example
βββ package.json
βββ README.md
β
βββ server/ # Backend (Node.js + Express)
β βββ src/
β β βββ index.js # Entry point
β β βββ config.js # Environment config
β β βββ db.js # SQLite connection + migrations
β β βββ auth.js # Authentication middleware
β β βββ totp.js # TOTP generation logic
β β βββ routes/
β β β βββ auth.js # Auth routes
β β β βββ accounts.js # Account routes
β β βββ utils/
β β βββ encryption.js # Secret encryption/decryption
β β βββ qrcode.js # QR code parsing
β β βββ session.js # Session management
β βββ tests/ # Unit tests (optional)
β
βββ client/ # Frontend (React + Vite)
β βββ public/
β βββ src/
β β βββ main.jsx # Entry point
β β βββ App.jsx # Root component
β β βββ components/
β β β βββ LoginForm.jsx
β β β βββ Dashboard.jsx
β β β βββ AccountCard.jsx
β β β βββ AddAccountDialog.jsx
β β β βββ ui/ # shadcn/ui components
β β βββ hooks/
β β β βββ useAuth.js
β β β βββ useAccounts.js
β β βββ lib/
β β β βββ api.js # API client (fetch wrapper)
β β βββ styles/
β β βββ globals.css
β βββ vite.config.js
β βββ tailwind.config.js
β
βββ data/ # Persistent volume mount
βββ app.db # SQLite database (created at runtime)
# .env file
NODE_ENV=production
PORT=3000
# Database
DB_PATH=/app/data/app.db
DB_ENCRYPTION_KEY=your-strong-32-char-encryption-key
# Authentication (bcrypt hashed passwords)
ADMIN_USERNAME=admin
ADMIN_PASSWORD_HASH=$2b$10$... (bcrypt hash)
VIEWER_USERNAME=viewer
VIEWER_PASSWORD_HASH=$2b$10$... (bcrypt hash)
# Session
SESSION_SECRET=your-strong-session-secret
SESSION_TIMEOUT=86400000 # 24 hours in msversion: '3.8'
services:
authenticator:
build: .
ports:
- "3000:3000"
volumes:
- ./data:/app/data
env_file:
- .env
restart: unless-stopped- Clone repository
- Copy
.env.exampleto.envand configure - Generate password hashes:
npm run hash-password - Run:
docker-compose up -d - Access:
http://localhost:3000 - (Recommended) Set up reverse proxy (nginx) with SSL
- Network Isolation: Deploy on internal network only
- HTTPS: Use reverse proxy (nginx/Caddy) with Let's Encrypt or self-signed cert
- Firewall: Restrict access to authorized IP ranges
- Backups: Regular encrypted backups of SQLite database
- Monitoring: Basic logging of authentication attempts
- Updates: Regular dependency updates for security patches
- TOTP for the authenticator itself (meta-2FA)
- Audit logging (who viewed which codes when)
- Export/import functionality
- Browser extension for auto-fill
Phase 1: Core Setup (2-3 hours)
- Project initialization
- Database setup with encryption
- Basic Express server with auth
Phase 2: Backend API (3-4 hours)
- TOTP generation logic
- QR code parsing
- Account CRUD endpoints
- Session management
Phase 3: Frontend UI (4-5 hours)
- React app setup with Vite
- shadcn/ui integration
- Login page
- Dashboard with account cards
- Add account modal
Phase 4: Integration & Testing (2-3 hours)
- Frontend-backend integration
- Manual testing
- Docker configuration
- Documentation
Total Estimate: 11-15 hours for MVP
β Two users can log in with different permissions β Admin can add accounts via QR or manual secret β TOTP codes display and refresh every 30 seconds β Codes can be copied to clipboard β Admin can delete accounts β Viewer has read-only access β Responsive UI works on mobile + desktop β Single Docker container deployment β Secrets encrypted at rest
- User management (registration, password reset)
- Multi-user account isolation (each user has their own accounts)
- Backup/restore functionality
- Browser extension
- Mobile app (React Native)
- Hardware token support (YubiKey)
- API rate limiting per user
- Audit logging