Metadata-Version: 2.4
Name: auth
Version: 2.3.1
Summary: Authorization for humans
Author-email: Farshid Ashouri <farsheed.ashouri@gmail.com>
License-Expression: MIT
Keywords: authorization,role,auth,groups,membership,ensure,ldap
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Natural Language :: English
Classifier: Intended Audience :: Developers
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: Implementation :: CPython
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: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: flask<4,>=2.0.0
Requires-Dist: flask-cors<7,>=3.0.0
Requires-Dist: sqlalchemy<3,>=2.0.0
Requires-Dist: waitress<4,>=2.0.0
Requires-Dist: cryptography<48,>=3.0.0
Requires-Dist: APScheduler<4,>=3.0.0
Requires-Dist: psycopg[binary]<4,>=3.0.0
Requires-Dist: pydantic<3,>=2.0.0
Requires-Dist: pydantic-settings<3,>=2.0.0
Requires-Dist: requests<3,>=2.25.0
Requires-Dist: bleach<7,>=5.0.0
Requires-Dist: python-json-logger<4,>=3.1.0
Provides-Extra: ratelimit
Requires-Dist: flask-limiter>=3.0.0; extra == "ratelimit"
Provides-Extra: migrations
Requires-Dist: alembic>=1.13.0; extra == "migrations"
Provides-Extra: dev
Requires-Dist: pytest>=6.0; extra == "dev"
Requires-Dist: pytest-cov>=2.0; extra == "dev"
Requires-Dist: alembic>=1.13.0; extra == "dev"
Requires-Dist: ruff>=0.0.260; extra == "dev"
Requires-Dist: mypy>=1.0; extra == "dev"
Requires-Dist: types-requests; extra == "dev"
Requires-Dist: types-waitress; extra == "dev"
Requires-Dist: black>=22.0; extra == "dev"
Requires-Dist: isort>=5.0; extra == "dev"
Requires-Dist: responses>=0.23; extra == "dev"
Dynamic: license-file

# auth — RBAC authorization service

[![CI](https://github.com/ourway/auth/actions/workflows/ci.yml/badge.svg)](https://github.com/ourway/auth/actions/workflows/ci.yml)
[![Python](https://img.shields.io/badge/python-3.11%2B-blue)]()
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)

Role-based access control over HTTP. `auth` answers one question — **may user X
do Y** — so your services don't reinvent roles and permissions.

It is **authorization, not authentication**: it does not log anyone in, store
passwords, or issue tokens. It trusts that the caller already knows *who* the
user is, and decides *what they may do*. Model:
`user → (member of) → role → (holds) → permission`.

## Quickstart

Your **client key is any UUID4** — it is also your private, isolated namespace.
Generate one, keep it secret, and reuse it for every call. A role must exist
before you add members or permissions to it.

```bash
KEY=$(python3 -c "import uuid; print(uuid.uuid4())")
BASE=https://auth.rodmena.app

curl -X POST -H "Authorization: Bearer $KEY" $BASE/api/role/engineers
curl -X POST -H "Authorization: Bearer $KEY" $BASE/api/permission/engineers/deploy
curl -X POST -H "Authorization: Bearer $KEY" $BASE/api/membership/alice/engineers
curl        -H "Authorization: Bearer $KEY" $BASE/api/has_permission/alice/deploy
# -> {"success": true, "data": {"has_permission": true}, ...}
```

With the Python client (`pip install auth`):

```python
from auth import Client

with Client(api_key=KEY, service_url="https://auth.rodmena.app") as c:
    c.create_role("engineers")
    c.add_permission("engineers", "deploy")
    c.add_membership("alice", "engineers")
    c.user_has_permission("alice", "deploy")   # -> {... "has_permission": true}
```

## Things to know before you write code

- **Writes can return HTTP 200 with `{"result": false}`** (e.g. adding to a
  missing role). Check the `result`/`data` field, not just the status code.
- **Two response shapes** — bare `{"result": ...}` and wrapped
  `{"success", "data", ...}`. The API reference says which per endpoint.
- **Errors below 2xx are HTML**, not JSON. Branch on the status code first.
- **Reuse one key.** A new key is a new empty namespace, not an error. Keep the
  key out of source control, logs, and URLs — it is the only thing protecting
  your data. Rotate it with `POST /api/keys/rotate` if it leaks.

## Documentation

| Doc | What's in it |
|---|---|
| **Live API reference** — [`/docs`](https://auth.rodmena.app/docs) · [`/llms.txt`](https://auth.rodmena.app/llms.txt) | Every endpoint and exact response shape, served by the app (agent-friendly). |
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Design, components, request lifecycle, data model, permission-check and key-rotation flows, diagrams. |
| [SECURITY.md](SECURITY.md) | Security model (tenant isolation, encryption, audit, rotation), threat notes, reporting. |
| [MIGRATIONS.md](MIGRATIONS.md) | Schema creation vs migrations, upgrade/rollback runbook. |
| [CONTRIBUTING.md](CONTRIBUTING.md) | Local setup, tests (sqlite + postgres), lint/type-check, CI. |
| [docs/](docs/) | Full Sphinx docs (concepts, configuration, encryption, deployment, REST & Python usage). |

## When to use — and not

**Use it** for RBAC: named roles, permissions, group membership, and boolean
"can user X do Y" gates for a service, CLI, or workflow engine.

**Not** for authentication (login/passwords/sessions/OAuth/JWT), fine-grained /
attribute-based rules (owner-of-*this*-record, time-of-day, row-level tenancy —
reach for an ABAC/policy engine), or air-gapped hot loops where a network hop per
check is too costly (cache, or use the library in-process).

## Development

```bash
python3.11 -m venv .venv && . .venv/bin/activate
pip install -e ".[dev,ratelimit,migrations]"
make check   # ruff + mypy
make test    # sqlite suite
make test-postgres   # postgres integration (Docker), encryption on
```

See [CONTRIBUTING.md](CONTRIBUTING.md) for the full workflow. Licensed under the
[MIT License](LICENSE).
