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.
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.
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
pip install authwardenOptional extras:
pip install "authwarden[redis]" # Redis-backed sessions and token blacklist
pip install "authwarden[sns]" # AWS SNS SMS backend
pip install "authwarden[all]" # everythingfrom 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 --reloadOpen 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.
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.
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 methodsMore examples (MongoDB/Beanie, SQLModel, Tortoise) in the full docs.
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"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
git clone https://github.com/timihack/authwarden
cd authwarden
pip install -e ".[dev]"
pytest390 tests across foundation, auth flows, MFA/permissions, OAuth, router assembly, and full HTTP end-to-end coverage.
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.
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.
Issues and PRs welcome. This project is in active development — check the roadmap discussion before starting major work.
MIT © timihack