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
- Login — sends a
client_credentialsgrant with the API key to{identity_url}/connect/tokenand receives a bearer token. - Sync — fetches
GET /api/syncwhich returns the user profile (email, KDF parameters, encrypted symmetric key) and all ciphers. - 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.
- 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 clientcryptography— AES‑256‑CBC via OpenSSL bindingsargon2-cffi— Argon2id KDF (optional; falls back gracefully)
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea742ec54d725af17bb9826b349d4db8af508751da3c0fe4767c1959509b28b2
|
|
| MD5 |
25c4d99ce7c1e71c4ff463882ce7855a
|
|
| BLAKE2b-256 |
736b6594b4ece875aca49175f12faf1b24a0916cf68ce101514d2c6929d1c9fd
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b71c722dacecc2048dd18a0bad184860987e4ee65836bde7f024749093a692bb
|
|
| MD5 |
0a0d312767902c97f2a4bb74a788e093
|
|
| BLAKE2b-256 |
9c543713f9316c1694092c755ceee9d91319aa2248e5d3f3f525e171aa62af61
|