Skip to main content

A reusable, database-backed authentication, user management, and audit logs plugin for FastAPI with a built-in admin dashboard.

Project description

AuthKit FastAPI

A highly secure, reusable, database-backed authentication, user management, and audit logging plugin for FastAPI. Exposes standard JSON API endpoints, secures routes via role-based dependency injections, and renders a stunning out-of-the-box HTML admin dashboard.


Key Features

  • Dual-Token JWT Security: Uses short-lived Access JWTs and long-lived Refresh JWTs. Checked in HTTP-only cookies first (highly secure for web applications) with Bearer Header fallback (for APIs and mobile applications).
  • Database Session Revocation: Stores active refresh tokens securely (SHA-256 hashed) in the database. Allows users to sign out of single devices or revoke all sessions across all devices.
  • Built-in Glassmorphic Admin Dashboard: Serves a premium dark-themed visual user administration panel. Admin users can activate/deactivate user accounts, change roles, inspect and search system audit logs, and revoke active device sessions.
  • Hybrid Audit Trail Logging: Automatically records all security events (successful/failed logins, registrations, password resets) and exposes a helper function for host applications to record custom actions.
  • SQLite & Supabase (Postgres) Compatibility: Built-in safeguards including dynamic UUID-as-String columns, event listeners to enforce foreign keys on SQLite, and generic JSON structures.
  • CLI Scaffolding Tool: Spin up a fully configured authentication architecture in any project in seconds using authkit init.

Installation

Install the package directly into your virtual environment:

pip install fast-authkit

Or using uv:

uv add fast-authkit

Getting Started: Bootstrap in 3 Steps

Step 1: Initialize code scaffolding

Run the initializer command in the root of your new project:

authkit init
# or
uv run authkit init

This scaffolds a local auth/ module and pre-fills environment files:

project-root/
├── .env                               # Active configuration values (ignored in git)
├── .env.example                       # Configuration template
└── auth/                              # Local Auth Module
    ├── __init__.py
    ├── setup.py                       # SQLAlchemy engine & AuthKit instantiation
    ├── models.py                      # Subclassable database tables
    └── schemas.py                     # Extensible validation schemas

Step 2: Configure variables

Review the generated .env file. A strong random secret key is automatically generated for you:

AUTHKIT_SECRET_KEY=e83d8a9f23...
AUTHKIT_DATABASE_URL=sqlite+aiosqlite:///./authkit.db
AUTHKIT_COOKIE_SECURE=False
AUTHKIT_COOKIE_SAMESITE=lax

Note: For production (e.g. Supabase Postgres), change AUTHKIT_DATABASE_URL to postgresql+asyncpg://... and set AUTHKIT_COOKIE_SECURE=True.

Step 3: Mount in your FastAPI app

In your main FastAPI entry point (e.g. main.py), import the bootstrapped module and mount the routers:

from fastapi import FastAPI
from auth import auth_kit, init_db

app = FastAPI(title="My AI Application")

# Mount JSON endpoints (register, login, refresh, logout, profile)
app.include_router(auth_kit.router, prefix="/auth", tags=["Authentication"])

# Mount Visual HTML Admin Dashboard
app.include_router(auth_kit.admin_router, prefix="/admin", tags=["Admin Panel"])

@app.on_event("startup")
async def startup():
    # Automatically creates SQLite tables if they do not exist
    await init_db()

Run your server:

uvicorn main:app --reload

You can now access:

  1. Interactive Swagger API Docs: http://127.0.0.1:8000/docs
  2. Visual Admin Dashboard: http://127.0.0.1:8000/admin (to log in, create a user and set their role to "admin" in the database).

Integrating with Existing Projects (Manual Setup)

If you already have an existing project with defined database models and configurations, you do not need to use authkit init. You can integrate the prebuilt routers and mixins directly.

Step 1: Mixin Auth Columns into Your SQLAlchemy Models

Import the SQLAlchemy base mixins and mix them into your existing models in your models.py file:

from sqlalchemy import Column, String
from database import Base  # Your existing declarative base
from authkit_fastapi.models import BaseUserMixin, BaseRefreshTokenMixin, BaseAuditLogMixin

# 1. Mix fields into your existing User model
class User(BaseUserMixin, Base):
    __tablename__ = "users"
    
    # Your existing columns
    full_name = Column(String(100), nullable=True)

# 2. Inherit RefreshToken and AuditLog models
class RefreshToken(BaseRefreshTokenMixin, Base):
    __tablename__ = "refresh_tokens"

class AuditLog(BaseAuditLogMixin, Base):
    __tablename__ = "audit_logs"

Step 2: Initialize AuthKit

Create your configuration and instantiate AuthKit passing your existing session maker and models:

from authkit_fastapi import AuthKit, AuthKitConfig
from database import async_session_maker  # Your existing async session maker
from models import User, RefreshToken, AuditLog

