Skip to main content

🛡️ Desktop-2FA

A secure, offline two-factor authentication (2FA) manager for desktop environments. Built with Python, featuring strong encryption and no cloud dependencies.

🌐 Landing Page: desktop-2fa.org

PyPI - Downloads PyPI version Python versions License Build codecov


✨ Features

Feature Description
🔐 Vault Security AES-256-GCM encryption with Argon2id key derivation
⏱️ TOTP Generation RFC 6238 compliant code generation
💻 Full CLI Complete command-line interface for managing tokens
📋 Clipboard Support Automatic copying of TOTP codes to clipboard
🔓 Stateless Design Vault contents require authentication; no long-lived sessions
🛡️ Password Policy Configurable password strength enforcement with zxcvbn
🧪 Well Tested 309 tests passing with comprehensive coverage
📖 Security Model Detailed threat analysis and cryptographic design documentation
🖥️ Textual UI Early prototype for listing accounts and generating or copying TOTP codes

📸 Screenshots

Add entry interactively Adding a new TOTP entry interactively

Code generation Generating a TOTP code for an entry

Rename and duplicate error Renaming an entry with duplicate detection

Version and list Viewing version info and listing all entries


🚀 Quick Start

Installation

pip install desktop-2fa

Verify installation:

python -c "import desktop_2fa; print(desktop_2fa.__version__)"
# Output: 0.8.3

Basic Usage

# Initialize a new vault
d2fa vault init

# Add a new TOTP token
d2fa add GitHub GitHub JBSWY3DPEHPK3PXP

# List all entries
d2fa list

# Generate a code
d2fa code GitHub

The vault is stored by default at ~/.desktop-2fa/vault. Select a different file for any command with the global --vault option, or set DESKTOP_2FA_VAULT to choose one by default. An explicit --vault takes precedence over the environment variable; without either, the default remains ~/.desktop-2fa/vault.

# Use a separate vault for this command
d2fa --vault ./development-vault list

# Show the currently selected vault path
d2fa --vault ./development-vault vault path

# Launch the early Textual UI prototype with that vault
d2fa --vault ./development-vault ui

The Textual UI is at an early prototype stage. It prompts for the vault password unless one is supplied with --password or --password-file, and supports listing entries, generating codes, and copying codes to the clipboard. It does not support entry management or create a missing vault.

Non-Interactive Usage

# Provide password via command line
d2fa --password mypassphrase add GitHub GitHub JBSWY3DPEHPK3PXP

# Provide password via file
d2fa --password-file /path/to/passphrase.txt add GitHub GitHub JBSWY3DPEHPK3PXP

📁 Vault Lifecycle

The vault is an encrypted storage file located by default at ~/.desktop-2fa/vault; use --vault or DESKTOP_2FA_VAULT to select another path. Vault files must be regular files no larger than 10 MiB.

Before Upgrading

Vaults created with Desktop-2FA 0.6.0 and later are designed to remain compatible with newer releases. Even so, before upgrading, we strongly recommend creating an encrypted backup and storing it securely. Compatibility is not a substitute for a backup.

d2fa backup

Vault Creation

When a CLI command that creates or updates entries requires a vault and none exists:

  1. The CLI prompts for a new password (interactive mode) or requires --password/--password-file (non-interactive mode)
  2. An empty encrypted vault is created
  3. A confirmation message is always printed: Vault created at <path>

The Textual UI does not create a missing vault; it displays the vault-loading error instead.

Vault Loading

When a command requires a vault and it exists:

  1. The CLI prompts for the existing password (interactive mode) or requires credentials (non-interactive mode)
  2. The vault is decrypted and loaded
  3. If the password is invalid, the CLI exits with typer.Exit(1)

Duplicate Entry Handling

The rename command enforces deterministic behavior when multiple entries match the target name:

  • If multiple entries match the provided name (issuer or account_name), the rename is aborted
  • Error message: Error: Multiple entries named '<name>' exist. Operation aborted. Resolve duplicates first.
  • No entry is renamed in this case
  • This check occurs before any mutation

📖 CLI Commands

Core Commands

Command Description
d2fa add <name> <issuer> <secret> Add a new TOTP entry
d2fa list List all stored TOTP entries
d2fa rename <old> <new> Rename an entry
d2fa remove <name> Remove an entry
d2fa code <name> [--copy|--copy-only] Generate TOTP code with clipboard copy options

Vault Management

Command Description
d2fa vault init [--force] Initialize a new vault (d2fa init-vault is an alias)
d2fa vault unlock Open vault with weak password warning (if configured)
d2fa vault change-password Change the vault password
d2fa vault path Show the currently selected vault path
d2fa backup Create an encrypted backup of the vault
d2fa export <path> Export vault to file
d2fa import <path> [--force] Import vault from file
d2fa ui Launch the early Textual UI prototype

Global Options

