Metadata-Version: 2.4
Name: aura-auth
Version: 0.1.0
Summary: Pluggable authentication framework for FastAPI.
Author-email: Chapi <chapimenge3@gmail.com>
Requires-Python: >=3.11
Requires-Dist: aiosqlite>=0.17
Requires-Dist: bcrypt>=4.0
Requires-Dist: email-validator>=2.0
Requires-Dist: fastapi>=0.100
Requires-Dist: pydantic>=2.0
Requires-Dist: pyjwt[crypto]>=2.0
Requires-Dist: python-multipart>=0.0.5
Requires-Dist: sqlalchemy[asyncio]>=2.0
Provides-Extra: 2fa
Requires-Dist: pyotp>=2.9; extra == '2fa'
Provides-Extra: admin
Requires-Dist: jinja2>=3.0; extra == 'admin'
Provides-Extra: all
Requires-Dist: aiomysql>=0.2; extra == 'all'
Requires-Dist: asyncpg>=0.27; extra == 'all'
Requires-Dist: httpx>=0.24; extra == 'all'
Requires-Dist: jinja2>=3.0; extra == 'all'
Requires-Dist: pyotp>=2.9; extra == 'all'
Requires-Dist: sqlmodel>=0.0.14; extra == 'all'
Requires-Dist: webauthn>=2.0; extra == 'all'
Provides-Extra: facebook
Requires-Dist: httpx>=0.24; extra == 'facebook'
Provides-Extra: github
Requires-Dist: httpx>=0.24; extra == 'github'
Provides-Extra: google
Requires-Dist: httpx>=0.24; extra == 'google'
Provides-Extra: magic-link
Requires-Dist: httpx>=0.24; extra == 'magic-link'
Provides-Extra: mysql
Requires-Dist: aiomysql>=0.2; extra == 'mysql'
Provides-Extra: oauth
Requires-Dist: httpx>=0.24; extra == 'oauth'
Provides-Extra: otp
Provides-Extra: passkey
Requires-Dist: webauthn>=2.0; extra == 'passkey'
Provides-Extra: postgres
Requires-Dist: asyncpg>=0.27; extra == 'postgres'
Provides-Extra: sqlmodel
Requires-Dist: sqlmodel>=0.0.14; extra == 'sqlmodel'
Description-Content-Type: text/markdown

<div align="center">

# Aura Auth

**Batteries-included authentication for FastAPI — install, wire three lines, ship.**

