Metadata-Version: 2.4
Name: softauth
Version: 0.1.0
Summary: Zero-setup JWT authentication for FastAPI and Flask
Author: Soft Tech Talks
License: MIT
Project-URL: Homepage, https://github.com/suhanapthn24/softauth.git
Project-URL: Repository, https://github.com/suhanapthn24/softauth.git
Project-URL: Documentation, https://softauth.readthedocs.io
Project-URL: Bug Tracker, https://github.com/suhanapthn24/softauth.git/issues
Keywords: authentication,jwt,fastapi,flask,security,rbac
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Framework :: FastAPI
Classifier: Topic :: Security
Classifier: Topic :: Internet :: WWW/HTTP :: Session
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyjwt>=2.8.0
Requires-Dist: passlib[bcrypt]>=1.7.4
Requires-Dist: pydantic>=2.0.0
Requires-Dist: sqlalchemy>=2.0.0
Requires-Dist: typer>=0.9.0
Requires-Dist: python-dotenv>=1.0.0
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.100.0; extra == "fastapi"
Requires-Dist: python-multipart>=0.0.6; extra == "fastapi"
Provides-Extra: flask
Requires-Dist: flask>=2.3.0; extra == "flask"
Provides-Extra: django
Requires-Dist: django>=4.2; extra == "django"
Provides-Extra: sqlmodel
Requires-Dist: sqlmodel>=0.0.14; extra == "sqlmodel"
Provides-Extra: dev
Requires-Dist: pytest>=7.4.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
Requires-Dist: httpx>=0.24.0; extra == "dev"
Requires-Dist: uvicorn>=0.23.0; extra == "dev"
Requires-Dist: fastapi[all]>=0.100.0; extra == "dev"
Requires-Dist: flask>=2.3.0; extra == "dev"
Requires-Dist: django>=4.2; extra == "dev"
Requires-Dist: python-multipart>=0.0.6; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Requires-Dist: mypy>=1.5.0; extra == "dev"
Dynamic: license-file

# softauth

**Zero-setup JWT authentication for FastAPI, Flask, and Django.**

