Metadata-Version: 2.4
Name: myauth
Version: 0.3.0
Summary: Reusable FastAPI + MongoDB authentication package (JWT + OTP based)
Requires-Python: >=3.10
Requires-Dist: aiosmtplib>=5.1.0
Requires-Dist: bcrypt==4.0.1
Requires-Dist: email-validator>=2.0.0
Requires-Dist: fastapi>=0.141.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: motor>=3.7.0
Requires-Dist: passlib[bcrypt]>=1.7.4
Requires-Dist: pydantic-settings>=2.14.0
Requires-Dist: pydantic>=2.13.0
Requires-Dist: python-jose[cryptography]>=3.5.0
Requires-Dist: python-multipart>=0.0.32
Requires-Dist: slowapi>=0.1.9
Description-Content-Type: text/markdown

# myauth

Reusable **FastAPI + MongoDB** authentication package. Ek baar banao, har project me `pip install` karke use karo.

**v2 — production-hardened:** rate limiting, login-lockout, refresh-token rotation + reuse-detection, RBAC, audit logging, logout-all-devices.

---

## Installation

```bash
pip install myauth
```

---

## Quick Start

```python
from fastapi import FastAPI
from myauth import AuthConfig, auth_router, init_auth

app = FastAPI()
app.include_router(auth_router)

config = AuthConfig(
    db_url="mongodb://localhost:27017",
    jwt_secret="a-very-long-random-secret-at-least-32-characters",
    smtp_host="smtp.gmail.com",
    smtp_port=587,
    smtp_user="you@gmail.com",
    smtp_password="your-app-password",
    sender_email="noreply@yourapp.com",
)

@app.on_event("startup")
async def on_startup():
    # 'app' zaroori hai — isi se rate limiting FastAPI ke sath wire hoti hai
    await init_auth(config, app=app)
```

---

## Endpoints (10)

| Method | Path | Rate Limit (default) | Kaam |
|---|---|---|---|
| POST | `/auth/register` | 3/min | Naya account, verification OTP email pe jata hai |
| POST | `/auth/login` | 5/min | Email+password → access + refresh token |
| POST | `/auth/refresh` | 5/min | Refresh token **rotate** hota hai — purana turant invalid |
| POST | `/auth/logout` | 30/min | Current session revoke |
| POST | `/auth/logout-all` | 30/min | **Har device/session** ek saath revoke (Bearer token chahiye) |
| GET | `/auth/me` | 30/min | Current logged-in user ka data (role samet) |
| POST | `/auth/forgot-password` | 3/min | Password reset OTP bhejna |
| POST | `/auth/reset-password` | 5/min | OTP verify karke naya password set karna |
| POST | `/auth/verify-email` | 5/min | Register OTP se email confirm karna |
| POST | `/auth/resend-verification` | 3/min | Naya verification OTP dobara bhejwana |

Limit cross hone par `429 Too Many Requests` milta hai. Interactive docs: `http://localhost:8000/docs`

---

## Configuration (`AuthConfig`)

### Core
| Field | Required | Default |
|---|---|---|
| `db_url` | ✅ | — |
| `db_name` | ❌ | `myauth_db` |
| `jwt_secret` | ✅ (32+ chars) | — |
| `access_token_expiry_minutes` | ❌ | `15` |
| `refresh_token_expiry_days` | ❌ | `7` |
| `smtp_host` / `smtp_user` / `smtp_password` / `sender_email` | ✅ | — |

### Security (v2)
| Field | Default | Kaam |
|---|---|---|
| `max_login_attempts` | `5` | Itni galat tries ke baad account lock |
| `lockout_duration_minutes` | `15` | Lock kitni der rahega |
| `password_min_length` | `10` | + upper/lower/digit/special char zaroori |
| `otp_resend_cooldown_seconds` | `60` | OTP spam se bachao |
| `strict_ip_binding` | `False` | On karne par refresh-token IP change par revoke ho jata hai |
| `rate_limit_login` / `rate_limit_register` / `rate_limit_otp_request` / `rate_limit_otp_verify` / `rate_limit_general` | see table above | Per-endpoint limits |
| `rate_limit_storage_uri` | `"memory://"` | ⚠️ **Production me `"redis://host:6379"` set karein** — warna multi-server deployment me limit bypass ho sakti hai |
| `require_captcha_on_register` | `False` | On karke `captcha_verify_url` + `captcha_secret` dena zaroori |

**Secrets:** `.env` me rakhein, `os.getenv()` se pass karein — package khud `.env` nahi padhta.

---

## Security Features

- **Passwords/OTPs:** bcrypt hashed, kabhi plaintext store nahi
- **JWT:** access (`role` claim samet) + refresh, dono me unique `jti` — access/refresh ek dusre ki jagah use nahi ho sakte
- **Refresh token rotation:** har `/refresh` par purana token turant invalid; **reuse detect** hone par (chori hua token dobara use ho) pura session-family revoke — attacker aur legit user dono re-login karenge
- **Login lockout:** `max_login_attempts` ke baad `423 Locked`, email-keyed (no enumeration via lockout timing)
- **RBAC:** `role` field + `require_role("admin")` dependency apne routes pe use karein:
  ```python
  from myauth import require_role
  @app.get("/admin/users")
  async def list_users(user: dict = Depends(require_role("admin"))):
      ...
  ```
- **Audit log:** login/register/lockout/reuse-detection/logout-all sab `audit_logs` collection me (90-din TTL)
- **Email enumeration protection:** `forgot-password`/`resend-verification` hamesha same generic response dete hain
- **Rate limiting:** `slowapi`, per-endpoint config-driven limits (upar table dekhein)

---

## Roadmap / Known Scope

- **Database:** Filhal sirf **MongoDB** support hai (Motor). PostgreSQL support jaan-boojh kar abhi nahi banaya — isay properly karne ke liye Repository Pattern (database-agnostic abstraction layer) chahiye hoga, jo poori codebase restructure kar deta. Jab koi real project Postgres demand karega, tab v2 me isay implement karenge — us waqt requirements clearer honge.

---

## Project Structure

```
myauth/
├── pyproject.toml
├── src/myauth/
│   ├── __init__.py         # init_auth(config, app), auth_router, require_role export
│   ├── config.py           # AuthConfig + validation
│   ├── db.py                # Motor connection + collections
│   ├── security.py          # hashing, JWT (role + jti claims), token-family
│   ├── otp.py                # OTP generate/verify/cooldown
│   ├── email.py               # SMTP
│   ├── password_policy.py     # complexity rules
│   ├── lockout.py              # brute-force lockout
│   ├── rate_limiting.py         # slowapi wiring
│   ├── captcha.py                # optional captcha hook
│   ├── audit.py                    # security event logging
│   ├── models.py                    # Pydantic schemas
│   ├── dependencies.py               # get_current_user, require_role
│   └── router.py                      # 10 endpoints
└── tests/
```