Option Description
--version Show the installed version
--password <pwd> Provide vault password directly
--password-file <path> Read vault password from file
--vault <path> Select the vault file; place before the command
--allow-weak-passwords Allow weak passwords
--help Show command help

The --vault option takes precedence over DESKTOP_2FA_VAULT. When neither is provided, Desktop-2FA uses ~/.desktop-2fa/vault. The code command also supports --json, --raw, --quiet, --copy, and --copy-only; --force is available on vault initialization and import commands.


🔒 Security

The vault uses:

  • AES-256-GCM for authenticated encryption
  • Argon2id for key derivation (time_cost=4, memory_cost=128MiB, parallelism=2)
  • zxcvbn for password strength evaluation
  • Versioned header for forward compatibility

Every command that accesses vault contents requires password authentication. Path and version queries do not access vault contents. No session-based access.

Password Strength Evaluation

Desktop-2FA uses zxcvbn to evaluate password strength when creating or changing vault passwords:

  • Score 0-2 (Weak): Easily guessable passwords (e.g., "password123")
  • Score 3-4 (Strong): Resistant to common attacks (recommended)

Examples:

  • ❌ Weak: password, 123456, qwerty, admin2024
  • ✅ Strong: Battery-Horse-Staple-Correct, Mountain@River*2024, MySecureVault#42

Configuration (~/.config/d2fa/config.toml):

[security]
# Require strong passwords (score >= 3)
reject_weak_passwords = false  # warn but allow | true: reject weak passwords

When reject_weak_passwords = false:

  • Weak passwords trigger a yellow warning
  • User is prompted to confirm continuation
  • Password acceptance is non-blocking

When reject_weak_passwords = true:

  • Weak passwords are rejected immediately
  • Command exits with error
  • User must choose a stronger password

Backward Compatibility: If you have min_password_entropy set in your config (legacy option), it is recognized and treated as equivalent to requiring zxcvbn score >= 3.

Security Hardening

Version 0.8.2 added bounded vault loading and atomic saves; version 0.8.3 adds the early Textual UI prototype:

  • Empty passwords are immediately rejected with a clear error message
  • Permission errors are distinguished from missing vault files
  • Vault loading accepts only regular files and reads at most 10 MiB
  • Vault saves use unique temporary files and atomic replacement
  • No Python stack traces are shown to users
  • User-friendly error messages for filesystem permission issues
  • Modular design separates CLI and core cryptographic components for enhanced security boundaries
  • zxcvbn-based password strength evaluation

📚 Documentation

Document Description
User Manual Complete usage guide
Security Model Detailed threat analysis and cryptographic design
CLI UX Specification UX contract and behavior
Cryptography Security implementation details

🧪 Testing

pytest tests/              # Run all tests
pytest --cov=src/desktop_2fa  # Run with coverage

🏗️ Project Structure

src/desktop_2fa/
├── app/           # Application components
├── cli/           # Command-line interface
├── crypto/        # Encryption utilities
├── totp/          # TOTP generation
├── ui_textual/    # Early Textual UI prototype
├── vault/         # Vault management
└── utils/         # Utilities

📄 License

Apache License 2.0. See LICENSE file.


👤 Author

Łukasz Perek


🏆 Sponsorship

desktop‑2fa is supported through the Kilo OSS Sponsorship Program.


📧 Contact

For questions or support, contact us at contact@desktop-2fa.org


💖 Support the Project

Desktop‑2FA is an independent open‑source tool built with a focus on autonomy, transparency, and offline security. If you find it useful and want to support ongoing development, you can do so through the platforms below:

Metadata

Release files for desktop-2fa 0.8.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for desktop-2fa 0.8.3
File Size Uploaded Provenance
desktop_2fa-0.8.3.tar.gz 340.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for desktop-2fa 0.8.3
File Interpreter ABI Platform
desktop_2fa-0.8.3-py3-none-any.whl Python 3 none any Details

Total release size: 381.4 kB

Release files / desktop_2fa-0.8.3.tar.gz

Download URL desktop_2fa-0.8.3.tar.gz
Size 340.5 kB
Tags Source
SHA-256 checksum
How to use checksums
e028d9c537e79a5b02bdd27fb4144aec468cd2beb25446d9fe9682e47fada262
BLAKE2b-256 checksum
How to use checksums
47051a2bb1ab0657d8b053a3db28c3b5ad1932df42779d4c25c88fb3e7cf8af1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Release files / desktop_2fa-0.8.3-py3-none-any.whl

Download URL desktop_2fa-0.8.3-py3-none-any.whl
Size 41.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e1b507a8bf7878ea36ecf70fdd1716452dc716a6b6a2a2b73a05c7e0ece51b94
BLAKE2b-256 checksum
How to use checksums
159edc2b8feac8a938b8ae5ff0fe7329cc93ad721a1be27363546e6b8268121d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Security for desktop-2fa 0.8.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page