# Configure settings (including custom claims and audience verification)
config = AuthKitConfig(
    secret_key="your-secure-secret-key",
    cookie_secure=True,  # Set to True in production (HTTPS)
    
    # Custom Callback to inject extra claims into the Access Token payload
    # Signature: Callable[[Any], Dict[str, Any]]
    access_token_claims=lambda user: {"tenant_id": "hotel-123", "aud": "my-app"},
    
    # Expected JWT audience for verification (optional)
    jwt_audience="my-app"
)

auth_kit = AuthKit(
    config=config,
    db_session_maker=async_session_maker,
    user_model=User,
    refresh_token_model=RefreshToken,
    audit_log_model=AuditLog
)

Step 3: Mount Routers in FastAPI

Mount the prebuilt JSON endpoints and the Admin Dashboard routers directly inside your application:

from fastapi import FastAPI
from setup_auth import auth_kit  # Import the instance from Step 2

app = FastAPI()

# Mount all JSON APIs (/auth/login, /auth/register, /auth/logout, etc.)
app.include_router(auth_kit.router, prefix="/auth", tags=["Auth"])

# Mount HTML Admin dashboard (/admin, /admin/dashboard, etc.)
app.include_router(auth_kit.admin_router, prefix="/admin", tags=["Admin Dashboard"])

Usage Guide

Protecting Host Application Routes

Secure your own application endpoints using Depends along with AuthKit dependencies:

from fastapi import FastAPI, Depends
from auth import auth_kit

app = FastAPI()

# 1. Require any active authenticated user
@app.get("/profile")
def read_profile(user = Depends(auth_kit.current_active_user)):
    return {"email": user.email, "role": user.role}

# 2. Restrict to Administrators only
@app.get("/system-settings")
def admin_settings(admin = Depends(auth_kit.current_admin)):
    return {"message": "Welcome back admin", "admin_id": admin.id}

# 3. Dynamic role requirements
@app.get("/moderation-queue")
def moderation_queue(user = Depends(auth_kit.requires_role("moderator"))):
    return {"status": "ok", "moderated_by": user.email}

# 4. Multi-role checks
@app.get("/editor-panel")
def editor_panel(user = Depends(auth_kit.requires_roles(["admin", "editor"]))):
    return {"message": "Granted access to editor/admin panel"}

Extending Database Tables

If you need to add custom columns to the User table (e.g., full_name, organization_id), simply edit the generated auth/models.py file:

# auth/models.py
from sqlalchemy import String, mapped_column
from authkit_fastapi.models import Base, BaseUserMixin

class User(Base, BaseUserMixin):
    __tablename__ = "users"
    
    # Custom fields added here!
    full_name: Mapped[str] = mapped_column(String(100), nullable=True)
    organization_id: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)

Don't forget to update your Pydantic schemas in auth/schemas.py to match:

# auth/schemas.py
from authkit_fastapi.schemas import UserCreate, UserRead

class CustomUserCreate(UserCreate):
    full_name: Optional[str] = None

class CustomUserRead(UserRead):
    full_name: Optional[str]

Extensible JWT Claims & Supabase/Hasura Compatibility

AuthKit makes it easy to integrate custom claims (like hotel_id or tenant_id) into your access token payloads.

1. Custom Claims Callback Hook

Register a custom callback during initialization to dynamic add key-value pairs to the payload:

config = AuthKitConfig(
    secret_key="your-secret-key",
    access_token_claims=lambda user: {
        "hotel_id": getattr(user, "hotel_id", None),
        "user_email": user.email
    }
)

2. Supabase/Hasura app_role Compatibility

By default, AuthKit puts the user's role in the "app_role" claim rather than "role". This is done to prevent conflicts with database-as-a-service providers (such as Supabase, Hasura, or PostgREST) which reserve "role" for database RLS policies (e.g. requiring "role" to be "authenticated").


Writing Custom Audit Logs

Keep track of critical operations in your app by using the hybrid audit logger:

from fastapi import FastAPI, Depends, Request
from sqlalchemy.ext.asyncio import AsyncSession
from auth import auth_kit

app = FastAPI()

@app.post("/train-ai-model")
async def run_ai(
    request: Request,
    db: AsyncSession = Depends(auth_kit.get_db),
    user = Depends(auth_kit.current_active_user)
):
    # Perform operation...
    
    # Audit log entry created automatically with user ID, IP address, and User-Agent
    await auth_kit.log_action(
        db=db,
        action="trained_ai_model",
        user_id=user.id,
        details={"model_type": "Transformer", "epochs": 10},
        request=request
    )
    
    return {"success": True}

Local Sandbox Verification

A pre-packaged sandbox app is provided in the repository for quick testing.

  1. Sync dependencies: uv sync
  2. Run the sandbox: uv run python examples/main.py
  3. Log in as admin:
    • Navigate to http://127.0.0.1:8000/admin
    • Use email admin@example.com and password adminpass123.