![Python 3.11+](https://img.shields.io/badge/python-3.11+-3776AB?style=flat&logo=python&logoColor=white)
![FastAPI](https://img.shields.io/badge/FastAPI-0.100+-009688?style=flat&logo=fastapi&logoColor=white)
![License](https://img.shields.io/badge/license-TBD-lightgrey?style=flat)

</div>

> **Early beta** — APIs, module layout, and defaults may change without a major-version bump while we learn from real apps. Pin versions in production and read the release notes when upgrading.

---

## Why this exists

If you have built auth in Python, you have probably felt the same friction:

- **“Batteries included” rarely means “works on Monday.”** You still glue together hashing, JWTs, a user model, migrations, login routes, dependency injection, and error shapes — often from blog posts that disagree with each other.
- **Frameworks tend to stop at the tutorial.** The happy path is documented; edge cases, transport choices (cookie vs bearer), and clean extension points are left as an exercise.
- **Teams get discouraged** and either ship something fragile, over-buy a SaaS, or copy-paste security-sensitive code they do not fully own.

**Aura Auth** is an attempt to fix that for the **FastAPI + async SQLAlchemy** lane: a **small, explicit library** where the default install gives you **email/password auth that actually runs** — models, backend, strategy, JWTs, and a ready-made router — while **optional extras** stay pluggable (OAuth, magic links, OTP, 2FA, passkeys, etc.) as the project grows.

We are not trying to be every auth product at once on day one. We *are* trying to be the library you reach for when you want **clarity, defaults that work, and a path to more** without rewriting your app.

---

## What you get today (default install)

| Capability | Notes |
|------------|--------|
| **User model + mixin** | UUID user table you can subclass |
| **Async SQLAlchemy backend** | CRUD with sensible errors (e.g. duplicate email) |
| **Password strategy** | bcrypt + strength checks |
| **JWT access tokens** | HS256, standard claims (`sub`, `exp`, `iat`, `jti`) |
| **Bearer + cookie transports** | Switch via config |
| **`UserManager`** | Register, login, verify token, email-verify flow hooks |
| **FastAPI integration** | `AuraAuth`, `init_app`, `/auth/*` router, `current_user` dependencies |

Optional installs (see `pyproject.toml` → `[project.optional-dependencies]`) add **OAuth** (`google`, `github`, `facebook`, `oauth`), **magic-link**, **2fa**, **passkey**, **sqlmodel**, **admin**, **postgres**, **mysql**, and an **`all`** extra.

---

## Installation

Requires **Python 3.11+**. `email-validator` is included so Pydantic `EmailStr` works out of the box.

**From PyPI** (once the package is published):

```bash
uv add aura-auth
# or
pip install aura-auth
```

**From GitHub** (typical during early beta):

```bash
uv add "aura-auth @ git+https://github.com/YOUR_ORG/aura-auth.git"
# or
pip install "git+https://github.com/YOUR_ORG/aura-auth.git"
```

Replace `YOUR_ORG/aura-auth` with your real repository path. For local development, use `uv pip install -e .` from a clone of this repo.

---

## Quickstart (copy-paste)

Minimal FastAPI app: create tables on startup, mount auth, protect a route.

```python
from fastapi import Depends, FastAPI

from aura_auth import AuraAuth

app = FastAPI()

# Use a long random secret in production (≥32 bytes for HS256 is a good habit).
auth = AuraAuth(
    database_url="sqlite+aiosqlite:///./app.db",
    secret="change-me-to-a-long-random-secret-at-least-32-chars",
)


@app.on_event("startup")
async def startup() -> None:
    await auth.create_tables()


auth.init_app(app)  # registers /auth routes + exception handlers


@app.get("/protected")
async def protected(user=Depends(auth.current_user())):
    return {"message": f"Hello, {user.email}"}
```

**Endpoints added by `init_app`:**

| Method | Path | Purpose |
|--------|------|---------|
| `POST` | `/auth/register` | Create user (email + password) |
| `POST` | `/auth/login` | Returns `{ "access_token", "token_type" }`; sets cookie if you use cookie transport |
| `POST` | `/auth/logout` | Clears cookie when using cookie transport |
| `GET` | `/auth/me` | Current user (requires `Authorization: Bearer <token>` by default) |

**Dependencies you can attach to routes:**

- `Depends(auth.current_user())` — must be authenticated (401 otherwise)
- `Depends(auth.current_active_user())` — must be active (403 if inactive)
- `Depends(auth.current_verified_user())` — must be active and verified (403 if not)

---

## Mental model (for humans and AI coding agents)

Think in **four layers**. Everything else hangs off these names in the repo.

```mermaid
flowchart LR
  subgraph transport [Transport]
    T[Bearer / Cookie]
  end
  subgraph strategy [Strategy]
    S[Password — more later]
  end
  subgraph backend [Backend]
    B[SQLAlchemy async CRUD]
  end
  subgraph data [Data]
    M[User model + JWT]
  end
  T <--> M
  S <--> B
  B <--> M
```

| Layer | Role | Main entry points in code |
|-------|------|---------------------------|
| **Transport** | How the token is read/written on HTTP | `aura_auth.transport.*` |
| **Strategy** | How credentials become a user + hooks | `aura_auth.strategies.password` |
| **Backend** | Persistence implementing the backend protocol | `aura_auth.backend.sqlalchemy` |
| **Orchestration** | Wires pieces together for apps | `aura_auth.app.AuraAuth`, `aura_auth.manager.UserManager` |

**Contracts** (types, protocols, schemas, exceptions, security helpers) live under **`aura_auth._core`**. Routers and FastAPI dependencies live beside them under **`aura_auth.router`** and **`aura_auth.dependencies`**.

If you are an **AI agent** implementing or extending this library:

1. Read **`AGENTS.md`** in this repo — it is the canonical phased plan, folder target, and conventions (imports, docstrings, testing layout).
2. Prefer **protocols** in `_core` over importing concrete backends from “higher” layers — keeps cycles and coupling down.
3. Run **`make check`** (or `uv run ruff check .`, `uv run ty check`, `uv run pytest`) before proposing a PR-style change.

---

## Configuration highlights

`AuraAuth(database_url=..., secret=..., **kwargs)` forwards supported keys to **`AuraAuthConfig`** (`aura_auth._core.config`), including:

- `token_lifetime_seconds` — access JWT lifetime (default `3600`)
- `verify_token_lifetime_seconds` — email verification token lifetime
- `cookie_transport` — use HTTP-only cookie transport instead of bearer header for token I/O
- `password_min_length` — minimum password length (default `8`)
- `user_model` — optional custom SQLAlchemy user model
- `engine` — *advanced / testing*: inject a pre-built async engine (see tests)

---

## Development

Clone the repo, then:

```bash
make sync    # install with dev dependencies (uv)
make check   # lint + format check + types + tests
```

Individual targets: `make lint`, `make format`, `make type`, `make test`, `make test-cov`.

---

## Project layout (source of truth)

```
src/aura_auth/
├── _core/           # types, protocols, schemas, exceptions, config, security
├── app.py           # AuraAuth + FastAPI wiring
├── manager.py       # UserManager (orchestration)
├── models/          # SQLAlchemy mixins + default user model
├── backend/         # BaseBackend + SQLAlchemy implementation
├── strategies/      # Password (extensible)
├── transport/       # Bearer + cookie
├── router/          # FastAPI auth routes
├── dependencies.py  # current_user, active, verified
└── __init__.py      # lazy export of AuraAuth (avoids heavy imports on submodule import)
```

Tests mirror this under `tests/` (see `AGENTS.md` for the full testing map).

---

## Roadmap & stability

- **Now:** Email/password, JWT, SQLAlchemy async backend, FastAPI router and dependencies, bearer/cookie transports.
- **Next:** Optional extras (OAuth, magic links, OTP, 2FA, passkeys) as documented in `AGENTS.md` and `pyproject.toml` extras.
- **Stability:** Until **1.0**, treat semver as *best effort*; breaking changes may land in **0.x** while the public surface stabilizes. Issues and design feedback are welcome.

---

## License

License TBD — add a `LICENSE` file when you publish to GitHub.

---

<div align="center">

**Built so you spend less time wiring auth and more time shipping your product.**

If Aura Auth saves you a day, a star on GitHub helps others find it.

</div>
