Metadata-Version: 2.4
Name: jengolabs-auth
Version: 0.1.0
Summary: Python SDK for Jengo Auth — session verification, FastAPI middleware, and role-based access control
Project-URL: Repository, https://github.com/jengolabs/jen-auth
Project-URL: Documentation, https://github.com/jengolabs/jen-auth/blob/main/docs/dx/DX.md
Author: Jengo Labs
License-Expression: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: FastAPI
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: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: all
Requires-Dist: fastapi>=0.100.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: fastapi>=0.100.0; extra == 'dev'
Requires-Dist: mypy>=1.13.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.8.0; extra == 'dev'
Requires-Dist: uvicorn>=0.30.0; extra == 'dev'
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.100.0; extra == 'fastapi'
Description-Content-Type: text/markdown

# jengolabs-auth

Python SDK for [Jengo Auth](https://github.com/jengolabs/jen-auth) — session verification, FastAPI middleware, and role-based access control.

## Install

```bash
pip install jengolabs-auth[fastapi]
```

## Quick Start (FastAPI)

### Option 1: Dependency Injection

```python
from fastapi import FastAPI, Depends
from jengolabs_auth import AuthClient, AuthClientConfig
from jengolabs_auth.fastapi import require_auth, require_app_role

auth_client = AuthClient(AuthClientConfig(
    auth_server_url="http://localhost:4000",
    tenant_api_key="your-tenant-api-key",
    app_slug="my-service",
    cache_ttl_seconds=30,
))

app = FastAPI()

@app.get("/api/me")
async def get_me(session=require_auth(auth_client)):
    return {"id": session.user.id, "email": session.user.email}

@app.delete("/api/resource/{resource_id}")
async def delete_resource(
    resource_id: str,
    session=require_app_role("admin", auth_client=auth_client),
):
    return {"deleted": resource_id}
```

### Option 2: Middleware

```python
from fastapi import FastAPI, Request
from jengolabs_auth import AuthClient, AuthClientConfig
from jengolabs_auth.fastapi import JengoAuthMiddleware

auth_client = AuthClient(AuthClientConfig(
    auth_server_url="http://localhost:4000",
    tenant_api_key="your-tenant-api-key",
    app_slug="my-service",
))

app = FastAPI()
app.add_middleware(
    JengoAuthMiddleware,
    auth_client=auth_client,
    public_paths=["/health", "/docs", "/openapi.json"],
)

@app.get("/api/me")
async def get_me(request: Request):
    user = request.state.auth_user
    return {"id": user.id, "email": user.email}
```

### Option 3: Manual Verification

```python
from jengolabs_auth import AuthClient, AuthClientConfig, AuthenticationError

auth_client = AuthClient(AuthClientConfig(
    auth_server_url="http://localhost:4000",
    tenant_api_key="your-tenant-api-key",
    app_slug="my-service",
))

async def verify_token(token: str):
    try:
        session = await auth_client.verify_session(f"Bearer {token}")
        return session.user
    except AuthenticationError:
        return None
```

## Models

All models are Pydantic v2 and support both snake_case and camelCase fields:

| Model | Fields |
|---|---|
| `AuthUser` | id, email, name, email_verified, image, role, created_at, updated_at |
| `AuthSessionData` | id, token, expires_at |
| `AuthAppGrant` | app_slug, role, granted_at |
| `AuthSessionWithGrant` | user, session, app_grant, organization |

## Session Caching

Enable in-memory caching to reduce auth server calls:

```python
auth_client = AuthClient(AuthClientConfig(
    auth_server_url="http://localhost:4000",
    tenant_api_key="your-tenant-api-key",
    app_slug="my-service",
    cache_ttl_seconds=30,  # cache sessions for 30 seconds
))
```

## License

MIT
