Skip to main content

FastAPI FullAuth

FastAPI FullAuth

Production-grade, async-native authentication and authorization for FastAPI.

PyPI Downloads Python CI License Docs

Documentation: https://mdfarhankc.github.io/fastapi-fullauth
Source Code: https://github.com/mdfarhankc/fastapi-fullauth


A complete, async-native authentication and authorization system for FastAPI - production-ready and pluggable. JWT access/refresh tokens with rotation, Argon2 password hashing, email verification, OAuth2 social login, passkeys, session management, and role-based access control, all out of the box. Bring your own database with the SQLModel, SQLAlchemy, Tortoise ORM, or Beanie (MongoDB) adapter, and opt into only the features you need.

Features

  • JWT access + refresh tokens with configurable expiry
  • Refresh token rotation with reuse detection; revokes entire session family on replay. Tokens are stored as sha256 digests, so a leaked database exposes no usable sessions
  • Secure by default: registration anti-enumeration, login timing-attack defense, account lockout, and spoof-resistant client IP resolution are all on out of the box
  • Session management: list active sessions (device, IP, last used), revoke one device, or sign out everywhere else
  • Password hashing via Argon2id (default) or bcrypt, offloaded to a worker thread, with transparent rehashing
  • Email verification and password reset flows with event hooks
  • Passkey (WebAuthn): passwordless login with fingerprint, Face ID, security keys
  • OAuth2 social login: Google, GitHub, Discord, and GitLab built in; add your own provider by subclassing StandardOAuthProvider
  • Role-based access control: current_user, require_role(), require_permission(), and typed dependencies for custom user schemas
  • Rate limiting: per-route auth limits + global middleware (memory or Redis)
  • CSRF protection and security headers middleware
  • Bearer or cookie transport: opt into HttpOnly cookies that carry both access and refresh tokens, out of JavaScript's reach; bearer is the default
  • Pluggable adapters: SQLModel, SQLAlchemy, Tortoise ORM, Beanie (MongoDB), or write your own for any data store
  • Generic type parameters: define your own schemas with full IDE support and type safety
  • Any primary key type: UUID by default, or UserSchema[int] for integer and sequence keys, UserSchema[str] for string keys
  • Composable routers: include only the route groups you need
  • Event hooks: after_register, after_login, send_verification_email, etc.
  • Custom JWT claims: embed app-specific data in tokens
  • Structured logging: all auth events, security violations, and failures logged
  • Redis support: token blacklist and rate limiter backends
  • Python 3.10 - 3.14 supported

Installation

The fastest way to start: one adapter plus every optional feature in a single extra.

# Recommended: SQLModel adapter + Redis, OAuth, passkeys, bcrypt
pip install "fastapi-fullauth[sqlmodel-standard]"

# Same, on the SQLAlchemy adapter
pip install "fastapi-fullauth[sqlalchemy-standard]"

Or stay minimal and add only what you use:

# Core + one ORM adapter (pick one)
pip install "fastapi-fullauth[sqlmodel]"

# Mix and match any extras
pip install "fastapi-fullauth[sqlalchemy,oauth,redis]"
Extra Adds
sqlmodel / sqlalchemy SQL ORM adapter + Alembic (pick one)
tortoise Tortoise ORM adapter (async SQL)
beanie Beanie adapter (MongoDB)
redis Redis backends for token blacklist, lockout, rate limiting, passkey challenges
oauth OAuth2 social login (Google, GitHub, Discord, GitLab)
passkey Passkey / WebAuthn support
bcrypt bcrypt password hashing (Argon2id is the default and needs no extra)
sqlmodel-standard / sqlalchemy-standard / tortoise-standard / beanie-standard One adapter plus all of the above

Quotes around the package spec keep shells like zsh from globbing the [extras].

Quick start

from fastapi import FastAPI
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
from sqlmodel import Relationship

from fastapi_fullauth import FullAuth, FullAuthConfig
from fastapi_fullauth.adapters import SQLModelAdapter
from fastapi_fullauth.models.sqlmodel import RefreshTokenMixin, UserMixin


class RefreshToken(RefreshTokenMixin, table=True):
    pass


class User(UserMixin, table=True):
    refresh_tokens: list[RefreshToken] = Relationship()


engine = create_async_engine("sqlite+aiosqlite:///./app.db")
session_maker = async_sessionmaker(engine, expire_on_commit=False)

app = FastAPI()
fullauth = FullAuth(
    adapter=SQLModelAdapter(
        session_maker=session_maker,
        user_model=User,
        refresh_token_model=RefreshToken,
    ),
    config=FullAuthConfig(SECRET_KEY="your-secret-key"),
)
fullauth.init_app(app)

That's it; all auth routes are registered under /api/v1/auth/ automatically. Create the tables with Alembic (see the migrations guide) or SQLModel.metadata.create_all for a quick local start.

The SQLite quick-start needs an async driver: pip install aiosqlite.

