Metadata-Version: 2.4
Name: memydev-auth-sdk
Version: 0.1.0
Summary: Official MemyAuth (OIDC + IAM) client SDK for Python
License: Proprietary and unlicensed pending approved service terms.
Requires-Python: >=3.11
Requires-Dist: httpx<1,>=0.27
Requires-Dist: pyjwt[crypto]<3,>=2.9
Provides-Extra: dev
Requires-Dist: editables==0.5; extra == 'dev'
Requires-Dist: hatchling==1.27.0; extra == 'dev'
Requires-Dist: pytest-asyncio==0.24.0; extra == 'dev'
Requires-Dist: pytest==8.3.5; extra == 'dev'
Requires-Dist: respx==0.22.0; extra == 'dev'
Requires-Dist: unasync==0.6.0; extra == 'dev'
Description-Content-Type: text/markdown

# memydev-auth-sdk

Official Python client for **MemyAuth** — the estate's OIDC + IAM provider. Import name: `memyauth`.

```python
import asyncio
from memyauth import MemyAuth

async def main() -> None:
    async with MemyAuth(
        issuer_url="https://auth.memy.dev/oidc",
        client_id="my-app",
        client_secret="...",
        public_base_url="https://my-app.example.com",
        id_token_validation="local-jwks",   # or "tls-token-endpoint" — see below, no default
    ) as auth:
        req = await auth.oidc.build_authorization_url()
        # redirect the browser to req.url, persist req via auth.state.sign(...)
        ...

asyncio.run(main())
```

A synchronous facade is available for non-async callers:

```python
from memyauth.sync import MemyAuth

with MemyAuth(issuer_url=..., client_id=..., client_secret=..., id_token_validation="local-jwks") as auth:
    tokens = auth.oidc.exchange_code(code=..., code_verifier=...)
```

## Choosing `id_token_validation`

MemyAuth signs ID tokens with **ES384 only**. Two ID-token trust strategies are both in production
use across the estate and neither is a silent default — you must choose:

- `local-jwks` (**recommended for new consumers**): verifies the ID token's signature locally
  against the provider's JWKS, with an explicit algorithm allow-list (`["ES384"]` by default).
  Stateless, no extra round trip, defends against ID-token substitution.
- `tls-token-endpoint`: performs **no** local signature verification; identity is derived from the
  direct TLS channel to the token endpoint (OIDC Core §3.1.3.7 item 6) plus `/oidc/me` or
  `/iam/me`. Choose this only when you never process the ID token directly.

An `allowed_algorithms` pin that cannot verify any token this provider issues (e.g. `["RS256"]`)
fails loudly at construction with `UnsupportedAlgorithmPinError` — this SDK exists in large part to
make that historically-real defect (shipped twice against this provider) impossible to repeat
silently.

## Async is the source of truth

`memyauth/_*.py` are hand-written and authoritative. `memyauth/_sync/*.py` and the `memyauth.sync`
facade are **mechanically generated** from them by `scripts/gen_sync.py` (via `unasync`) — never
hand-edit `_sync/`. Regenerate after any async change:

```
python scripts/gen_sync.py            # write the twins
python scripts/gen_sync.py --check    # verify no drift; exits non-zero if the twins are stale
```

## Development

```
python3 -m venv .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install hatchling==1.27.0 editables==0.5
.venv/bin/python -m pip install --no-build-isolation -e ".[dev]"
.venv/bin/python -m pytest -q
```
