Skip to main content

Python SDK for PhilVault authentication and authorization APIs.

Project description

PhilVault SDK

Python SDK for integrating PhilVault authentication and authorization APIs.

Install

pip install philvault-sdk

PyPI: https://pypi.org/project/philvault-sdk/0.1.0/

Quick Start

from philvault_sdk import PhilVaultClient

client = PhilVaultClient(
    base_url="http://localhost:8000",
    api_key="your-api-key",
)

register_result = client.register(
    username="alice",
    password="secret",
    email="alice@example.com",
)

access_token = register_result["access_token"]
client.set_access_token(access_token)

me = client.me()

Only base_url and api_key are required. Other options have defaults.

You can also create the client from environment variables:

from philvault_sdk import PhilVaultClient

client = PhilVaultClient.from_env()

Default env vars:

  • PHILVAULT_BASE_URL
  • PHILVAULT_API_KEY
  • PHILVAULT_ACCESS_TOKEN
  • PHILVAULT_TIMEOUT
  • PHILVAULT_VERIFY_SSL
  • PHILVAULT_API_KEY_HEADER
  • PHILVAULT_USER_AGENT

Async Usage

import asyncio
from philvault_sdk import AsyncPhilVaultClient

async def main():
    async with AsyncPhilVaultClient(
        base_url="http://localhost:8000",
        api_key="your-api-key",
    ) as client:
        result = await client.login("alice", "secret")
        client.set_access_token(result["access_token"])
        me = await client.me()
        print(me)

asyncio.run(main())

httpx Usage

Both clients expose request/get/post/put/patch/delete/head/options with the same signature style as httpx. These methods return raw httpx.Response, while helper methods like login() still return parsed JSON dictionaries.

from philvault_sdk import PhilVaultClient

with PhilVaultClient(base_url="http://localhost:8000", api_key="your-api-key") as client:
    response = client.get("/healthz")
    print(response.status_code, response.json())

Config Options

  • base_url (required): PhilVault service root, no /api/v1 suffix
  • api_key (required): value for X-API-Key
  • access_token (optional): Bearer token for authenticated endpoints
  • timeout (optional): request timeout in seconds, default 10
  • user_agent (optional): default philvault-sdk/0.1.0
  • verify_ssl (optional): verify HTTPS certificates, default True
  • api_key_header (optional): override API key header name, default X-API-Key
  • extra_headers (optional): dict of extra headers merged into every request

Client Methods

The sync and async clients expose the same methods. For async usage, add await and use AsyncPhilVaultClient.

Lifecycle and setup

  • from_env(): create client from environment variables (see env var list above). Returns: PhilVaultClient / AsyncPhilVaultClient Example:
    from philvault_sdk import PhilVaultClient
    
    client = PhilVaultClient.from_env()
    
  • set_api_key(api_key): update API key (must be non-empty). Useful for rotating keys without re-instantiating the client. Returns: None Example:
    client.set_api_key("new-api-key")
    
  • set_access_token(access_token): set or clear bearer token used for authenticated endpoints. Pass None or an empty string to clear. Returns: None Example:
    client.set_access_token(access_token)
    client.set_access_token(None)
    
  • close() / aclose(): close underlying httpx client and release resources. Returns: None Example:
    client.close()
    # or: await client.aclose()
    
  • context manager: ensures automatic close when leaving the block. Returns: client instance within the context. Example:
    from philvault_sdk import PhilVaultClient, AsyncPhilVaultClient
    
    with PhilVaultClient(base_url="http://localhost:8000", api_key="key") as client:
        me = client.me()
    
    async with AsyncPhilVaultClient(base_url="http://localhost:8000", api_key="key") as client:
        me = await client.me()
    

Raw HTTP (httpx style)

These return httpx.Response:

  • request(method, path, **kwargs)
  • get(path, **kwargs)
  • post(path, **kwargs)
  • put(path, **kwargs)
  • patch(path, **kwargs)
  • delete(path, **kwargs)
  • head(path, **kwargs)
  • options(path, **kwargs) Example:
response = client.get("/healthz")
print(response.status_code)
print(response.json())

Auth endpoints

These return parsed JSON dict:

  • register(username, password, email=None, domain_roles=None)
    POST /api/v1/auth/register/
    Creates a new user and returns tokens. domain_roles is an optional list of [domain, role] pairs, e.g. [["team-a", "admin"]]. password must be at least 8 characters. Returns: {"user": {...}, "access_token": "...", "refresh_token": "..."} Example:
    result = client.register(
        username="alice",
        password="secret",
        email="alice@example.com",
        domain_roles=[["team-a", "admin"]],
    )
    client.set_access_token(result["access_token"])
    
    Example response:
    {
        "user": {
            "id": "64f1c2a1b2c3d4e5f6a7b8c9",
            "username": "alice",
            "email": "alice@example.com",
            "is_active": True,
            "is_superuser": False,
            "domain_roles": [["team-a", "admin"]],
            "created_at": 1730000000,
            "updated_at": 1730000000,
            "last_login": None,
        },
        "access_token": "eyJhbGciOi...",
        "refresh_token": "eyJhbGciOi...",
    }
    
  • login(username, password)
    POST /api/v1/auth/login/
    Authenticates and returns access/refresh tokens. Returns: {"user": {...}, "access_token": "...", "refresh_token": "..."} Example:
    result = client.login("alice", "secret")
    client.set_access_token(result["access_token"])
    
    Example response:
    {
        "user": {
            "id": "64f1c2a1b2c3d4e5f6a7b8c9",
            "username": "alice",
            "email": "alice@example.com",
            "is_active": True,
            "is_superuser": False,
            "domain_roles": [["team-a", "admin"]],
            "created_at": 1730000000,
            "updated_at": 1730000000,
            "last_login": 1730000500,
        },
        "access_token": "eyJhbGciOi...",
        "refresh_token": "eyJhbGciOi...",
    }
    
  • refresh(refresh_token)
    POST /api/v1/auth/refresh/
    Exchanges a refresh token for a new access token. Returns: {"access_token": "...", "token_type": "Bearer"} Example:
    refreshed = client.refresh(refresh_token)
    client.set_access_token(refreshed["access_token"])
    
    Example response:
    {"access_token": "eyJhbGciOi...", "token_type": "Bearer"}
    
  • me()
    GET /api/v1/auth/me/
    Returns the current authenticated user profile. Returns: {"id": "...", "username": "...", ...} Example:
    profile = client.me()
    
    Example response:
    {
        "id": "64f1c2a1b2c3d4e5f6a7b8c9",
        "username": "alice",
        "email": "alice@example.com",
        "is_active": True,
        "is_superuser": False,
        "domain_roles": [["team-a", "admin"]],
        "created_at": 1730000000,
        "updated_at": 1730000000,
        "last_login": 1730000500,
    }
    
  • list_users(page=None, page_size=None, search=None)
    GET /api/v1/auth/users/
    Lists users with pagination and optional search (by username or email). If page_size is omitted, the server default is used. Returns: {"users": [...], "total": 0, "page": 1, "page_size": 10} Example:
    result = client.list_users(page=1, page_size=20, search="alice")
    
    Example response:
    {
        "users": [
            {
                "id": "64f1c2a1b2c3d4e5f6a7b8c9",
                "username": "alice",
                "email": "alice@example.com",
                "is_active": True,
                "is_superuser": False,
                "domain_roles": [["team-a", "admin"]],
                "created_at": 1730000000,
                "updated_at": 1730000000,
                "last_login": None,
            }
        ],
        "total": 1,
        "page": 1,
        "page_size": 20,
    }
    
  • update_user(user_id, username=None, email=None, is_active=None, is_superuser=None, domain_roles=None)
    PUT /api/v1/auth/users/{user_id}
    Updates user information by user ID. All parameters are optional - only provided fields will be updated. Returns: {"message": "...", "user": {...}} Example:
    result = client.update_user(
        user_id="64f1c2a1b2c3d4e5f6a7b8c9",
        username="new_username",
        email="new_email@example.com",
        is_active=True,
    )
    
    Example response:
    {
        "message": "User updated successfully",
        "user": {
            "id": "64f1c2a1b2c3d4e5f6a7b8c9",
            "username": "new_username",
            "email": "new_email@example.com",
            "is_active": True,
            "is_superuser": False,
            "domain_roles": [["team-a", "admin"]],
            "created_at": 1730000000,
            "updated_at": 1730001000,
            "last_login": None,
        },
    }
    
  • delete_user(user_id)
    DELETE /api/v1/auth/users/{user_id}
    Deletes a user by user ID (soft delete). Returns: {"message": "..."} Example:
    result = client.delete_user("64f1c2a1b2c3d4e5f6a7b8c9")
    
    Example response:
    {"message": "User deleted successfully"}
    
  • change_password(old_password, new_password)
    POST /api/v1/auth/change-password/
    Changes the current user's password (requires bearer token). new_password must be at least 8 characters. Returns: {"message": "..."} Example:
    client.change_password("old-secret", "new-secret")
    
    Example response:
    {"message": "Password changed successfully"}
    

