Skip to main content

Lightweight Vaultwarden (Bitwarden-compatible) CLI in Python

Project description

vw-cli

Lightweight Vaultwarden (Bitwarden-compatible) CLI written in Python.
Authenticates via API key, syncs the vault, derives the encryption key locally, and prints decrypted passwords or items — all in a single command.

Designed for use in Alpine‑based Docker containers where the official bw Node.js CLI is impractical.

Quick start

pip install vw-cli

export VW_SERVER=https://vault.example.com
export VW_CLIENTID=user.aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
export VW_CLIENTSECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export VW_PASSWORD="your master password"

vw-cli get password "My Website"

Usage

usage: vw-cli <command> [args]

commands:
  login                     authenticate with API key
  sync                      sync vault and print raw JSON
  unlock                    unlock vault (derive encryption key)
  list                      list all item names
  get password <item>       print password for <item>
  get item <item>           print full decrypted <item> as JSON

Commands

command description
login Authenticate with the API key. Verifies credentials work.
sync Pull the full vault (profile + all ciphers) and print raw JSON.
unlock Derive the master key locally and decrypt the stored symmetric key.
list Print every item name (lowercased), one per line.
get password <item> Print the password for the named item (empty string if none).
get item <item> Print the full decrypted item as JSON.

Item lookup is case‑insensitive and supports substring matching.

Environment variables

variable required default description
VW_SERVER no https://vault.bitwarden.com Vaultwarden or Bitwarden server URL
VW_CLIENTID yes API client ID (user.xxx or org.xxx)
VW_CLIENTSECRET yes API client secret
VW_PASSWORD yes Master password

When VW_SERVER contains bitwarden the official Bitwarden identity and API endpoints are used automatically; otherwise the same URL is used for both identity and API paths.

Docker example

FROM alpine:3.19
RUN apk add --no-cache python3 py3-pip
RUN pip install vw-cli
docker run --rm \
  -e VW_SERVER=https://vault.example.com \
  -e VW_CLIENTID=user.xxx \
  -e VW_CLIENTSECRET=xxx \
  -e VW_PASSWORD="..." \
  my-image vw-cli get password "Database"

How it works

  1. Login — sends a client_credentials grant with the API key to {identity_url}/connect/token and receives a bearer token.
  2. Sync — fetches GET /api/sync which returns the user profile (email, KDF parameters, encrypted symmetric key) and all ciphers.
  3. Unlock — derives the 32‑byte master key using the password and email (PBKDF2‑SHA256 or Argon2id, depending on the profile KDF), then decrypts the 64‑byte symmetric key stored in the profile.
  4. Decrypt — splits the symmetric key into an AES‑256‑CBC encryption key (first 32 bytes) and an HMAC‑SHA256 MAC key (last 32 bytes), then decrypts individual cipher fields.

All key derivation happens locally — no unlock endpoint is called.

Architecture

vw_cli/
├── __init__.py     # package entry, re‑exports
├── __main__.py     # python -m vw_cli support
├── error.py        # VwError exception class
├── crypto.py       # VwCryptoKey, key derivation, AES-CBC, HMAC
├── auth.py         # VwAuth – API key login, session management
├── vault.py        # VwVault – sync, unlock, cipher operations
└── cli.py          # CLI argument parsing, orchestration

Separation of concerns:

module responsibility
crypto.py Pure functions: key derivation, encryption/decryption, data types. No I/O.
auth.py VwAuth class: HTTP session, token acquisition, request helper.
vault.py VwVault class: sync, unlock, name cache, find/get/list operations.
cli.py Environment variable reading, argument parsing, command dispatch.

Development

Virtualenv (recommended)

python -m venv venv
source venv/bin/activate
pip install -e .

The package is installed in editable mode (-e), so source changes take effect immediately — no need to reinstall.

Run without pip

You don't need to pip install at all. The __main__.py entry point lets you run the CLI directly from the checkout:

python -m vw_cli get password "My Website"

Or set up a shell alias for convenience:

alias vw-cli='python -m vw_cli'

Test

python -m pytest tests/ -v

Testing

Three test files covering all layers:

test file coverage
tests/test_crypto.py VwCryptoKey, _safe_int, key derivation, AES-CBC, HMAC, decrypt, decrypt_bytes, decode_encrypted
tests/test_client.py VwAuth (login, errors), VwVault (sync, unlock, find, get, list), _setup_urls, network errors, timeout
tests/test_cli.py CLI argument parsing, help/version output, error handling, exit codes

Tests use mocks and never touch the network.

Dependencies

  • requests — HTTP client
  • cryptography — AES‑256‑CBC via OpenSSL bindings
  • argon2-cffi — Argon2id KDF (optional; falls back gracefully)

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vw_cli-0.2.0.tar.gz (17.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vw_cli-0.2.0-py3-none-any.whl (11.6 kB view details)

Uploaded Python 3

File details

Details for the file vw_cli-0.2.0.tar.gz.

File metadata

  • Download URL: vw_cli-0.2.0.tar.gz
  • Upload date:
  • Size: 17.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.5

File hashes

Hashes for vw_cli-0.2.0.tar.gz
Algorithm Hash digest
SHA256 ea742ec54d725af17bb9826b349d4db8af508751da3c0fe4767c1959509b28b2
MD5 25c4d99ce7c1e71c4ff463882ce7855a
BLAKE2b-256 736b6594b4ece875aca49175f12faf1b24a0916cf68ce101514d2c6929d1c9fd

See more details on using hashes here.

File details

Details for the file vw_cli-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: vw_cli-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 11.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.5

File hashes

Hashes for vw_cli-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b71c722dacecc2048dd18a0bad184860987e4ee65836bde7f024749093a692bb
MD5 0a0d312767902c97f2a4bb74a788e093
BLAKE2b-256 9c543713f9316c1694092c755ceee9d91319aa2248e5d3f3f525e171aa62af61

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page