A comprehensive authentication and authorization library for FastAPI applications
with JWT-based authentication, role-based authorization, and SQLModel integration.
Documentation
This README provides a quick overview of FastAuth. For a more complete, interactive documentation with live examples and responsive design, visit our GitHub Pages Documentation.
New to FastAPI or building auth for the first time? Start with the Easy Mode guide for students: one file, five minutes, every step checked.
Using an AI coding assistant? This repo ships an AGENTS.md with the full API surface, so agents can integrate FastAuth correctly without guessing.
Table of Contents
- Features
- Installation
- Quick Start
- Authentication
- Database Initialization
- Role-Based Authorization
- Customization Levels
- Going to Production
- API Reference
- Error Handling
- Advanced Usage
- Security Best Practices
- What's New in 0.6.0
- What's New in 0.5.0
- What's New in 0.4.0
- Project Structure
- License
Features
- OAuth2 and JWT authentication built-in
- Role-based authorization system
- Cookie-based authentication option with configurable cookie settings
- Token refresh mechanism for extended sessions
- Logout endpoint that clears the auth cookie
- SQLModel integration for easy database operations
- CLI utilities for database initialization and management
- One-call setup:
auth.setup(app)wires up all routes and error handlers - Comprehensive error handling with standardized error responses
- Password hashing with bcrypt (no passlib dependency)
- Modular architecture for better code organization and extensibility
- Zero-config start:
FastAuth(engine=engine)manages a dev secret for you - Production mode:
production=Trueenforces a strong secret, secure cookies, and no default passwords - Ready-made dependencies:
auth.current_user,auth.admin,auth.roles(...),auth.required,auth.verified_user - Password reset and change flows with single-use tokens and delivery hooks
- Email verification flow with a
verified_userdependency - Token revocation:
/logout/allinvalidates every session on every device - Password rules: minimum length enforced on registration (configurable)
- Tested on every commit across Python 3.10–3.14 with GitHub Actions
Installation
uv add fastauth_iq "fastapi[standard]"
Or install from source:
git clone https://github.com/hu55ain3laa/fastauth.git
cd fastauth
uv pip install -e .
Requires Python 3.10+. fastapi[standard] brings the fastapi dev server for local development.
Don't have uv yet? Grab it with your platform's package manager, or see the uv installation guide:
# macOS
brew install uv
# Windows
winget install --id=astral-sh.uv -e
# Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# or as a snap
sudo snap install astral-uv --classic
Quick Start
A complete working app in one file:
from contextlib import asynccontextmanager
from fastapi import Depends, FastAPI
from sqlmodel import Session, create_engine
from fastauth import FastAuth, User
engine = create_engine("sqlite:///./app.db", connect_args={"check_same_thread": False})
def get_session():
with Session(engine) as session:
yield session
# Zero config: in development FastAuth manages a dev secret for you
# (stored in .fastauth-secret, add it to .gitignore).
# In production, set SECRET_KEY in the environment and production=True.
auth = FastAuth(engine=engine)
# Create tables, standard roles, and a superadmin on startup
@asynccontextmanager
async def lifespan(app: FastAPI):
auth.initialize_db(admin_username="superadmin", admin_password="admin123")
yield
app = FastAPI(lifespan=lifespan)
# One call adds all auth + role routes and standardized error handling
auth.setup(app, session_getter=get_session)
# Protect your routes with the ready-made dependencies
@app.get("/protected")
def protected_route(current_user: User = Depends(auth.current_user)):
return {"message": f"Hello, {current_user.username}!"}
@app.get("/admin-only")
def admin_only_route(current_user: User = Depends(auth.admin)):
return {"message": f"Hello admin, {current_user.username}!"}
That's it. Run it with uv run fastapi dev app.py and open /docs.
auth.setup(app) is equivalent to the manual version:
app.include_router(auth.get_auth_router(get_session), tags=["authentication"])
app.include_router(auth.get_role_router())
auth.setup_exception_handlers(app)
Use the manual version if you need custom prefixes or want to skip the role router
(auth.setup(app, include_role_router=False) also works).
Authentication
Login and Token Management
FastAuth implements JWT-based authentication with both access tokens and refresh tokens:
- Access tokens are short-lived (default: 30 minutes) and used for regular API access
- Refresh tokens are long-lived (default: 7 days) and used to obtain new access tokens
User authentication flow:
- User submits credentials to
/tokenendpoint - Server validates credentials and returns access + refresh tokens
- Client uses access token for API requests (via header or cookie)
- When the access token expires, the client sends
{"refresh_token": "..."}to/token/refreshto get a new one /logoutclears the auth cookie
Disabled users cannot log in, refresh tokens, or access protected routes.
Protected Routes
To protect a route, use FastAuth's dependencies:
# Basic authentication - any valid, active user
@app.get("/protected")
def protected_route(user = Depends(auth.current_user)):
return {"message": "Protected content", "user": user.username}
# Require any of these roles
@app.get("/admin-or-moderator")
def admin_or_mod_route(user = Depends(auth.roles("admin", "moderator"))):
return {"message": f"Hello privileged user, {user.username}!"}
# Require all of these roles
@app.get("/admin-and-verified")
def admin_and_verified_route(user = Depends(auth.all_roles("admin", "verified"))):
return {"message": f"Hello verified admin, {user.username}!"}
# Shortcut for admin-only routes
@app.get("/admin-only")
def admin_only_route(user = Depends(auth.admin)):
return {"message": f"Hello admin, {user.username}!"}
# Protect a whole router at once
from fastapi import APIRouter
staff_area = APIRouter(dependencies=[auth.required])
# The long-form names still work: auth.get_current_active_user_dependency(),
# auth.require_roles([...]), auth.require_all_roles([...]), auth.is_admin()
Cookie-Based Authentication
FastAuth supports both header-based and cookie-based authentication:
auth = FastAuth(
# ... other parameters ...
use_cookie=True, # Enable cookie support
cookie_secure=True, # Only send the cookie over HTTPS (set False for local dev)
cookie_samesite="lax", # SameSite policy
)
With cookie-based auth enabled:
- The
/tokenendpoint sets an HTTP-onlyaccess_tokencookie that expires together with the token - Protected routes accept an explicit
Authorization: Bearerheader first and fall back to the cookie cookie_securedefaults toFalsein development (cookies work onhttp://localhost) andTruein production mode/logoutclears the cookie- HTTP-only cookies protect the token from JavaScript access (XSS)
Local development tip: browsers may refuse
Securecookies over plain HTTP. Passcookie_secure=Falsewhile developing onhttp://localhostand keep the defaultTruein production.
Password Reset and Email Verification
FastAuth ships the account flows real apps need. Token delivery is your app's job (usually email); register a hook for each flow. Without a hook, tokens are printed to the console in development so you can try the flows locally:
@auth.on_password_reset
def send_reset(user, token):
send_email(user.email, f"Reset your password with this token: {token}")
@auth.on_email_verify
def send_verify(user, token):
send_email(user.email, f"Verify your email with this token: {token}")
The flows themselves are already mounted by auth.setup(app):
POST /password/forgot{"email"}: always returns 200 (no account discovery); issues a single-use reset tokenPOST /password/reset{"token", "new_password"}: sets the new password and logs the user out everywherePOST /password/change{"current_password", "new_password"}(logged in): rotates the password, revokes old sessionsPOST /email/verify/request(logged in) thenPOST /email/verify{"token"}: marks the email verifiedPOST /logout/all(logged in): invalidates every token on every device
Require a verified email on any route:
@app.get("/billing")
def billing(user: User = Depends(auth.verified_user)):
...
You can also add custom claims to every issued JWT:
@auth.token_claims
def claims(user):
return {"plan": user.plan}
Database Initialization
CLI Initialization
FastAuth provides a convenient CLI tool for database initialization:
# Just provide your app file - FastAuth will extract settings automatically
fastauth app.py
# Or use explicit parameters
fastauth --db-url="sqlite:///./app.db" --secret-key="your-secret-key"
# Customize the superadmin credentials
fastauth app.py --username="admin" --password="secure_password"
# Run specific initialization steps only
fastauth app.py --init-db --init-roles --create-superadmin
The CLI auto-detects DATABASE_URL and SECRET_KEY from (in order): environment
variables, a .env file, the app file itself, and common config files
(config.py, settings.py, db.py, database.py, models.py), including
imported engine objects.
Programmatic Initialization
# During application startup (see the lifespan example in Quick Start)
auth.initialize_db(
create_tables=True, # Create database tables
init_roles=True, # Initialize standard roles
create_admin=True, # Create superadmin if needed
admin_username="superadmin",
admin_password="admin123", # Change this in production!
)
# Or create a superadmin at any time
auth.create_superadmin(username="admin", password="secure_password")
Pass
admin_usernameandadmin_passwordexplicitly when initializing during app startup. Otherwise FastAuth will prompt interactively on the console.
Role-Based Authorization
Standard Roles
The initialization creates these standard roles:
superadmin: Super administrator with all privilegesadmin: Administrator with management privilegesmoderator: User with content moderation privilegespremium: Premium tier userverified: Verified useruser: Standard user with basic privileges
Role Requirements
# Require any of these roles (OR condition)
@app.get("/admin-or-moderator")
def admin_route(user = Depends(auth.require_roles(["admin", "moderator"]))):
return {"message": "Admin or moderator area"}
# Require all of these roles (AND condition)
@app.get("/premium-and-verified")
def premium_verified_route(user = Depends(auth.require_all_roles(["premium", "verified"]))):
return {"message": "Premium and verified area"}
# Shortcut for admin-only routes
@app.get("/admin-only")
def admin_only(user = Depends(auth.is_admin())):
return {"message": "Admin only area"}
Role Management API
Included automatically by auth.setup(app), or add manually:
role_router = auth.get_role_router()
app.include_router(role_router)
Customization Levels
Every knob is optional. Start with nothing and turn dials as your project grows:
Level 0 · Zero config: FastAuth(engine=engine) + auth.setup(app). FastAuth manages a development secret (in .fastauth-secret) and cookies work on localhost.
Level 1 · Small tweaks: constructor options with safe defaults: token lifetimes, password_min_length, use_cookie, cookie_samesite, production.
Level 2 · Your models and routes: pass a custom user_model, your own session_getter, or mount routers selectively with auth.get_auth_router() / auth.get_role_router().
Level 3 · Ultra custom: build any flow from the public primitives: auth.token_manager, auth.password_manager, auth.authenticate_user(), and RoleManager (see Custom Authentication Logic).
Going to Production
One flag turns on the safety rails:
auth = FastAuth(engine=engine, production=True)
# or set the environment variable FASTAUTH_PRODUCTION=1
With production=True, FastAuth requires a 32+ character secret from the SECRET_KEY environment variable (generate with openssl rand -hex 32), defaults cookie_secure to True, and refuses the default superadmin password.
Deploy checklist:
- Set
SECRET_KEYin your host's environment - Turn on
production=True(orFASTAUTH_PRODUCTION=1) - Serve over HTTPS
- Create the superadmin with a strong, unique password
- Swap SQLite for a server database if you expect real traffic (any SQLModel/SQLAlchemy engine works)
- Run with
uv run fastapi run main.pyinstead offastapi dev
For schema changes on a live database, add Alembic migrations; SQLModel's create_all only creates missing tables.
API Reference
Authentication Endpoints
POST /token- Login and get access + refresh tokens (sets cookie when enabled)POST /token/refresh- Send{"refresh_token": "..."}to get a new access tokenPOST /users- Register a new user (username and email must be unique)GET /users/me- Get current user informationPOST /logout- Clear the authentication cookiePOST /logout/all- Revoke every token for the current user (all devices)POST /password/forgot- Issue a password reset token (delivered via your hook)POST /password/reset- Set a new password with a single-use reset tokenPOST /password/change- Change the logged-in user's passwordPOST /email/verify/request- Issue an email verification tokenPOST /email/verify- Confirm an email address
Role Management Endpoints
All under /roles by default:
POST /roles/- Create a new role (admin only)GET /roles/- Get all roles (authenticated users)GET /roles/{role_id}- Get a specific role (authenticated users)PUT /roles/{role_id}- Update a role (admin only)DELETE /roles/{role_id}- Delete a role (admin only)POST /roles/assign/{user_id}/{role_id}- Assign role to user (admin only)DELETE /roles/assign/{user_id}/{role_id}- Remove role from user (admin only)GET /roles/user/{user_id}- Get all roles for a user (authenticated users)
Error Handling
FastAuth ships specialized exception classes and returns a consistent JSON structure
for every auth error (handlers are registered by auth.setup(app)):
from fastauth import (
CredentialsException, # Authentication failures (401)
TokenException, # Token verification issues (401)
RefreshTokenException, # Refresh token problems (401)
InactiveUserException, # User account is disabled (403)
PermissionDeniedException,# Insufficient permissions (403)
UserNotFoundException, # User doesn't exist (404)
RoleNotFoundException, # Role doesn't exist (404)
UserExistsException, # Username/email already taken (409)
EmailNotVerifiedException,# Route requires a verified email (403)
WeakPasswordException, # Password below minimum length (422)
RoleExistsException, # Role already exists (409)
)
{
"error": {
"code": "FASTAUTH_INVALID_CREDENTIALS",
"message": "Human-readable error description",
"status_code": 401
}
}
Advanced Usage
Custom User Models
You can use a custom user model with FastAuth. Role checks and the CLI respect it:
class CustomUser(SQLModel, table=True):
__tablename__ = "user" # Keep the table name expected by the role system
id: int | None = Field(default=None, primary_key=True)
username: str = Field(unique=True, index=True)
email: str = Field(unique=True)
hashed_password: str
disabled: bool = Field(default=False)
# Additional fields...
first_name: str = Field(default="")
last_name: str = Field(default="")
auth = FastAuth(
# ... other parameters ...
user_model=CustomUser,
)
Don't import fastauth's built-in
Usermodel in the same app when using a custom one; two table models for the same table will conflict.
Custom Authentication Logic
@app.post("/custom-login")
async def custom_login(
username: str,
password: str,
session: Session = Depends(get_session),
):
user = auth.authenticate_user(username, password, session=session)
if not user:
raise HTTPException(status_code=401, detail="Invalid credentials")
access_token = auth.create_access_token(data={"sub": user.username})
return {"access_token": access_token, "token_type": "bearer"}
Security Best Practices
- Deploy your FastAPI app with HTTPS in production environments
- Use a strong secret key: generate one with
openssl rand -hex 32and store it securely (e.g., environment variables) - Change the default superadmin password. Never ship
admin123 - Configure appropriate token expiration times based on your security requirements
- Keep
cookie_secure=Truein production when using cookie-based authentication - Consider implementing rate limiting on your authentication endpoints to prevent brute force attacks
What's New in 0.6.0
New
- Password reset:
POST /password/forgot+POST /password/resetwith stateless single-use tokens (a token dies the moment the password changes) - Password change:
POST /password/changefor logged-in users - Email verification:
POST /email/verify/request+POST /email/verify, plus theauth.verified_userdependency and anemail_verifiedcolumn - Token revocation:
POST /logout/allandauth.revoke_all_tokens()invalidate all sessions via atoken_versioncolumn; password reset/change do this automatically - Delivery hooks:
@auth.on_password_resetand@auth.on_email_verifyconnect the flows to your email sending; in development, tokens print to the console - Custom JWT claims:
@auth.token_claimsmerges your claims into every issued token - Clear custom-model errors: a wrong
__tablename__on a custom user model now fails at startup with instructions instead of breaking silently at runtime
Upgrading an existing database: v0.6.0 adds two columns to the user table. For SQLite dev databases, delete the file and restart; for live databases run:
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).
What's New in 0.5.0
New
- Zero-config start:
secret_keyis now optional; FastAuth readsSECRET_KEY/FASTAUTH_SECRET_KEYfrom the environment, or manages a dev secret in.fastauth-secret - Production mode:
production=True(orFASTAUTH_PRODUCTION=1) requires a strong secret, secures cookies, and refuses the default admin password - Ready-made dependencies:
auth.current_user,auth.admin,auth.roles(...),auth.all_roles(...),auth.required,auth.admin_required - Password rules: registration enforces
password_min_length(default 8, set 0 to disable) with aFASTAUTH_WEAK_PASSWORDerror - AGENTS.md: machine-readable API reference so AI coding assistants integrate FastAuth correctly
Changed
cookie_securenow defaults toFalsein development andTruein production mode (explicit values always win)- An explicit
Authorization: Bearerheader now takes precedence over the auth cookie engineis keyword-friendly and its absence is a clear error
What's New in 0.4.0
Fixes
- Fixed compatibility with modern
bcrypt(≥ 4.1, including 5.x) by hashing with bcrypt directly. The unmaintainedpasslibdependency is gone, and existing password hashes keep working - Removed the shared long-lived database session; every operation now uses a short-lived session, fixing thread-safety issues and a bug where one failed request could break all subsequent logins
- Disabled users can no longer log in or refresh tokens
- Registering with a duplicate email now returns a clean
409instead of a server error - Role checks and the CLI now respect custom user models
- Removed debug
print()statements that leaked token prefixes to stdout - Removed the unused
python-josedependency
New
auth.setup(app): one-call integrationPOST /logoutendpoint that clears the auth cookiecookie_secure/cookie_samesiteoptions; the auth cookie now expires with the token/token/refreshaccepts a documentedRefreshRequestbody (visible in/docs)- GitHub Actions CI running the test suite on Python 3.10–3.14
Breaking changes
- Python 3.10+ is now required
- The deprecated root-level
fastauth.py/User.pycompatibility shims were removed; import everything from thefastauthpackage instead FastAuthno longer exposes a shared.sessionattribute; pass a session toauthenticate_user(..., session=...)or let it create one automatically
Project Structure
FastAuth follows a modular architecture for better maintainability:
fastauth/
├── core/ # The main FastAuth class
├── security/ # Password hashing and JWT token management
├── models/ # User, role, and token models/schemas
├── routers/ # Route handlers for auth and roles
├── dependencies/ # FastAPI dependencies for auth and roles
├── exceptions.py # Standardized exception classes and handlers
├── cli.py # Database initialization CLI
└── utils/ # Utility functions and helpers
License
MIT
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 fastauth_iq-0.6.0.tar.gz.
File metadata
- Download URL: fastauth_iq-0.6.0.tar.gz
- Upload date:
- Size: 47.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b05dc6847b0689b82f3722b7c69af4df225854ac41cea4046a8d719c65f5149f
|
|
| MD5 |
0bbd857431d2f1eff52b66e85fd42a54
|
|
| BLAKE2b-256 |
b70e9992705e2841b3153267d9dc66d7ae5b8b5d9dc7ba282bd100f37a09b6c7
|
Provenance
The following attestation bundles were made for fastauth_iq-0.6.0.tar.gz:
Publisher:
publish.yml on hu55ain3laa/fastauth
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fastauth_iq-0.6.0.tar.gz -
Subject digest:
b05dc6847b0689b82f3722b7c69af4df225854ac41cea4046a8d719c65f5149f - Sigstore transparency entry: 2417943928
- Sigstore integration time:
-
Permalink:
hu55ain3laa/fastauth@792ca20fbd966cf55f02366771e16a075a9191d1 -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/hu55ain3laa
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@792ca20fbd966cf55f02366771e16a075a9191d1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fastauth_iq-0.6.0-py3-none-any.whl.
File metadata
- Download URL: fastauth_iq-0.6.0-py3-none-any.whl
- Upload date:
- Size: 37.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
387c0f9170118e9d153be5394ae120308cb7fdf25242ff21a964f5116e552c58
|
|
| MD5 |
4aeca1652f40eb7e12d29c1922699fe3
|
|
| BLAKE2b-256 |
1559a8b0be2c6a4f2bf718013976a0250294d17681897d28eabbcf94abececa4
|
Provenance
The following attestation bundles were made for fastauth_iq-0.6.0-py3-none-any.whl:
Publisher:
publish.yml on hu55ain3laa/fastauth
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fastauth_iq-0.6.0-py3-none-any.whl -
Subject digest:
387c0f9170118e9d153be5394ae120308cb7fdf25242ff21a964f5116e552c58 - Sigstore transparency entry: 2417944749
- Sigstore integration time:
-
Permalink:
hu55ain3laa/fastauth@792ca20fbd966cf55f02366771e16a075a9191d1 -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/hu55ain3laa
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@792ca20fbd966cf55f02366771e16a075a9191d1 -
Trigger Event:
push
-
Statement type: