All notable changes to FastAuth are documented here. This file is the source for GitHub release notes, so each version’s section is what you see on the releases page.
This file records changes to the published package. Repository tooling —
CI workflows, the documentation site, release scripts — is not listed here,
because none of it reaches someone running pip install fastauth_iq.
The format follows Keep a Changelog, and FastAuth follows semantic versioning: only a major release can break your code. See Versioning for the full policy.
async def,
which meant FastAPI ran it on the event loop: a single login held the whole
process for the duration of its bcrypt verification (roughly 200ms), and
every authenticated request blocked the loop for the length of its user
lookup. Concurrent logins queued behind one another and stalled unrelated
traffic. Those handlers are now synchronous, so FastAPI runs them in a
threadpool. No API changes: request and response shapes are identical, and
throughput under concurrency improves substantially.scripts/prepare_release.py bumps every version location and rolls the
changelog’s [Unreleased] section into a dated release in one command. It
refuses to run when there are no notes to release.scripts/check_release.py verifies the version agrees across all four files
it is written in, that the changelog has notes for it, and that no stale
domains remain. CI runs it on every push and again before publishing.prepare_release.py infers the bump from the [Unreleased] headings, so the
version follows from what changed rather than from a judgement call.
pip-audit and pnpm audit on every push and
weekly, so a CVE published against an unchanged dependency is still found.core/auth.py 94%, routers 96%,
security/ 97-100%.tests/test_docs_match_api.py asserts the documented API matches the API
that exists: the routes the app mounts, the endpoint reference, AGENTS.md,
and the route count the landing page advertises. Documentation drift is now
a test failure rather than something noticed later by a user.tests/test_cli.py covers settings discovery, .env parsing, role
initialization and superadmin creation. CLI coverage rises from 34% to 74%
and the project total from 81% to 89%.create_engine("sqlite:///" + name) matched the settings regex and yielded
"sqlite:///" — a URL that looks plausible and points nowhere. The patterns
now require the string literal to be the complete value, so a concatenated
expression falls through to importing the module and evaluating it properly..env file could override the real environment. SECRET_KEY set in a
deployment was silently replaced by a stale .env shipped in the image,
signing every token with the wrong key. The real environment now always
wins, and .env fills in only what is missing.exceptions.py.permissions, so CI jobs get a
read-only token instead of inheriting the repository default.No action needed for most projects, but one behaviour changed deliberately:
A .env file no longer overrides real environment variables. Previously a
.env value won; now the environment does, and .env fills in only what is
missing. This matches dotenv tooling elsewhere and closes a real hazard, where
a stale .env in a deployed image silently replaced the production
SECRET_KEY.
If you relied on .env taking precedence, unset the variable in the
environment instead, or pass the value explicitly with --secret-key /
--db-url.
llms.txt so AI coding agents integrate FastAuth correctly rather than
guessing at the API.One obvious way to do each thing. Four long-form names are superseded by
shorter equivalents. The old names still work and now emit a
DeprecationWarning; they will be removed in 1.0.
| Deprecated | Replacement |
|---|---|
auth.get_current_active_user_dependency() |
auth.current_user |
auth.is_admin() |
auth.admin |
auth.require_roles([...]) |
auth.roles(...) |
auth.require_all_roles([...]) |
auth.all_roles(...) |
The replacements accept role names directly or as a list, so both
auth.roles("admin", "moderator") and auth.roles(["admin", "moderator"])
work. The deprecated forms now accept either shape too, rather than requiring
a list.
session_getter is documented. Leave it out and FastAuth opens sessions
on the engine you gave it, which is what most apps want. Pass your own only
when routes must share a session with the rest of your app.
token_url now defaults to /token. It previously defaulted to token
with no leading slash, while the router registers /token. That value is
what Swagger’s Authorize button posts to, and a relative URL resolves
against the docs path, breaking as soon as the app is mounted under a prefix.
A missing leading slash is now added automatically, so passing "token" is
corrected rather than broken.index.html,
easy-mode.html, style.css, scripts.js), replaced by the new site.No action needed. Deprecated names keep working until 1.0. To find them in your code, make deprecation warnings fail your tests:
[tool.pytest.ini_options]
filterwarnings = ["error::DeprecationWarning"]
POST /password/forgot + POST /password/reset with
stateless single-use tokens (a token dies the moment the password changes)POST /password/change for logged-in usersPOST /email/verify/request + POST /email/verify,
plus the auth.verified_user dependency and an email_verified columnPOST /logout/all and auth.revoke_all_tokens()
invalidate all sessions via a token_version column; password reset and
change do this automatically@auth.on_password_reset and @auth.on_email_verify
connect the flows to your email sending; in development, tokens print to the
console@auth.token_claims merges your claims into every
issued token__tablename__ on a custom user model now fails at startup with
instructions instead of breaking silently at runtimeThis release adds two columns to the user table. For SQLite development databases, delete the file and restart. For live databases:
ALTER TABLE user ADD COLUMN email_verified BOOLEAN DEFAULT 0;
ALTER TABLE user ADD COLUMN token_version INTEGER DEFAULT 0;
Or use Alembic; see Going to Production.
secret_key is now optional; FastAuth reads
SECRET_KEY / FASTAUTH_SECRET_KEY from the environment, or manages a
development secret in .fastauth-secretproduction=True (or FASTAUTH_PRODUCTION=1) requires a
strong secret, secures cookies, and refuses the default admin passwordauth.current_user, auth.admin,
auth.roles(...), auth.all_roles(...), auth.required,
auth.admin_requiredpassword_min_length (default 8,
set 0 to disable) with a FASTAUTH_WEAK_PASSWORD errorcookie_secure now defaults to False in development and True in
production mode (explicit values always win)Authorization: Bearer header now takes precedence over the auth
cookieengine is keyword-friendly and its absence is a clear errorauth.setup(app): one-call integrationPOST /logout endpoint that clears the auth cookiecookie_secure / cookie_samesite options; the auth cookie now expires with
the token/token/refresh accepts a documented RefreshRequest body (visible in
/docs)bcrypt (≥ 4.1, including 5.x) by hashing with
bcrypt directly. The unmaintained passlib dependency is gone, and existing
password hashes keep working409 instead of a
server errorprint() statements that leaked token prefixes to stdoutpython-jose dependencyBreaking changes:
fastauth.py / User.py compatibility shims were
removed; import everything from the fastauth package insteadFastAuth no longer exposes a shared .session attribute; pass a session to
authenticate_user(..., session=...) or let it create one automatically