A production-grade, pluggable authentication library for FastAPI — JWT, OAuth2 (8 providers), MFA, RBAC, and full flow flexibility (email/SMS, link/OTP, multi-identifier login).
Project description
authwarden
A production-grade, pluggable authentication library for FastAPI.
JWT auth, OAuth2 across 8 providers, MFA, RBAC, and full flow flexibility — all behind a clean FastAPI router you can drop into any app.
Why authwarden
Most FastAPI auth tutorials show you a toy JWT example and stop there. authwarden is built for the parts that actually matter in production:
- Everything is a
Protocol. Bring your own database (theAbstractUserStoreprotocol works out of the box with SQLAlchemy, MongoDB/Beanie, SQLModel, or Tortoise — no built-in ORM lock-in), your own email/SMS provider, your own templates. - Flexibility where it counts. Verify by link or OTP. Notify by email, SMS, or both. Let users log in with email, username, or phone — your call, configured once.
- Security defaults that are actually defaults. Brute-force lockout, OTP attempt limiting, encrypted OAuth tokens at rest, PKCE on every social login flow — none of it bolted on, none of it optional homework.
- A real test suite. 390 tests across unit, flow, and full HTTP end-to-end coverage.
Features
Authentication
- Register, login, logout, refresh (with rotation)
- Email verification — link or OTP, your choice
- Password reset — link or OTP, your choice
- Change password, and
set-passwordfor OAuth-only accounts - Login via email, username, or phone — configurable priority order
- Email and SMS notification channels, independently configurable
MFA
- TOTP setup, confirm, disable
- 8 single-use, argon2-hashed backup codes per user
Permissions
- Role hierarchy (
guest→user→moderator→admin→superadmin) - Arbitrary scope strings (
"user:read","admin:delete", anything you want)
OAuth 2.0 / Social Login
- Google, GitHub, Facebook, Microsoft, LinkedIn, Discord, Twitter/X, Apple
- PKCE (S256) on every provider, no exceptions
- Automatic account linking (existing link → email match → auto-register)
- Apple's quirks handled for you: ES256 client-secret generation, JWKS-cached
id_tokenverification, first-login-only name capture - OAuth tokens encrypted at rest
Security
- Login lockout after configurable failed attempts
- OTP attempt limiting with auto-invalidation
- Anti-enumeration on password reset and resend-verification
- Single-use, hashed reset/verification tokens — raw tokens never touch storage
Installation
pip install authwarden
Optional extras:
pip install "authwarden[redis]" # Redis-backed sessions and token blacklist
pip install "authwarden[sns]" # AWS SNS SMS backend
pip install "authwarden[all]" # everything
Quickstart
from fastapi import FastAPI, Depends
from authwarden import AuthWarden, WardenConfig, MemoryUserStore
config = WardenConfig(
secret_key="change-me-to-a-real-32-byte-secret",
require_email_verification=False, # skip for this example
)
store = MemoryUserStore() # swap for your own AbstractUserStore in production
warden = AuthWarden(config=config, user_store=store)
app = FastAPI()
app.include_router(warden.router, prefix="/auth", tags=["auth"])
@app.get("/profile")
async def profile(user=Depends(warden.current_user)):
return {"id": user.id, "email": user.email}
@app.delete("/admin/users/{user_id}")
async def delete_user(user_id: str, _=Depends(warden.require_roles("admin"))):
...
Run it:
uvicorn main:app --reload
Open http://127.0.0.1:8000/docs — you now have working /auth/register, /auth/login, /auth/refresh, MFA, and OAuth endpoints, plus an interactive Authorize button for testing protected routes.
Core concepts
WardenConfig
Every behavioral switch lives here — verification method (link/OTP), notification channels, login identifier order, lockout thresholds, OAuth provider credentials, and more. See the full configuration reference for every field.
AbstractUserStore
A Protocol, not a base class — any object with the right async methods satisfies it. Works with any database:
class SQLAlchemyUserStore:
def __init__(self, session_factory):
self.session_factory = session_factory
async def get_by_email(self, email: str):
async with self.session_factory() as session:
result = await session.execute(select(UserModel).where(UserModel.email == email))
row = result.scalar_one_or_none()
return UserInDB.model_validate(row) if row else None
# ... remaining protocol methods
More examples (MongoDB/Beanie, SQLModel, Tortoise) in the full docs.
Extending the user model
UserInDB supports arbitrary extra data without a migration, or full subclassing for typed fields:
class MyUser(UserInDB):
company_id: str | None = None
subscription_tier: str = "free"
The AuthWarden facade
warden.router— mount it, get 20 endpointswarden.current_user—Depends()-compatible, fetches fresh from your store, checksis_activeon every requestwarden.require_roles(*roles)/warden.require_scopes(*scopes)— guard any route you write yourself
Testing
git clone https://github.com/timihack/authwarden
cd authwarden
pip install -e ".[dev]"
pytest
390 tests across foundation, auth flows, MFA/permissions, OAuth, router assembly, and full HTTP end-to-end coverage.
Documentation
This README gets you to a working quickstart. For the complete reference — every config field, every flow with code samples, every customization pattern — see the full documentation site.
Roadmap
Tracked in the project discussion — includes planned post-v1.0 work like transport/strategy pluggability, Enterprise OIDC, SAML 2.0, and built-in ORM backend implementations.
Contributing
Issues and PRs welcome. This project is in active development — check the roadmap discussion before starting major work.
License
MIT © timihack
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file authwarden-1.0.0.tar.gz.
File metadata
- Download URL: authwarden-1.0.0.tar.gz
- Upload date:
- Size: 84.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b086e66a2ff2d38f31e175f820dd5506452f567b5fb1ddbcac8daf7d89cb1301
|
|
| MD5 |
076c50d27b6243c489ddcb9d62ca85a9
|
|
| BLAKE2b-256 |
4ca804b159beef37ed957ec4c9c3bfc0e05fc581e353f3ebf9d68d2791b1d17f
|
Provenance
The following attestation bundles were made for authwarden-1.0.0.tar.gz:
Publisher:
publish.yml on timihack/authwarden
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
authwarden-1.0.0.tar.gz -
Subject digest:
b086e66a2ff2d38f31e175f820dd5506452f567b5fb1ddbcac8daf7d89cb1301 - Sigstore transparency entry: 1992209156
- Sigstore integration time:
-
Permalink:
timihack/authwarden@253d6f75dade8314e61f473285b2615af32715ce -
Branch / Tag:
- Owner: https://github.com/timihack
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@253d6f75dade8314e61f473285b2615af32715ce -
Trigger Event:
release
-
Statement type:
File details
Details for the file authwarden-1.0.0-py3-none-any.whl.
File metadata
- Download URL: authwarden-1.0.0-py3-none-any.whl
- Upload date:
- Size: 83.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3d5f796c77d4e189e23b97f210e9fd90aa7fa01b91e703766c8cf1f8b45d9026
|
|
| MD5 |
007c7fe8439f902fcf370a28997048b7
|
|
| BLAKE2b-256 |
7ef47df65ed4c5ad50623161f24cd834e258d91399f2a615646e46fbb85752c1
|
Provenance
The following attestation bundles were made for authwarden-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on timihack/authwarden
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
authwarden-1.0.0-py3-none-any.whl -
Subject digest:
3d5f796c77d4e189e23b97f210e9fd90aa7fa01b91e703766c8cf1f8b45d9026 - Sigstore transparency entry: 1992209303
- Sigstore integration time:
-
Permalink:
timihack/authwarden@253d6f75dade8314e61f473285b2615af32715ce -
Branch / Tag:
- Owner: https://github.com/timihack
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@253d6f75dade8314e61f473285b2615af32715ce -
Trigger Event:
release
-
Statement type: