Metadata-Version: 2.4
Name: uvb-client
Version: 0.2.0
Summary: Universal Verification Broker (UVB) Python SDK
Project-URL: Homepage, https://gitlab.com/sparkz-community/security/uvb
Project-URL: Documentation, https://gitlab.com/sparkz-community/security/uvb/-/blob/main/docs/README.md
Project-URL: Repository, https://gitlab.com/sparkz-community/security/uvb
Project-URL: Issues, https://gitlab.com/sparkz-community/security/uvb/-/issues
Author: UVB Team
License: MIT
Keywords: authentication,mfa,security,uvb,verification
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: httpx>=0.24.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: dev
Requires-Dist: black>=23.0.0; extra == 'dev'
Requires-Dist: mypy>=1.0.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Provides-Extra: test
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'test'
Requires-Dist: pytest-cov>=4.0.0; extra == 'test'
Requires-Dist: pytest>=7.0.0; extra == 'test'
Description-Content-Type: text/markdown

# uvb-client

Python SDK for Universal Verification Broker (UVB).

## Installation

```bash
pip install uvb-client
```

## Quick Start

```python
import asyncio
from uvb import UVBClient

async def main():
    # Initialize the client
    async with UVBClient(
        tenant_id="my-tenant",
        uvb_url="http://localhost:8080",
        api_key="optional-api-key"
    ) as client:
        # Verify a user with TOTP
        response = await client.verify(
            user_id="user123",
            factor_type="totp",
            factor_value="123456"
        )

        if response.success:
            print(f"Verification successful! Session: {response.session_id}")
        else:
            print(f"Verification failed: {response.error}")

        # Validate a session
        session = await client.validate_session(
            session_token=response.session_token
        )
        print(f"User: {session.user_id}")
        print(f"Factors verified: {session.factors_verified}")

asyncio.run(main())
```

## API Reference

### UVBClient

#### `__init__(tenant_id, uvb_url, api_key, timeout)`

Initialize the UVB client.

**Parameters:**

- `tenant_id` (required): Your UVB tenant identifier
- `uvb_url` (optional): Base URL of the UVB server (default: `http://localhost:8080`)
- `api_key` (optional): API key for server-to-server authentication
- `timeout` (optional): Request timeout in seconds (default: 30.0)

#### `verify(user_id, factor_type, factor_value, metadata)`

Verify a user with a specific authentication factor.

**Parameters:**

- `user_id` (required): User identifier
- `factor_type` (required): Authentication factor type (`totp`, `webauthn`, `email_otp`, etc.)
- `factor_value` (optional): Factor value (e.g., TOTP code)
- `metadata` (optional): Additional metadata dictionary

**Returns:** `VerificationResponse`

```python
response = await client.verify(
    user_id="user123",
    factor_type="totp",
    factor_value="123456"
)
```

#### `validate_session(session_token)`

Validate a session token and retrieve session information.

**Parameters:**

- `session_token` (required): Session token to validate

**Returns:** `UVBSession`

```python
session = await client.validate_session(
    session_token="eyJ0eXAiOiJKV1QiLCJhbGc..."
)
```

#### `revoke_session(session_id)`

Revoke a session.

**Parameters:**

- `session_id` (required): Session identifier to revoke

**Returns:** `bool` (True if successful)

```python
await client.revoke_session(session_id="sess_123")
```

#### `enroll_factor(user_id, factor_type, metadata)`

Enroll a new authentication factor for a user.

**Parameters:**

- `user_id` (required): User identifier
- `factor_type` (required): Factor type to enroll
- `metadata` (optional): Additional metadata dictionary

**Returns:** `EnrollmentResponse`

```python
enrollment = await client.enroll_factor(
    user_id="user123",
    factor_type="totp"
)
print(f"QR Code: {enrollment.qr_code}")
print(f"Secret: {enrollment.secret}")
```

#### `list_user_factors(user_id)`

List all enrolled factors for a user.

**Parameters:**

- `user_id` (required): User identifier

**Returns:** `list[dict]`

```python
factors = await client.list_user_factors(user_id="user123")
for factor in factors:
    print(f"Factor: {factor['type']}, ID: {factor['id']}")
```

#### `remove_factor(user_id, factor_id)`

Remove an enrolled factor from a user.

**Parameters:**

- `user_id` (required): User identifier
- `factor_id` (required): Factor identifier to remove

**Returns:** `bool` (True if successful)

```python
await client.remove_factor(
    user_id="user123",
    factor_id="factor_456"
)
```

## Types

### UVBSession

Session information returned by `validate_session()`.

```python
@dataclass
class UVBSession:
    user_id: str
    tenant_id: str
    session_id: str
    factors_verified: list[str]
    expires_at: datetime
    status: SessionStatus
    metadata: dict[str, Any]
```

### VerificationResponse

Response from `verify()` operation.

```python
@dataclass
class VerificationResponse:
    success: bool
    session_id: str | None
    session_token: str | None
    expires_at: datetime | None
    factors_verified: list[str]
    message: str | None
    error: str | None
```

### EnrollmentResponse

Response from `enroll_factor()` operation.

```python
@dataclass
class EnrollmentResponse:
    success: bool
    enrollment_id: str | None
    qr_code: str | None  # For TOTP
    secret: str | None  # For TOTP
    challenge: dict | None  # For WebAuthn
    message: str | None
    error: str | None
```

### FactorType

Enum of supported authentication factor types:

- `OAUTH`
- `TOTP`
- `WEBAUTHN`
- `EMAIL_OTP`
- `SMS_OTP`
- `WHATSAPP`
- `VOICE_CALL`
- `PUSH`

## Examples

### Multi-Factor Authentication

```python
async def verify_with_mfa(client, user_id):
    # First factor: TOTP
    response1 = await client.verify(
        user_id=user_id,
        factor_type="totp",
        factor_value="123456"
    )

    if not response1.success:
        return False

    # Second factor: WebAuthn
    response2 = await client.verify(
        user_id=user_id,
        factor_type="webauthn",
        factor_value=webauthn_credential
    )

    return response2.success
```

### Context Manager Usage

```python
async with UVBClient(tenant_id="my-tenant") as client:
    response = await client.verify(
        user_id="user123",
        factor_type="totp",
        factor_value="123456"
    )
# Client automatically closes when exiting context
```

### Error Handling

```python
from uvb import UVBClient, UVBAuthenticationError, UVBAPIError

async def safe_verify(client, user_id, code):
    try:
        response = await client.verify(
            user_id=user_id,
            factor_type="totp",
            factor_value=code
        )
        return response.success
    except UVBAuthenticationError as e:
        print(f"Authentication failed: {e}")
        return False
    except UVBAPIError as e:
        print(f"API error (status {e.status_code}): {e}")
        return False
```

### Enrolling Multiple Factors

```python
async def setup_user_mfa(client, user_id):
    # Enroll TOTP
    totp_enrollment = await client.enroll_factor(
        user_id=user_id,
        factor_type="totp"
    )
    print(f"TOTP Secret: {totp_enrollment.secret}")
    print(f"QR Code: {totp_enrollment.qr_code}")

    # Enroll WebAuthn
    webauthn_enrollment = await client.enroll_factor(
        user_id=user_id,
        factor_type="webauthn"
    )
    print(f"WebAuthn Challenge: {webauthn_enrollment.challenge}")

    # List all factors
    factors = await client.list_user_factors(user_id=user_id)
    print(f"User has {len(factors)} factors enrolled")
```

## Development

```bash
# Install development dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Type checking
mypy uvb

# Code formatting
black uvb
ruff check uvb
```

## License

MIT
