---
path: onboarding/devops-onboarding/python-connector.mdx
title: Python connector
sidebar_position: 5
slug: python-connector-devops
pagination_next: null
pagination_prev: null
description: >-
  How to use the Passwork Python connector (PassworkClient) for scripted integrations:
  authentication, reading secrets, custom fields, CSE support via MasterKeyManager,
  updating records, error handling, and session persistence.
keywords:
  - Passwork
  - Python
  - PassworkClient
  - Python connector
  - SDK
  - automation
  - CSE
  - MasterKeyManager
  - secret rotation
  - integration
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

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

<Tabs className="tabs-container">
  <TabItem className="tab-item-container" value="PyPI" label="PyPI">

  ```shell
  pip install passwork-python
  ```
  </TabItem>
  <TabItem className="tab-item-container" value="GitHub SSH" label="GitHub (SSH)">

  ```shell
  pip install git+ssh://git@github.com:passwork-me/passwork-python.git
  ```
  </TabItem>
</Tabs>

**Requirements:**
- Python 3.10+,
- requests>=2.31.0
- cryptography>=42.0.
- pbkdf2>=1.3

---

## Authentication

<Tabs className="tabs-container">
  <TabItem className="tab-item-container" value="token" label="Token pair (recommended)">

  ```python
  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"),
  )
  ```
  </TabItem>
  <TabItem className="tab-item-container" value="master" label="With CSE (master key)">

  ```python
  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"),
      master_key=os.environ["PASSWORK_MASTER_KEY"],
  )
  ```
  </TabItem>
</Tabs>

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

```python
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

```python
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:

```python
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

```python
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):

```python
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

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

### Update a custom field value

```python
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

```python
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:

```python
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

```python
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:

| Code | Meaning | Action |
|------|---------|--------|
| `accessTokenExpired` | Access token expired | Connector handles automatically if refresh token is set |
| `itemNotFound` | Item ID does not exist | Verify item ID or check vault access |
| `forbidden` | Service account lacks permission | Review vault access level |
| `masterKeyRequired` | CSE enabled but no master key provided | Add `master_key` to `Client()` constructor |

---

## Universal `call()` method

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

```python
# 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](https://passwork.pro/tech-guides/api-and-integrations/intro/).

For more Python connector examples, see the [integration examples repository](https://github.com/passwork-me/passwork-integration-examples).