Running Tests

To run the automated pytest test suite:

uv run pytest

AuthKit Architecture: Explained Simply

To help you understand how AuthKit secures your application under the hood, here is a detailed breakdown of the token lifecycle, database session tracking, and the password reset flow.

🎭 The Real-World Analogy: The Amusement Park

  • Access Token (The Daily Ride Wristband): When you enter the amusement park, you get a colored paper wristband for the day. At every ride (endpoint), the ride operator (server middleware) just looks at your wristband to verify today's color. They don't check a computer database. It's extremely fast and easy. However, the wristband expires at the end of the day (short-lived Access Token) so you can't reuse it tomorrow.
  • Refresh Token (The 7-Day Season Pass Card): To get a new daily wristband tomorrow, you go to the ticket booth (the /refresh endpoint) and scan your Season Pass Card (Refresh Token). The agent checks the database to verify your card is active and not blocked. If valid, they issue a new daily wristband (Access Token), print a new barcode on your card for security (Refresh Token Rotation), and extend your card's validity for another 7 days (rolling expiry). However, if you don't visit the park for 7 consecutive days, your card expires, and you must go to the main office (log in again with password) to get a new one.
  • Revocation (Blacklisting the Card): If you click "Logout" or an admin deactivates your account, your Season Pass Card's barcode is instantly blacklisted in the system database. The next time you try to scan it at the ticket booth, it is rejected immediately, even if the 7-day timer has not run out.

1. Token & Session Lifecycle (Login, Access, and Refresh)

This sequence diagram illustrates the steps when a user logs in, accesses a protected API statelessly, and requests new tokens when their access token expires:

Token & Session Lifecycle

Under the Hood:

  1. Login: On successful authentication, AuthKit generates two JWTs: an Access Token (short lifespan) and a Refresh Token (long lifespan containing a unique random ID called jti).
  2. Session Record: The jti is hashed (SHA-256) and saved in the database RefreshToken table along with the user's IP address and User-Agent.
  3. HTTP-Only Cookies: Both tokens are set in the user's browser using secure, HttpOnly, SameSite=Lax cookies so JavaScript scripts cannot steal them.
  4. Token Rotation: When the Access Token expires, the client calls /auth/refresh. AuthKit inspects the Refresh Token, queries the database to verify the jti session record is not expired or marked is_revoked = True. If valid, it revokes the old session and issues brand new Access and Refresh tokens to prevent token reuse attacks.

2. Single-Use Password Reset Flow

This sequence diagram explains how AuthKit sends a password reset link and guarantees it cannot be reused (is strictly single-use) without creating extra database state:

Password Reset Lifecycle

Under the Hood:

  1. Link Request: The user submits their email. AuthKit reads their current hashed_password from the database.
  2. Cryptographic Signature (pwd_sec): It hashes a segment of the current password hash and places it inside the JWT payload as pwd_sec. The reset link is sent to the user's email.
  3. Submission & Verification: When the user opens the link and submits a new password, the server decodes the token, fetches the user, and compares the token's pwd_sec against the user's current database password hash.
  4. Immediate Invalidation: Once the password is reset, the user's password hash in the database is updated. If the user clicks the reset link in the email again, the token's pwd_sec will no longer match the user's new password hash, causing the validation to fail immediately.
  5. Session Cleanup: Updating the password automatically revokes all other active device sessions (sets is_revoked = True for all of the user's refresh tokens) for maximum account security.

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

fast_authkit-0.1.5.tar.gz (2.1 MB view details)

Uploaded Source

Built Distribution

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

fast_authkit-0.1.5-py3-none-any.whl (42.1 kB view details)

Uploaded Python 3

File details

Details for the file fast_authkit-0.1.5.tar.gz.

File metadata

  • Download URL: fast_authkit-0.1.5.tar.gz
  • Upload date:
  • Size: 2.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","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 fast_authkit-0.1.5.tar.gz
Algorithm Hash digest
SHA256 7fab756f2d7e1e36ce9267c01ddcbb65b3c917e8a7e779d528dc8ba52e4c9fa9
MD5 1f2c1947c1b752755d147a0071f4b4e5
BLAKE2b-256 bb6ffd3eed515e01a42a962b38cd65499ab1a1d95646320821cf245c0f6cee77

See more details on using hashes here.

File details

Details for the file fast_authkit-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: fast_authkit-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 42.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","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 fast_authkit-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 2df1a3426ee64e37685b5b13c2ba658d3e39050af936238a7c63215df2f5fcb1
MD5 7835436f93cb6def0c2f8eb11cab2495
BLAKE2b-256 0b588b9aa86339a3f19afeae242bb5822df4f69807885e6df8f0fdc136b18957

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