ACL endpoints

These return parsed JSON dict:

  • check_permission(user_id, domain, resource_id, action)
    POST /api/v1/auth/acl/enforce:check
    Checks if a user can perform an action on a resource in a domain. user_id must be a valid MongoDB ObjectId string. The backend validates the user exists (invalid id returns 400, missing user returns 404). Returns: {"allowed": bool, "user_id": "...", "domain": "...", "resource_id": "...", "action": "..."} Example:
    allowed = client.check_permission(
        user_id="64f1c2a1b2c3d4e5f6a7b8c9",
        domain="team-a",
        resource_id="doc_456",
        action="read",
    )
    
    Example response:
    {
        "allowed": True,
        "user_id": "64f1c2a1b2c3d4e5f6a7b8c9",
        "domain": "team-a",
        "resource_id": "doc_456",
        "action": "read",
    }
    
  • check_permission_batch(policies)
    POST /api/v1/auth/acl/enforce:batch_check
    Batch check. policies is a list of {user_id, domain, resource_id, action}. Returns: {"results": [{"user_id": "...", "domain": "...", "resource_id": "...", "action": "...", "allowed": bool}, ...]} Example:
    result = client.check_permission_batch([
        {"user_id": "64f1c2a1b2c3d4e5f6a7b8c9", "domain": "team-a", "resource_id": "doc_1", "action": "read"},
        {"user_id": "64f1c2a1b2c3d4e5f6a7b8c9", "domain": "team-a", "resource_id": "doc_2", "action": "write"},
    ])
    
    Example response:
    {
        "results": [
            {
                "user_id": "64f1c2a1b2c3d4e5f6a7b8c9",
                "domain": "team-a",
                "resource_id": "doc_1",
                "action": "read",
                "allowed": True,
            },
            {
                "user_id": "64f1c2a1b2c3d4e5f6a7b8c9",
                "domain": "team-a",
                "resource_id": "doc_2",
                "action": "write",
                "allowed": False,
            },
        ]
    }
    
  • add_policy(subject, domain, object_name, action)
    POST /api/v1/auth/acl/enforce:add
    Adds an ACL policy rule for a subject (user or role). Returns: {"result": "Policy added", "policy": ["subject", "domain", "object", "action"]} Example:
    client.add_policy("user:u_123", "team-a", "doc_456", "read")
    
    Example response:
    {"result": "Policy added", "policy": ["user:u_123", "team-a", "doc_456", "read"]}
    
  • revoke_policy(subject, domain, object_name, action)
    POST /api/v1/auth/acl/enforce:revoke
    Removes an ACL policy rule. Returns: {"result": "Policy revoked", "policy": ["subject", "domain", "object", "action"]} Example:
    client.revoke_policy("user:u_123", "team-a", "doc_456", "read")
    
    Example response:
    {"result": "Policy revoked", "policy": ["user:u_123", "team-a", "doc_456", "read"]}
    
  • assign_domain_role(user_id, role, domain)
    POST /api/v1/auth/acl/roles:assign/
    Assigns a role to a user within a domain. Returns: {"result": "Role assigned", "role": ["user_id", "role", "domain"]} Example:
    client.assign_domain_role("64f1c2a1b2c3d4e5f6a7b8c9", "admin", "team-a")
    
    Example response:
    {"result": "Role assigned", "role": ["64f1c2a1b2c3d4e5f6a7b8c9", "admin", "team-a"]}
    
  • remove_domain_role(user_id, role, domain)
    POST /api/v1/auth/acl/roles:remove/
    Removes a role assignment for a user. Returns: {"result": "Role removed", "role": ["user_id", "role", "domain"]} Example:
    client.remove_domain_role("64f1c2a1b2c3d4e5f6a7b8c9", "admin", "team-a")
    
    Example response:
    {"result": "Role removed", "role": ["64f1c2a1b2c3d4e5f6a7b8c9", "admin", "team-a"]}
    
  • list_domain_roles(user_id, domain)
    POST /api/v1/auth/acl/roles:list/
    Lists roles for a user in a domain. Returns: {"roles": ["role_name", ...]} Example:
    roles = client.list_domain_roles("64f1c2a1b2c3d4e5f6a7b8c9", "team-a")
    
    Example response:
    {"roles": ["admin", "editor"]}
    
  • add_resource_policy(resource_id, parent_resource_id)
    POST /api/v1/auth/acl/resources:assign/
    Links a resource to a parent resource (resource hierarchy). Returns: {"result": "Policy added", "policy": ["resource_id", "parent_resource_id"]} Example:
    client.add_resource_policy("doc_456", "folder_1")
    
    Example response:
    {"result": "Policy added", "policy": ["doc_456", "folder_1"]}
    
  • remove_resource_policy(resource_id, parent_resource_id)
    POST /api/v1/auth/acl/resources:remove/
    Unlinks a resource from its parent. Returns: {"result": "Policy removed", "policy": ["resource_id", "parent_resource_id"]} Example:
    client.remove_resource_policy("doc_456", "folder_1")
    
    Example response:
    {"result": "Policy removed", "policy": ["doc_456", "folder_1"]}
    

