Skip to main content

Python connector

The Passwork Python connector wraps the REST API and all cryptographic operations in a high-level Python interface. Use it when you need more control than Passwork CLI provides: batch operations, conditional logic, error handling, migrations, or custom reporting.

The core class is PassworkClient. It provides access to all Passwork objects — vaults, folders, items, users, groups, sessions — and handles token refresh and CSE transparently.


Installation

pip install passwork-python

Requirements:

  • Python 3.10+,
  • requests>=2.31.0
  • cryptography>=42.0.
  • pbkdf2>=1.3

Authentication

import os
from passwork import Client

client = Client(
url=os.environ["PASSWORK_HOST"],
token=os.environ["PASSWORK_TOKEN"],
refresh_token=os.environ.get("PASSWORK_REFRESH_TOKEN"),
)

When refresh_token is provided, the connector renews the access token automatically on expiry. No manual token management is needed in long-running scripts.


Reading secrets

Get a single item by ID

item = client.get_password(item_id="<item_id>")

print(item.name) # item name
print(item.login) # login field
print(item.password) # password field (decrypted if CSE enabled)

Get all items from a folder

items = client.get_passwords(folder_id="<folder_id>")

for item in items:
print(f"{item.name}: {item.password}")

Access custom fields

Custom fields are available on the item.fields dictionary, keyed by field name:

item = client.get_password(item_id="<item_id>")

aws_key_id = item.login
aws_secret_key = item.fields.get("AWS_SECRET_ACCESS_KEY")
aws_region = item.fields.get("AWS_REGION")

Search across vaults

results = client.search_passwords(query="postgres")

for item in results:
print(f"{item.name} in vault {item.vault_id}")

CSE and the MasterKeyManager

When client-side encryption is enabled, the MasterKeyManager component handles key derivation from the master key, RSA private key decryption, and per-vault and per-item key unwrapping. The client handles this automatically when master_key is provided.

If you need to derive the master key from a master password (rather than providing the pre-derived key):

from passwork import Client
from passwork.crypto import MasterKeyManager

manager = MasterKeyManager()
master_key = manager.derive_master_key(
password="your_master_password",
salt="<salt_from_user_profile>",
)

client = Client(
url="https://passwork.example.com",
token="<token>",
master_key=master_key,
)

In practice, most automation uses the pre-derived PASSWORK_MASTER_KEY (which is a base64-encoded byte string) rather than the raw master password.


Writing and updating secrets

Update an existing item's password

item = client.get_password(item_id="<item_id>")
item.password = "new_strong_password_here"
client.update_password(item)

Update a custom field value

item = client.get_password(item_id="<item_id>")
item.fields["AWS_SECRET_ACCESS_KEY"] = "new_aws_secret_key"
client.update_password(item)

Create a new item

from passwork.models import PasswordItem

new_item = PasswordItem(
name="Redis sessions",
login="redis",
password="generated_password",
folder_id="<target_folder_id>",
tags=["production", "messaging"],
)
client.create_password(new_item)

Session persistence

For scripts that run frequently, save and restore the session to avoid generating a new token pair on every run:

import os
from passwork import Client

session_file = "/tmp/passwork_session.enc"

client = Client(url=os.environ["PASSWORK_HOST"])

if os.path.exists(session_file):
client.load_session(session_file)
else:
client.set_tokens(
token=os.environ["PASSWORK_TOKEN"],
refresh_token=os.environ["PASSWORK_REFRESH_TOKEN"],
)

# ... use client ...

client.save_session(session_file)

Saved sessions are encrypted. The encryption key is derived from a combination of token material and is not stored alongside the session file.


Error handling

from passwork import Client
from passwork.exceptions import PassworkResponseError, PassworkError

try:
item = client.get_password(item_id="<item_id>")
except PassworkResponseError as e:
# HTTP error from the Passwork API (4xx, 5xx)
print(f"API error {e.code}: {e.message}")
except PassworkError as e:
# Client-side error (network, encryption, etc.)
print(f"Client error: {e}")

Common API error codes to handle:

CodeMeaningAction
accessTokenExpiredAccess token expiredConnector handles automatically if refresh token is set
itemNotFoundItem ID does not existVerify item ID or check vault access
forbiddenService account lacks permissionReview vault access level
masterKeyRequiredCSE enabled but no master key providedAdd master_key to Client() constructor

Universal call() method

For any API endpoint not covered by a specific connector method, use call():

# Get activity logs
response = client.call(
method="GET",
endpoint="/api/v1/activity-logs",
params={"limit": 100},
)

# Bulk delete items
response = client.call(
method="POST",
endpoint="/api/v1/items/delete/bulk",
json={"ids": ["id1", "id2", "id3"]},
)

For full API reference, see API and integrations: overview.

For more Python connector examples, see the integration examples repository.