Skip to content

v0.19.0

Latest

Choose a tag to compare

@igorbenav igorbenav released this 24 Jun 02:39
cf4f10f

Release v0.19.0 - The crudauth Migration

Release Notes by the Fastro FastAPI boilerplate team

This release is mostly about replacing the authentication code with crudauth. About 6,000 lines of security-critical code you no longer have to maintain.

If you're on v0.18.0 and you don't reach into infrastructure/auth/ internals, this upgrade is close to transparent: /login, /logout, /oauth/google, /refresh-csrf, and /check-auth behave the same, get_current_user returns the same dict, and a cookie-based frontend needs no changes. If you imported from the old infrastructure.auth.session.* modules or relied on the JWT-era settings, see the breaking changes below.

Why hand auth off to a library

The forked auth was the boilerplate's single largest source of subtle, security-relevant surface: token handling, CSRF double-submit, escalating lockout, session storage across three backends. It worked, but every line of it was ours to keep correct, and none of it was the boilerplate's actual job.

crudauth does exactly this job: it's the auth library extracted from fastroai-template (the same lineage as the v0.18.0 restructure), it's been running real apps under load, and it's transport-agnostic: the same Principal resolves a request whether it authenticates by cookie session or, if you opt in, a JWT bearer token. The trade is a third-party dependency in exchange for deleting ~6,000 lines and inheriting a maintained, independently-tested auth core. For a boilerplate whose whole pitch is "use what you need, drop what you don't", auth is the one place where rolling your own is rarely the right call.

What's New in v0.19.0

Three changes, one of them the headline:

  • Auth runs on crudauth. A single auth = CRUDAuth(...) composition root in infrastructure/auth/setup.py replaces the vendored session manager, the OAuth framework, and the password utilities. The route handlers drive crudauth's building blocks directly, so the URLs and response shapes are unchanged.
  • Annotated type-alias dependency injection (#261). Route signatures moved from inline Depends(...) to centralized Annotated[..., Depends(...)] aliases, with per-module dependencies.py files holding the service aliases.
  • Env-configurable app metadata. APP_NAME, APP_DESCRIPTION, and VERSION are now read from the environment.

Plus the smaller wins that come with crudauth: login lockout now returns 429 + Retry-After instead of a generic failure, a TRUSTED_PROXY_HOPS setting for correct client-IP resolution behind a proxy, and a derived User.is_active (not is_deleted) so soft-deleted users can't authenticate.

Breaking Changes Summary

Change Impact Migration Effort
Forked auth modules deleted Imports from infrastructure.auth.session.* / auth.oauth.* break at import time Medium — repoint to infrastructure.auth.dependencies
get_password_hash / verify_password moved Old import path fails Low — import from crudauth
Memcached session backend removed SESSION_BACKEND=memcached is invalid Low — use redis or memory
JWT-era settings removed ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES, REFRESH_TOKEN_EXPIRE_DAYS, SESSION_COOKIE_MAX_AGE, LOGIN_MAX_ATTEMPTS, LOGIN_WINDOW_MINUTES no longer exist Low — delete from env; add TRUSTED_PROXY_HOPS if behind a proxy
Login lockout response Now 429 + Retry-After (was a generic 401) Low — handle 429 client-side
GitHub OAuth provider removed Only Google is wired Low — re-enable via crudauth's OAuthProviderFactory
Password hash format crudauth uses bcrypt with a SHA-256 pre-hash; existing hashes won't validate High for existing DBs — rehash on next login; none for fresh installs

Detailed Changes

1. Auth on crudauth ⚠️ BREAKING

The boilerplate carried its own SessionManager, an OAuth provider framework, password utilities, and three session storage backends. All of it duplicated what crudauth already does. This release introduces a single composition root — auth = CRUDAuth(...) in infrastructure/auth/setup.py, constructed at import time and wired into the app lifespan via auth.initialize() / auth.shutdown() — and routes the app through it.

The six existing routes keep their paths and response shapes; their bodies now call crudauth's building blocks. infrastructure/auth/dependencies.py resolves each request to a crudauth Principal and layers the dict-compatible get_current_user / get_optional_user / get_current_superuser on top, re-loading the row so the byte-identical user dict the handlers and the API-key module expect is preserved. Because the boilerplate's User already has every column crudauth needs, no column_map is required.

The vendored engine was then deleted wholesale: infrastructure/auth/{session,oauth}/, auth/utils.py, and auth/constants.py — about 6,000 lines. auth/http_exceptions.py is kept (it only re-exports FastCRUD exceptions). Password hashing now imports from crudauth.

2. Annotated type-alias dependency injection (#261)

Route signatures moved from inline Depends(...) to centralized Annotated[..., Depends(...)] aliases in infrastructure/dependencies.py, with per-module dependencies.py files (user, tier, rate_limit, api_keys) holding the service aliases. Adding a new endpoint no longer means repeating the dependency boilerplate. Landed by co-maintainer @emiliano-go.

3. Env-configurable app metadata

APP_NAME, APP_DESCRIPTION, and VERSION are now read from the environment via config(...) instead of being hardcoded, so a fork can rename itself without editing settings.

4. Settings, lockout, and the memcached drop ⚠️ BREAKING

Login lockout is now crudauth's escalating per-IP / per-identifier throttle, surfaced as 429 + Retry-After, and its client-IP resolution is governed by a new TRUSTED_PROXY_HOPS setting (default 0; set 1 behind a single reverse proxy). The dead JWT config (ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES, REFRESH_TOKEN_EXPIRE_DAYS) and the session knobs now owned by the transport (SESSION_COOKIE_MAX_AGE, LOGIN_MAX_ATTEMPTS, LOGIN_WINDOW_MINUTES) are removed; SECRET_KEY goes from dead config to actually used. crudauth supports redis and memory session backends only, so the memcached session backend is gone (the general cache and the non-auth rate limiter still support memcached).

Mobile / JWT

crudauth ships a bearer (JWT) transport that runs alongside sessions for mobile and API clients — both transports resolve to the same Principal, so your route protection doesn't change. It's off by default; see the authentication guide and crudauth's bearer-token guide for the opt-in.

Thanks

The Annotated type-alias DI refactor (#261) landed from co-maintainer @emiliano-go.

If you want to talk to us

Join us on Discord, open an issue, or ping @igorbenav, @LucasQR, @carlosplanchon, or @emiliano-gandini-outeda on the repo. Auth is now a thin wiring layer over crudauth — if there's an auth capability you want (a different transport, an account-recovery flow, a hook), it's likely a crudauth feature you can turn on rather than a fork of the boilerplate.

Full Changelog: v0.18.0...v0.19.0