Omit config in dev and a random secret key is generated (tokens won't survive restarts).

Composable routers

Opt in to a subset of routers:

fullauth.init_app(app, include_routers=["auth", "profile"])

include_routers=None (default) registers every available router. Or wire routers manually for full control:

app = FastAPI()
fullauth.bind(app)  # required for dependencies to work

app.include_router(fullauth.auth_router, prefix="/api/v1/auth")
app.include_router(fullauth.profile_router, prefix="/api/v1/auth")

bind() registers no shutdown cleanup (only init_app() wraps the lifespan), so on this path call await fullauth.aclose() in your shutdown to release pooled Redis connections and OAuth HTTP clients.

Router Routes
auth_router register, login, logout, refresh
profile_router me, verified-me, update profile, delete account, change password
verify_router email verification, password reset
admin_router assign/remove roles and permissions (superuser)
oauth_router OAuth provider routes (only if configured)
passkey_router Passkey register, authenticate, list, delete (only if enabled)
sessions_router list active sessions, revoke one device, sign out others

Middleware

init_app() does not wire any middleware automatically. Import what you want and add it yourself:

from fastapi_fullauth.middleware import (
    SecurityHeadersMiddleware,
    CSRFMiddleware,
    RateLimitMiddleware,
)

app.add_middleware(SecurityHeadersMiddleware)
app.add_middleware(CSRFMiddleware, secret=fullauth.config.SECRET_KEY)
app.add_middleware(RateLimitMiddleware, max_requests=60, window_seconds=60)

Token transport

By default, tokens are returned in the response body for Authorization: Bearer use. Opt into cookie transport to carry both the access and refresh tokens in separate HttpOnly cookies, out of JavaScript's reach:

from fastapi_fullauth.backends import CookieBackend

fullauth = FullAuth(
    adapter=adapter,
    config=config,
    backends=[CookieBackend(config)],
)

/refresh and /logout then read the tokens from the cookies, so the browser never stores them. Wire CSRFMiddleware whenever you use cookie transport.

Routes

Method Path Description
POST /auth/register Create a new user
POST /auth/login Authenticate, get tokens
POST /auth/logout Blacklist token
POST /auth/refresh Rotate token pair
GET /auth/sessions List active sessions
DELETE /auth/sessions/{family_id} Revoke one session
POST /auth/sessions/revoke-others Sign out other sessions
GET /auth/me Get current user
GET /auth/me/verified Verified users only
PATCH /auth/me Update profile
DELETE /auth/me Delete account
POST /auth/change-password Change password
POST /auth/verify-email/request Request verification email
POST /auth/verify-email/confirm Confirm email
POST /auth/password-reset/request Request password reset
POST /auth/password-reset/confirm Reset password
POST /auth/admin/assign-role Assign role (superuser)
POST /auth/admin/remove-role Remove role (superuser)
POST /auth/admin/assign-permission Assign permission to role (superuser)
POST /auth/admin/remove-permission Remove permission from role (superuser)
GET /auth/admin/role-permissions/{role_name} List role's permissions (superuser)

With OAuth enabled, additional routes are registered under /auth/oauth/. All routes are prefixed with /api/v1 by default.

Custom user schemas

Combine each mixin with table=True (or your DeclarativeBase for the SQLAlchemy adapter), then pass everything to the adapter:

from sqlmodel import Field, Relationship
from fastapi_fullauth import FullAuth, FullAuthConfig, UserSchema, CreateUserSchema
from fastapi_fullauth.adapters import SQLModelAdapter
from fastapi_fullauth.models.sqlmodel import (
    RefreshTokenMixin, RoleMixin, UserMixin, UserRoleMixin,
)


class RefreshToken(RefreshTokenMixin, table=True): pass
class Role(RoleMixin, table=True): pass
class UserRole(UserRoleMixin, table=True): pass


class User(UserMixin, table=True):
    display_name: str = Field(default="", max_length=100)
    phone: str = Field(default="", max_length=20)
    roles: list[Role] = Relationship(link_model=UserRole)
    refresh_tokens: list[RefreshToken] = Relationship()


class MyUserSchema(UserSchema):
    display_name: str = ""
    phone: str = ""


class MyCreateSchema(CreateUserSchema):
    display_name: str = ""


fullauth = FullAuth(
    adapter=SQLModelAdapter(
        session_maker,
        user_model=User,
        refresh_token_model=RefreshToken,
        role_model=Role,
        user_role_model=UserRole,
        user_schema=MyUserSchema,
        create_user_schema=MyCreateSchema,
    ),
    config=FullAuthConfig(SECRET_KEY="..."),
)

Full IDE autocompletion and type checking on custom fields:

from typing import Annotated
from fastapi import Depends
from fastapi_fullauth.dependencies import current_user, current_active_verified_user

CurrentUser = Annotated[MyUserSchema, Depends(current_user)]
VerifiedUser = Annotated[MyUserSchema, Depends(current_active_verified_user)]

@app.get("/profile")
async def profile(user: CurrentUser):
    return {"name": user.display_name}  # IDE knows this field exists

Protected routes

from typing import Annotated
from fastapi import Depends
from fastapi_fullauth.dependencies import current_user, current_active_verified_user, current_superuser, require_role

CurrentUser = Annotated[UserSchema, Depends(current_user)]
VerifiedUser = Annotated[UserSchema, Depends(current_active_verified_user)]
SuperUser = Annotated[UserSchema, Depends(current_superuser)]

@app.get("/profile")
async def profile(user: CurrentUser):
    return user

@app.get("/dashboard")
async def dashboard(user: VerifiedUser):
    return {"email": user.email}

@app.delete("/admin/users/{id}")
async def delete_user(user: SuperUser):
    ...

@app.get("/editor")
async def editor_panel(user=Depends(require_role("editor"))):
    ...

OAuth2 social login

from fastapi_fullauth import FullAuth, FullAuthConfig
from fastapi_fullauth.oauth.google import GoogleOAuthProvider
from fastapi_fullauth.oauth.github import GitHubOAuthProvider

fullauth = FullAuth(
    adapter=adapter,
    config=FullAuthConfig(SECRET_KEY="..."),
    providers=[
        GoogleOAuthProvider(
            client_id="your-google-client-id",
            client_secret="your-google-secret",
            redirect_uris=[
                "http://localhost:3000/auth/callback",
                "https://myapp.com/auth/callback",
            ],
        ),
        GitHubOAuthProvider(
            client_id="your-github-client-id",
            client_secret="your-github-secret",
            redirect_uris=["http://localhost:3000/auth/callback"],
        ),
    ],
)

Requires httpx: pip install "fastapi-fullauth[oauth]"

Security note: the OAuth state token is signed and carries the PKCE challenge, but it is not bound to the browser session. For defense against login-CSRF, also bind state to the initiating browser (e.g. a short-lived cookie you set before redirecting and verify on callback).

Event hooks

@fullauth.hooks.on("after_register")
async def welcome(user):
    await send_email(user.email, "Welcome!")

@fullauth.hooks.on("send_verification_email")
async def send_verify(email, token):
    await send_email(email, f"Verify: https://myapp.com/verify?token={token}")

Events: after_register, after_login, after_logout, after_password_change, after_password_reset, after_email_verify, send_verification_email, send_password_reset_email, after_oauth_login, after_oauth_register

Configuration

Pass a FullAuthConfig object or set env vars with FULLAUTH_ prefix.

fullauth = FullAuth(
    adapter=adapter,
    config=FullAuthConfig(
        SECRET_KEY="...",
        ACCESS_TOKEN_EXPIRE_MINUTES=60,
        API_PREFIX="/api/v2",
        LOGIN_FIELD="username",
        PASSWORD_HASH_ALGORITHM="bcrypt",
        BLACKLIST_BACKEND="redis",
        REDIS_URL="redis://localhost:6379/0",
        AUTH_RATE_LIMIT_ENABLED=True,
        TRUSTED_PROXY_HEADERS=["X-Forwarded-For"],
    ),
)

See Configuration docs for all options.

AI-friendly docs

Using an AI coding assistant? Install the fastapi-fullauth Agent Skill so it knows the library's APIs, contracts, and pitfalls:

npx skills add mdfarhankc/fastapi-fullauth

It works with any agent that supports the Agent Skills standard, including Claude Code, Codex, Cursor, GitHub Copilot, and Gemini CLI.

For tools that take a docs URL instead:

  • llms.txt: concise overview with links to all doc pages
  • llms-full.txt: full documentation in a single file

Development

git clone https://github.com/mdfarhankc/fastapi-fullauth.git
cd fastapi-fullauth
uv sync --dev --extra sqlalchemy --extra sqlmodel
uv run pytest tests/ -v

# run examples
uv run uvicorn examples.sqlmodel_app.main:app --reload

License

MIT

Metadata

Release files for fastapi-fullauth 0.16.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fastapi-fullauth 0.16.0
File Size Uploaded
fastapi_fullauth-0.16.0.tar.gz 445.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fastapi-fullauth 0.16.0
File Interpreter ABI Platform
fastapi_fullauth-0.16.0-py3-none-any.whl Python 3 none any Details

Total release size: 585.6 kB

Release files / fastapi_fullauth-0.16.0.tar.gz

Download URL fastapi_fullauth-0.16.0.tar.gz
Size 445.8 kB
Tags Source
SHA-256 checksum
How to use checksums
2e530d6c0465a6104bedcfdc291a4f8cc8f889e69b8c924083d63df5828eae2c
BLAKE2b-256 checksum
How to use checksums
76913bdba0b5cdad45c864c9dfd0cc46fac4885928b2b82b14be117eba0698d3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.

Transparency log

Release files / fastapi_fullauth-0.16.0-py3-none-any.whl

Download URL fastapi_fullauth-0.16.0-py3-none-any.whl
Size 139.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8c40017815ad15f8a6225c3deae4d196197325c36962a623a8e99492bdd2a68c
BLAKE2b-256 checksum
How to use checksums
c00d712ac56013748bd7bf34ce9e8a7c5ea4471e7a4a9a5aea322a913d99f23b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.

Transparency log

Release history Release notifications | RSS feed

0.17.2

2 release files

0.17.1

2 release files

0.17.0

2 release files

This release

0.16.0 This release

2 release files

0.14.1

2 release files

0.14.0

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page