Error handling

All helper methods raise PhilVaultHTTPError when the HTTP status is 4xx/5xx. The exception includes status_code, message, and (when possible) the parsed JSON response payload.

Example:

from philvault_sdk import PhilVaultClient
from philvault_sdk.errors import PhilVaultHTTPError

client = PhilVaultClient(base_url="http://localhost:8000", api_key="bad-key")
try:
    client.me()
except PhilVaultHTTPError as exc:
    print(exc.status_code)  # 401
    print(exc.payload)      # {"detail": "Invalid API key"}

Common error responses for auth/ACL endpoints use FastAPI's default shape: {"detail": "..."}. Typical status codes include 400, 401, 404, 409, and 500 depending on the operation.

Notes

  • base_url should point to the PhilVault service root (no /api/v1 suffix).
  • All /api/v1/auth/* endpoints require X-API-Key.
  • Endpoints that require authentication use Authorization: Bearer <token>.

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

philvault_sdk-0.2.0.tar.gz (12.6 kB view details)

Uploaded Source

Built Distribution

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

philvault_sdk-0.2.0-py3-none-any.whl (11.4 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for philvault_sdk-0.2.0.tar.gz
Algorithm Hash digest
SHA256 4f6b73823e6b10e6b5793b78f63406baee1c344afa50f2c7e40448ff8e0ea748
MD5 353e0181bf101aa26ba4b78910327b97
BLAKE2b-256 9cd7cef1256e9b56fbd757e9847cf2388b480a10914fcb63cea82d70a54a74c9

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for philvault_sdk-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a61a35c0d0ed569d827f9cd8ef46033fe67bff13024fa341c9e089afe50693de
MD5 ea4c1f5ed37845a0f26e848a0a624157
BLAKE2b-256 058e01379b88dfb481ad357d9d6125e1d329db9770439b88dfc0540c343735fb

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