Skip to main content

Batteries-included, transport-agnostic authentication for FastAPI.

Project description

crudauth

Batteries-included, transport-agnostic authentication for FastAPI.

One CRUDAuth object gives you cookie sessions, JWT bearer tokens, OAuth, email flows (verify / reset / change), CSRF, login lockout, and multi-device session management — over your SQLAlchemy User model, with app policy in hooks instead of forked dependency code.

Status: early 0.1 — the API is the v1 surface we're converging on.

Install

pip install crudauth            # core (session + bearer)
pip install "crudauth[all]"     # + httpx (oauth), redis, user-agents

Quickstart

Sessions are the default — no transports= needed. You get cookie auth, CSRF, login lockout, secure cookies, and /login /logout /register /me.

from fastapi import FastAPI, Depends
from crudauth import CRUDAuth, Principal
from myapp.db import get_session
from myapp.models import User

auth = CRUDAuth(session=get_session, user_model=User, SECRET_KEY="change-me")

app = FastAPI()
app.include_router(auth.router)

@app.get("/dashboard")
async def dashboard(me: Principal = Depends(auth.current_user())):
    return {"hello": me.user.username}

The user model

Inherit the mixin and get every column the package needs; your own columns coexist freely.

from sqlalchemy.orm import Mapped, mapped_column
from crudauth.models import AuthUserMixin
from myapp.db import Base

class User(Base, AuthUserMixin):
    __tablename__ = "users"
    full_name: Mapped[str | None] = mapped_column(default=None)

Existing table with different names? Map the contract, don't rename your schema:

auth = CRUDAuth(
    session=get_session, user_model=LegacyAccount, SECRET_KEY=...,
    column_map={"id": "account_id", "email": "email_address", "hashed_password": "pw_hash"},
)

Protecting routes — one factory, every case a kwarg

auth.current_user()                              # required, 401 if anon
auth.current_user(optional=True)                 # None instead of raising
auth.current_user(superuser=True)                # 403 unless is_superuser
auth.current_user(verified=True)                 # 403 unless email_verified
auth.current_user(scopes=["reports:read"])       # 403 unless scopes ⊇ required
auth.current_user(transport="bearer")            # narrow to one transport
auth.current_user(superuser=True, check=my_predicate)  # extra per-route check

The resolved Principal carries user_id, is_superuser, scopes, transport (which transport authed the request), and user (your resolved row).

Multiple transports, one identity

from crudauth import CRUDAuth, SessionTransport, BearerTransport

auth = CRUDAuth(
    session=get_session, user_model=User, SECRET_KEY=...,
    transports=[
        SessionTransport(backend="redis", redis_url=..., csrf=True),  # browsers
        BearerTransport(access_ttl=900, refresh="cookie"),            # apps/scripts
    ],
)

When both credentials are present, the first transport in the list wins. CSRF is a property of the session transport — it appears only where sessions do, never on bearer/api-key paths.

Storage & lifespan

Server-side backends open connections and run a cleanup sweep — call initialize() / shutdown() in your lifespan:

@asynccontextmanager
async def lifespan(app: FastAPI):
    await auth.initialize()
    yield
    await auth.shutdown()

OAuth, email, hooks

See the usage cookbook for OAuth (Google/GitHub/custom providers), email flows (implement the EmailSender port; the package mints/verifies the signed tokens), lifecycle hooks (AuthHooks — welcome email, trial grant, audit log), and dropping to primitives.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

crudauth-0.1.0-py3-none-any.whl (83.1 kB view details)

Uploaded Python 3

File details

Details for the file crudauth-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: crudauth-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 83.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for crudauth-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 78ca93c0f75207a5e8d7e700efd0204c64f99aaa14a5d76c3903fb60e4e8c9ac
MD5 488d7cfed9ca39d43fd8bd76b848f26c
BLAKE2b-256 9b13dae2c41819d615452898a821567a6780acbe75f07aad044cd7820d2130d0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page