# gnexus-gauth

Framework-agnostic Python client library for integrating services with `gnexus-auth`.

## Status

Alpha — early scaffold with working core pieces.

Current scaffold includes:

- package metadata;
- high-level `GAuthClient`;
- configuration object;
- DTO set;
- storage and service contracts;
- exception family;
- PKCE and authorization URL helpers;
- HTTP token endpoint client;
- HTTP userinfo client;
- webhook HMAC verifier;
- webhook JSON parser;
- package-level unit tests;
- plain Python integration example.

## Requirements

- Python 3.11+
- `httpx`

## Installation

```bash
pip install gnexus-gauth
```

Or from source:

```bash
pip install git+https://git.gnexus.space/git/root/gnexus-auth-client-py.git
```

## Usage Shape

The package is designed around one high-level client:

```python
from gnexus_gauth.client import GAuthClient
```

It expects:

- `GAuthConfig`
- token endpoint implementation
- runtime user provider
- webhook verifier
- webhook parser
- state store
- PKCE store

### Quick Example

```python
from gnexus_gauth.client import GAuthClient
from gnexus_gauth.config import GAuthConfig
from gnexus_gauth.oauth import HttpTokenEndpoint
from gnexus_gauth.runtime import HttpRuntimeUserProvider
from gnexus_gauth.webhook import HmacWebhookVerifier, JsonWebhookParser
from gnexus_gauth.support import InMemoryStateStore, InMemoryPkceStore

config = GAuthConfig(
    base_url="https://gnexus-auth.local",
    client_id="my-service",
    client_secret="my-secret",
    redirect_uri="https://my-service.local/callback",
)

client = GAuthClient(
    config=config,
    token_endpoint=HttpTokenEndpoint(config),
    runtime_user_provider=HttpRuntimeUserProvider(config),
    webhook_verifier=HmacWebhookVerifier(config),
    webhook_parser=JsonWebhookParser(),
    state_store=InMemoryStateStore(),
    pkce_store=InMemoryPkceStore(),
)

# Build authorization URL
auth_request = client.build_authorization_request(
    return_to="/dashboard",
    scopes=["openid", "email", "profile"],
)
print(auth_request.authorization_url)

# Exchange callback code
token_set = client.exchange_authorization_code("code_from_callback", "state_from_callback")
user = client.fetch_user(token_set.access_token)

# Verify and parse webhook
event = client.verify_and_parse_webhook(raw_body, headers, "webhook_secret")
```

### User avatar

After fetching the user, avatar data is available through the `AuthenticatedUser` object:

```python
user = client.fetch_user(token_set.access_token)

# Direct avatar URL (or None if not set)
print(user.avatar_url)

# Size variants: small, medium, large, xlarge
for variant, url in user.avatar_variants.items():
    print(f"{variant}: {url}")
```

The `avatar_url` and `avatar_variants` are read from the `profile` section of the `/oauth/userinfo` response. Avatar URLs are public — no additional token is required to download the image.

If you need the raw binary data of an avatar, use any HTTP client:

```python
import httpx

if user.avatar_url:
    response = httpx.get(user.avatar_url)
    image_bytes = response.content
```

See `examples/plain/example.py` for a more complete demonstration.

## Package Structure

```text
src/gnexus_gauth/
  __init__.py
  client.py       # GAuthClient
  config.py       # GAuthConfig
  contracts.py    # Abstract interfaces
  dto.py          # Data transfer objects
  exceptions.py   # Exception hierarchy
  oauth.py        # PKCE, URL builder, token endpoint
  runtime.py      # Userinfo client
  support.py      # In-memory stores, system clock
  webhook.py      # HMAC verifier, JSON parser
```

## Development

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

# Run tests
pytest

# Run linter
ruff check src tests

# Run type checker
mypy src
```

## Related

- PHP version: `gnexus/auth-client`
- Auth server: `gnexus-auth`