[![CI](https://github.com/suhanapthn24/softauth/actions/workflows/ci.yml/badge.svg)](https://github.com/suhanapthn24/softauth/actions)
[![PyPI](https://img.shields.io/pypi/v/softauth)](https://pypi.org/project/softauth/)
[![Python](https://img.shields.io/pypi/pyversions/softauth)](https://pypi.org/project/softauth/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

---

## The problem

Every new project requires the same boilerplate:

- JWT helpers (create / decode / verify)  
- Password hashing  
- Auth routes (`/register`, `/login`, `/refresh`, `/me`)  
- Middleware that parses the token on every request  
- Role-based access control decorators or dependencies  
- User model + database table  

**softauth eliminates all of it.**

---

## Installation

```bash
# FastAPI
pip install "softauth[fastapi]"

# Flask
pip install "softauth[flask]"

# Both
pip install "softauth[fastapi,flask]"
```

---

## Quick start — FastAPI

```python
from fastapi import FastAPI, Depends
from softauth import SoftAuth

auth = SoftAuth(secret_key="your-secret", framework="fastapi")
app  = FastAPI()
auth.init_app(app)   # mounts /auth/* routes + JWT middleware
auth.init_db()       # creates the users table

@app.get("/profile")
def profile(user=Depends(auth.current_user)):
    return user.to_dict()

@app.get("/admin")
def admin(user=Depends(auth.current_admin)):
    return {"msg": f"hello admin {user.email}"}

@app.get("/editor")
def editor(user=Depends(auth.require_role("editor"))):
    return {"msg": f"hello editor {user.email}"}
```

Visit `/docs` — Swagger UI shows all auth routes and lets you log in directly.

---

## Quick start — Flask

```python
from flask import Flask, g, jsonify
from softauth import SoftAuth

auth = SoftAuth(secret_key="your-secret", framework="flask")
app  = Flask(__name__)
auth.init_app(app)   # registers /auth/* blueprint + before_request hook
auth.init_db()       # creates the users table

@app.route("/profile")
@auth.login_required
def profile():
    return jsonify(g.user.to_dict())

@app.route("/admin")
@auth.admin_required
def admin():
    return jsonify({"msg": f"hello admin {g.user.email}"})

@app.route("/editor")
@auth.require_role("editor")
def editor():
    return jsonify({"msg": f"hello editor {g.user.email}"})
```

---

## Auto-generated routes

| Method | Path              | Description                              |
|--------|-------------------|------------------------------------------|
| POST   | `/auth/register`  | Create a new account                     |
| POST   | `/auth/login`     | Exchange credentials for a token pair    |
| POST   | `/auth/refresh`   | Exchange a refresh token for access token|
| GET    | `/auth/me`        | Current user's profile                   |
| POST   | `/auth/logout`    | Instruct client to discard tokens        |

---

## Configuration

```python
auth = SoftAuth(
    secret_key="your-secret",          # required
    framework="fastapi",               # "fastapi" | "flask" | None (custom adapter)
    algorithm="HS256",                 # JWT algorithm
    access_expiry_minutes=15,          # access token lifetime
    refresh_expiry_days=7,             # refresh token lifetime
    database_url="sqlite:///auth.db",  # any SQLAlchemy URL
    auth_prefix="/auth",               # route prefix
    enable_refresh_tokens=True,
)
```

### Environment variables

| Variable            | Config field            |
|---------------------|-------------------------|
| `SOFTAUTH_SECRET`   | `secret_key`            |
| `SOFTAUTH_DB_URL`   | `database_url`          |
| `SOFTAUTH_ALGORITHM`| `algorithm`             |

---

## CLI

```bash
# Scaffold project
softauth init

# Generate FastAPI boilerplate
softauth setup fastapi

# Generate Flask boilerplate
softauth setup flask

# Print a secure secret key
softauth secret
```

---

## RBAC

Roles are stored on each user record.  Built-in roles: `user`, `manager`, `admin`.
Custom roles work out of the box — register a user with any role string.

| What                    | FastAPI                               | Flask                         |
|-------------------------|---------------------------------------|-------------------------------|
| Any authenticated user  | `Depends(auth.current_user)`          | `@auth.login_required`        |
| Admin only              | `Depends(auth.current_admin)`         | `@auth.admin_required`        |
| Specific role           | `Depends(auth.require_role("mgr"))`   | `@auth.require_role("mgr")`   |

Admin users are **always** allowed through `require_role()` checks.

---

## Custom adapters (Django, Litestar, Quart, …)

The core is 100% framework-agnostic.  Add support for any framework by
implementing `BaseAdapter` and calling `use_adapter()`:

```python
from softauth import SoftAuth
from softauth.interfaces import BaseAdapter

class DjangoAdapter(BaseAdapter):
    def init_app(self, app): ...
    def get_current_user_dependency(self): ...
    def get_current_admin_dependency(self): ...
    def get_require_role_dependency(self, role): ...

auth = SoftAuth(secret_key="...", framework=None)
auth.use_adapter(DjangoAdapter(auth, auth.config), django_app)
```

---

## Extension points

These interfaces are ready for future implementations without breaking the
existing API:

| Interface       | Purpose                                        |
|-----------------|------------------------------------------------|
| `BaseAdapter`   | Add any framework (Django, Litestar, Quart …)  |
| `AuthProvider`  | OAuth2 / social login (Google, GitHub …)       |
| `TokenStore`    | Redis token blacklisting, audit logs           |
| `UserStore`     | Custom identity backends, multi-tenant         |

---

## Architecture

```
softauth/
├── core/           # SoftAuth facade, SoftAuthConfig, exceptions
├── jwt/            # JWTHandler — zero framework imports
├── security/       # PasswordHandler — zero framework imports
├── database/       # SQLAlchemy models, session, repository
├── interfaces/     # BaseAdapter, AuthProvider, TokenStore, UserStore ABCs
├── fastapi/        # FastAPIAdapter, DependencyFactory, JWTMiddleware, routes
├── flask/          # FlaskAdapter, DecoratorFactory, middleware, routes
└── cli/            # Typer CLI commands
```

The JWT engine (`softauth.jwt`) and password handler (`softauth.security`) import
nothing from any web framework.  Adapters are loaded lazily so installing only
`fastapi` or only `flask` works without errors.

---

## Testing

```bash
pip install -e ".[dev]"
pytest --cov=softauth
```

Minimum required coverage: **90 %**

---

## Versioning

This project follows [Semantic Versioning](https://semver.org/).
See [CHANGELOG.md](CHANGELOG.md) for the full history.

### Releasing

```bash
git tag v0.2.0
git push origin v0.2.0
# GitHub Actions builds and publishes to PyPI automatically
```

---

## License

[MIT](LICENSE)
