Skip to main content

Standalone FastAPI JWT auth with admin-approved registration, password management, and extensible token claims.

Project description

fastapi-auth-admin

Standalone JWT authentication package for FastAPI applications with admin-approved registration, password management, and extensible token claims (e.g. multi-tenant company_id).

Installation

pip install fastapi-auth-admin

Or with uv:

uv add fastapi-auth-admin

All dependencies (fastapi, sqlalchemy, aiosqlite, bcrypt, pyjwt, pydantic[email], python-multipart) are installed automatically.

Features

  • One-call setup — setup_auth(app) does everything
  • Fully async — built on SQLAlchemy async + aiosqlite
  • Email/password registration and login
  • Admin-approved user registration workflow
  • JWT tokens with extensible arbitrary claims
  • Password change (authenticated, requires current password)
  • Async SQLAlchemy user repository (dedicated users.db database)
  • Auto-seeded admin user on first run
  • Swagger UI /docs compatible (OAuth2 password flow)

Quick start

Two touch points — that's it:

1. Entry point — one call to set up auth:

from fastapi import FastAPI
from fastapi_auth import setup_auth

app = FastAPI()
setup_auth(app)

This single call:

  • Configures JWT security
  • Registers an async startup handler that initializes the users.db SQLite database and seeds the default admin user
  • Registers all /auth/* endpoints on your app

2. Endpoints — add RequireLogin where needed:

from fastapi_auth import RequireLogin

@router.get("/orders")
async def list_orders(user: RequireLogin):
    ...

Run with:

uvicorn myapp:app --reload

setup_auth options

setup_auth(
    app,
    secret_key="your-secret-key-min-32-bytes-long!",  # JWT secret (random per process unless set; use a fixed key in production)
    algorithm="HS256",                                  # JWT algorithm (default)
    expire_minutes=30,                                  # token TTL (default)
    db_url="sqlite+aiosqlite:///./users.db",            # async database URL (default)
)

Any async SQLAlchemy-compatible URL works:

setup_auth(app, db_url="sqlite+aiosqlite:///./data/auth.db")           # custom SQLite path
setup_auth(app, db_url="postgresql+asyncpg://user:pass@host/mydb")     # PostgreSQL (requires asyncpg)

Endpoints

Method Path Auth Description
POST /auth/register public Register a new user (pending)
POST /auth/login public Login, returns JWT (OAuth2 form)
GET /auth/me login Current user info + token claims
POST /auth/change-password login Change own password
GET /auth/pending admin List unapproved users
POST /auth/approve admin Approve a user by email
POST /auth/reject admin Reject a user by email

Default admin

On first startup the adapter auto-creates an admin user:

  • Email: admin@admin.com
  • Password: changeme

Change the password immediately after first login via /auth/change-password.

Protecting endpoints

Add RequireLogin as a parameter to any endpoint to require a valid JWT:

from fastapi import APIRouter
from fastapi_auth import RequireLogin

router = APIRouter()

@router.get("/dashboard")
async def dashboard(user: RequireLogin):
    print(user.sub)                        # user email
    print(user.extra.get("is_admin"))      # True/False

If you don't need user info in the function body, it still enforces authentication just by being declared as a parameter.

Multi-tenant / custom token claims

The JWT token supports arbitrary extra claims. Call the login use case directly with extra_claims:

from fastapi_auth.use_cases import login

token = await login(
    email="user@example.com",
    password="secret",
    repo=repo,
    extra_claims={"company_id": 42, "role": "manager"},
)

These claims are available in any protected endpoint:

@router.get("/tenant-data")
async def tenant_data(user: RequireLogin):
    company_id = user.extra.get("company_id")
    role = user.extra.get("role")

Custom user repository

Implement the UserRepositoryPort protocol to use any async storage backend:

from fastapi_auth import UserRepositoryPort, User, set_get_user_repo

class MyUserRepository:
    async def find_by_email(self, email: str) -> User | None: ...
    async def create(self, user: User) -> None: ...
    async def update(self, user: User) -> None: ...
    async def list_pending(self) -> list[User]: ...
    async def ensure_admin(self, email: str, hashed_password: str) -> None: ...

async def get_user_repo():
    yield MyUserRepository()

set_get_user_repo(get_user_repo)

Testing

The test suite uses pytest-asyncio and httpx. Each test gets an isolated in-memory database:

uv sync --group dev
uv run pytest

To add the dev dependencies to your own project:

uv add --group dev pytest pytest-asyncio httpx

Configure pytest-asyncio in pyproject.toml:

[tool.pytest.ini_options]
asyncio_mode = "auto"

Use httpx.AsyncClient with ASGITransport to test endpoints without a running server:

import pytest
from fastapi import FastAPI
from httpx import ASGITransport, AsyncClient
from fastapi_auth import auth_router, configure_security, set_get_user_repo
from fastapi_auth.sqlalchemy_adapter import get_user_repo, init_db

@pytest.fixture
async def client():
    configure_security(secret_key="a-secret-key-long-enough-for-hs256")
    await init_db("sqlite+aiosqlite:///:memory:")
    set_get_user_repo(get_user_repo)
    app = FastAPI()
    app.include_router(auth_router)
    async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac:
        yield ac

Package structure

fastapi_auth/
  __init__.py            # setup_auth() + public API exports
  models.py              # User, TokenPayload dataclasses
  ports.py               # UserRepositoryPort protocol (async)
  errors.py              # AuthError, InvalidCredentials, NotAuthorized, ...
  security.py            # bcrypt password hashing, JWT encode/decode, configure()
  use_cases.py           # async: register, login, approve, reject, change_password, list_pending
  dependencies.py        # FastAPI deps: get_current_user, RequireLogin
  router.py              # APIRouter with all auth endpoints (async handlers)
  sqlalchemy_adapter.py  # Async SQLAlchemy + aiosqlite user repository (default, recommended)
  json_adapter.py        # JSON file user repository (dev/prototyping only)

Workflow

  1. Admin logs in with default credentials
  2. Users register via POST /auth/register (created as unapproved)
  3. Admin views pending users via GET /auth/pending
  4. Admin approves (POST /auth/approve) or rejects (POST /auth/reject)
  5. Approved users can log in and receive a JWT
  6. Users change their own password via POST /auth/change-password

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_auth_admin-0.2.0.tar.gz (37.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_auth_admin-0.2.0-py3-none-any.whl (13.0 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_auth_admin-0.2.0.tar.gz.

File metadata

  • Download URL: fastapi_auth_admin-0.2.0.tar.gz
  • Upload date:
  • Size: 37.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for fastapi_auth_admin-0.2.0.tar.gz
Algorithm Hash digest
SHA256 09d124b0bb8a05c2efdf82dbb0483efdf5349515ee148e4a2ba416e3f4f83b69
MD5 2504fad471390bfef7523562aa29be86
BLAKE2b-256 a7900bf56f8b3d144e45d301b9f4d7a1cac9b6af6efa4ae7aed90c9adaa90ceb

See more details on using hashes here.

File details

Details for the file fastapi_auth_admin-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: fastapi_auth_admin-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 13.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for fastapi_auth_admin-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 18de1d4cf51828a62ee4015704f83e9c7e79bda985e4b65e841c1688d9a1f247
MD5 8ef262a1bb47fc042005880682235c09
BLAKE2b-256 af3f49bf91a0ff63d6ad2cddf9393b532113a68d687485d9bcb47e5c5e6162e9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page