CRUDAuth¶
crudauth.CRUDAuth
¶
CRUDAuth(
*,
session: Callable[..., Any],
user_model: type[Any],
SECRET_KEY: str,
transports: Sequence[Transport] | None = None,
column_map: dict[str, str] | None = None,
oauth: dict[str, Any] | None = None,
email: Any = None,
hooks: AuthHooks | None = None,
redirect_base_url: str | None = None,
algorithm: str = DEFAULT_ALGORITHM,
cookies: CookieConfig | None = None,
register_schema: type[BaseModel] | None = None,
register_extra_fields: set[str] | None = None,
rate_limiter: RateLimiterBackend | None = None,
rate_limits: dict[str, RateLimit] | None = None,
trusted_proxy_hops: int = 0,
sudo: SudoConfig | None = None,
warn_on_memory_backend: bool = True,
)
Composition root: configure transports, mount routers, gate routes.
Construct one per auth surface. It owns the user repository, the shared
AuthRuntime, the rate-limiter backend, and the
assembled routers. Session auth is the default; add bearer/oauth/email by
passing transports=, oauth=, email=.
Example
Configure the auth surface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session
|
Callable[..., Any]
|
FastAPI dependency that yields an |
required |
user_model
|
type[Any]
|
Your SQLAlchemy user model (typically inheriting AuthUserMixin). |
required |
SECRET_KEY
|
str
|
Secret used to sign session/JWT and email tokens. |
required |
transports
|
Sequence[Transport] | None
|
Ordered auth channels to enable; defaults to a single SessionTransport. Order is the first-wins precedence. |
None
|
column_map
|
dict[str, str] | None
|
Maps crudauth logical field names to your model's actual
column names when they differ (e.g. |
None
|
oauth
|
dict[str, Any] | None
|
|
None
|
email
|
Any
|
An EmailConfig to enable verify/reset/change
flows; |
None
|
hooks
|
AuthHooks | None
|
Lifecycle callbacks (AuthHooks). |
None
|
redirect_base_url
|
str | None
|
Public base URL used to build OAuth redirect URIs and the post-login redirect default. |
None
|
algorithm
|
str
|
JWT signing algorithm (default |
DEFAULT_ALGORITHM
|
cookies
|
CookieConfig | None
|
App-wide CookieConfig ( |
None
|
register_schema
|
type[BaseModel] | None
|
Custom Pydantic body for |
None
|
register_extra_fields
|
set[str] | None
|
App-defined model columns that |
None
|
rate_limiter
|
RateLimiterBackend | None
|
Backend for lockout/throttles; defaults to an in-process
MemoryRateLimiterBackend. Use
|
None
|
rate_limits
|
dict[str, RateLimit] | None
|
Per-action overrides merged over
:data: |
None
|
trusted_proxy_hops
|
int
|
Number of trusted reverse proxies in front of the
app. |
0
|
sudo
|
SudoConfig | None
|
Enable sudo mode (short-lived re-authentication for sensitive
actions) with this SudoConfig. Requires
a session transport - elevation is stamped on the server-side
session. Exposes |
None
|
warn_on_memory_backend
|
bool
|
Log a startup warning when an in-memory
backend is active (the zero-config default). In-memory state is
per-process, so under multiple workers it silently breaks; set
|
True
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
router
property
¶
session_router
property
¶
Only the session transport's routes (/login, /logout).
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no SessionTransport is configured. |
bearer_router
property
¶
Only the bearer transport's routes (/token, /refresh).
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no BearerTransport is configured. |
current_user
¶
current_user(
*,
optional: bool = False,
superuser: bool = False,
verified: bool = False,
scopes: list[str] | None = None,
transport: str | list[str] | None = None,
check: Callable[[Principal], Any] | None = None,
) -> Callable[..., Any]
Build a FastAPI dependency that authenticates and authorizes a request.
Every gate is a keyword: optional, superuser, verified,
scopes, transport (narrow to one/some transports), and check.
Note
check is a predicate (sync or async) run last on the resolved
principal. Returning False denies the request with 403. To deny
with a custom status/message, raise your own exception from inside
check. Returning None (or anything that isn't False)
allows - so both styles work: a boolean predicate
(check=lambda p: p.is_superuser) and a raise-to-deny callback that
simply returns nothing on success.
Note
Transports are tried in order, first credential wins. A transport
returns None when its credential is absent (move to the next),
but RAISES for a present-but-invalid one (e.g. a session cookie that
fails the CSRF header check on a mutation). That hard-fail propagates
even under optional=True - a tampered credential is an attack
signal, not "treat me as anonymous".
Returns:
| Type | Description |
|---|---|
Callable[..., Any]
|
An async dependency yielding the Principal (or |
Callable[..., Any]
|
|
require_sudo
¶
Build a dependency that requires a current sudo elevation.
Authenticates like current_user
(reusing the per-request principal cache) and then demands an unexpired
sudo stamp, raising 403 otherwise. Compose it with current_user gates
on the same route to also enforce identity/role:
Example
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If sudo isn't configured (pass |
rate_limit
¶
rate_limit(
action: str,
limit: RateLimit | None = None,
*,
key: KeyBy | Callable[[Request], str] = IP,
) -> Callable[..., Any]
Build a FastAPI dependency that throttles an endpoint.
Resolves the limit (explicit limit → rate_limits= override →
:data:~crudauth.ratelimit.DEFAULT_RATE_LIMITS), keys by IP, user, or a
custom function, writes X-RateLimit-* headers, and raises
RateLimitException (429) when the caller exceeds the window.