Skip to content

SQLModel Adapter

The recommended adapter for most projects.

Installation

pip install fastapi-fullauth[sqlmodel]

Setup

1. Define your tables

Each table you use is a concrete class you define by combining a *Mixin with table=True. Only subclass the mixins for features you actually use.

from sqlmodel import Field, Relationship
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()

UserMixin provides these fields:

Field Type Description
id UUID (UUID7) Primary key, auto-generated
email str Unique, indexed
hashed_password str \| None Password hash. NULL for OAuth-only users.
is_active bool Account active flag
is_verified bool Email verified flag
is_superuser bool Superuser flag
created_at datetime UTC creation timestamp

2. Create the adapter

from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine

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

You can use either SQLAlchemy's AsyncSession or SQLModel's AsyncSession:

from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine

engine = create_async_engine("sqlite+aiosqlite:///app.db")
session_maker = async_sessionmaker(engine, expire_on_commit=False)
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.ext.asyncio import async_sessionmaker
from sqlmodel.ext.asyncio.session import AsyncSession

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

Then create the adapter = pass every concrete class you defined:

from fastapi_fullauth.adapters import SQLModelAdapter

adapter = SQLModelAdapter(
    session_maker=session_maker,
    user_model=User,
    refresh_token_model=RefreshToken,
    role_model=Role,
    user_role_model=UserRole,
)

Required kwargs: user_model, refresh_token_model. Optional kwargs (required if you use the matching feature): role_model, user_role_model, permission_model, role_permission_model, oauth_account_model, passkey_model. Calling a feature method without its model raises RuntimeError.

3. Wire into FullAuth

from fastapi_fullauth import FullAuth, FullAuthConfig

fullauth = FullAuth(
    adapter=adapter,
    config=FullAuthConfig(
        SECRET_KEY="your-secret-key",
    ),
)

Tables created

Tables are created based on which mixins you subclass:

Group Tables Mixins
Core (always) fullauth_users, fullauth_refresh_tokens UserMixin, RefreshTokenMixin
Roles fullauth_roles, fullauth_user_roles RoleMixin, UserRoleMixin
Permissions fullauth_permissions, fullauth_role_permissions PermissionMixin, RolePermissionMixin
OAuth fullauth_oauth_accounts OAuthAccountMixin
Passkeys fullauth_passkeys PasskeyMixin

Custom schemas

Define your own schemas and pass them to the adapter:

from fastapi_fullauth import UserSchema, CreateUserSchema

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

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

adapter = SQLModelAdapter(
    session_maker=session_maker,
    user_model=User,
    refresh_token_model=RefreshToken,
    user_schema=MyUserSchema,
    create_user_schema=MyCreateSchema,
)

If you don't pass custom schemas, the base UserSchema and CreateUserSchema are used.

OAuth support

The SQLModel adapter implements OAuthAdapterMixin. Define an OAuthAccount from OAuthAccountMixin and pass it to the adapter as oauth_account_model=....