Skip to content

v0.10.0: mixin pivot, audit hardening, manual middleware#21

Merged
mdfarhankc merged 1 commit into
mainfrom
feat/v0.10.0-mixin-pivot
May 18, 2026
Merged

v0.10.0: mixin pivot, audit hardening, manual middleware#21
mdfarhankc merged 1 commit into
mainfrom
feat/v0.10.0-mixin-pivot

Conversation

@mdfarhankc
Copy link
Copy Markdown
Owner

@mdfarhankc mdfarhankc commented May 18, 2026

Breaking release.

Models now ship as *Mixin classes from fastapi_fullauth.models.{sqlalchemy,sqlmodel}. Bring your own Base/SQLModel; the library no longer attaches tables to your metadata. Adapter constructors take every concrete model as a kwarg. fastapi_fullauth.migrations removed.

Middleware is no longer auto-wired. init_app() only mounts routers — add SecurityHeadersMiddleware, CSRFMiddleware, RateLimitMiddleware yourself. init_middleware() and auto_middleware gone. create_rate_limiter() exported from fastapi_fullauth.protection.

Audit hardening:

  • /auth/refresh requires the refresh-token row in DB; signed JWT without a backing row is rejected.
  • PREVENT_LOGIN_TIMING_ATTACKS runs a dummy argon2 verify on unknown-user paths.
  • CSRFMiddleware(secret=...) required, validated >= 32 chars.
  • SECRET_KEY rejected under 32 chars; ALGORITHM constrained to HS256/384/512.
  • UUID(payload.sub) wrapped everywhere — bad sub returns 401, not 500.
  • Passkey /authenticate/begin returns identical shape for known vs unknown email.
  • Rate limits added on verify-email, password-reset confirm, oauth callback, passkey authenticate complete.

Config:

  • New global BACKEND and ORIGINS propagate to per-feature settings.
  • Removed: INCLUDE_USER_IN_LOGIN, CSRF_ENABLED, INJECT_SECURITY_HEADERS, RATE_LIMIT_ENABLED, ACCOUNT_LOCKED_EXCEPTION.

Renames: exclude_routers -> include_routers (allowlist), router/ -> routers/, dependencies/require_role.py -> dependencies/rbac.py, flows/update_profile.py -> flows/profile.py. core/redis_blacklist.py folded into core/blacklist.py.

Summary by CodeRabbit

v0.10.0 Release Notes

  • Breaking Changes

    • Model definitions now use mixins; define your own SQLAlchemy/SQLModel tables.
    • Adapter initialization requires passing each concrete model as keyword arguments.
    • Router registration syntax changed to include_routers allowlist; exclude_routers removed.
    • Middleware no longer auto-wired; add manually via app.add_middleware().
    • Removed fastapi_fullauth.migrations helper; manage Alembic metadata yourself.
    • Configuration fields INCLUDE_USER_IN_LOGIN, INJECT_SECURITY_HEADERS, CSRF_ENABLED removed.
  • Security Improvements

    • CSRF middleware now requires explicit secret validation.
    • Enhanced refresh token and JWT validation.
    • Optional login timing-attack hardening via PREVENT_LOGIN_TIMING_ATTACKS.
  • Bug Fixes

    • Improved malformed JWT and password hash error handling.

Review Change Stack

Models ship as `*Mixin` classes from `fastapi_fullauth.models.{sqlalchemy,sqlmodel}` —
bring your own `Base` / `SQLModel`. `FullAuthBase` and the concrete `*Model` /
`*Record` classes are gone, and apps no longer end up with the library's
tables on their `Base.metadata`. Adapter constructors take every concrete
model as a keyword arg (`user_model`, `refresh_token_model`, optional
`role_model`, `user_role_model`, `permission_model`, `role_permission_model`,
`oauth_account_model`, `passkey_model`). Adapter modules flattened to
`adapters/sqlalchemy.py` and `adapters/sqlmodel.py`. `fastapi_fullauth.migrations`
removed — your own `Base.metadata` is the source of truth.

Audit hardening:
- `/auth/refresh` now requires the refresh-token row to exist in DB before
  issuing a new pair; a signed JWT without a backing row is rejected.
- New `PREVENT_LOGIN_TIMING_ATTACKS` (default off): when on, login runs a
  dummy argon2 verify on unknown-user / no-password paths.
- `CSRFMiddleware(secret=...)` is required and validated (>= 32 chars);
  the env-pulling fallback is gone.
- `UUID(payload.sub)` wrapped at every call site (`current_user`,
  `/refresh`, `verify_email`, `reset_password`, `logout` hook) — bad sub
  -> 401 / TokenError instead of 500.
- `verify_password` catches argon2 `InvalidHashError` and bcrypt
  `ValueError` on malformed stored hashes.
- Passkey `/authenticate/begin` always returns a list `allowCredentials`
  when an email is supplied, so unknown emails can't be enumerated by
  response shape.
- `SECRET_KEY` rejected when shorter than 32 chars.
- `ALGORITHM` constrained to `Literal["HS256", "HS384", "HS512"]`.
- Rate limits added on `/verify-email/{request,confirm}`,
  `/password-reset/confirm`, `/oauth/{provider}/callback`, and
  `/passkeys/authenticate/complete`.

Config surface:
- New `BACKEND` and `ORIGINS` global settings propagate to per-feature
  `*_BACKEND` and `PASSKEY_ORIGINS`. Per-feature overrides still win.
- Removed: `INCLUDE_USER_IN_LOGIN` (login/OAuth/passkey always include
  `user`), `CSRF_ENABLED`, `INJECT_SECURITY_HEADERS`, `RATE_LIMIT_ENABLED`,
  `ACCOUNT_LOCKED_EXCEPTION` (dead since 0.9.0 anti-enum change).

Middleware is no longer auto-wired. `init_app()` only mounts routers.
Import `SecurityHeadersMiddleware`, `CSRFMiddleware`, `RateLimitMiddleware`
from `fastapi_fullauth.middleware` and `app.add_middleware(...)` them
yourself. `init_middleware()` and the `auto_middleware` kwarg are removed.
`create_rate_limiter()` is exported from `fastapi_fullauth.protection` for
Redis-backed manual wiring.

`exclude_routers` renamed to `include_routers` on `init_app()` —
allowlist instead of denylist. `include_routers=None` (default) keeps
the previous "everything" behaviour.

Layout / naming cleanup: `router/` -> `routers/`, `_models.py` ->
`_schemas.py`, `dependencies/require_role.py` -> `dependencies/rbac.py`,
`flows/update_profile.py` -> `flows/profile.py`, `_get_fullauth` ->
`get_fullauth`, `core/redis_blacklist.py` folded into
`core/blacklist.py` with parallel `InMemoryTokenBlacklist` /
`RedisTokenBlacklist` naming. `RateLimitMiddleware` moved from
`protection/` to `middleware/`.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: aeac9e7f-ece3-40a5-a973-f4b45f170606

📥 Commits

Reviewing files that changed from the base of the PR and between 25e02f9 and 6fdc54b.

📒 Files selected for processing (97)
  • CHANGELOG.md
  • README.md
  • docs/adapters/sqlalchemy.md
  • docs/adapters/sqlmodel.md
  • docs/api-reference.md
  • docs/configuration.md
  • docs/getting-started.md
  • docs/index.md
  • docs/llms-full.txt
  • docs/llms.txt
  • docs/migrations.md
  • docs/oauth.md
  • docs/security/middleware.md
  • docs/security/rate-limiting.md
  • examples/sqlalchemy_app/auth.py
  • examples/sqlalchemy_app/main.py
  • examples/sqlalchemy_app/models.py
  • examples/sqlmodel_app/auth.py
  • examples/sqlmodel_app/main.py
  • examples/sqlmodel_app/models.py
  • fastapi_fullauth/.agents/skills/fastapi-fullauth/SKILL.md
  • fastapi_fullauth/.agents/skills/fastapi-fullauth/references/adapters.md
  • fastapi_fullauth/.agents/skills/fastapi-fullauth/references/api-reference.md
  • fastapi_fullauth/.agents/skills/fastapi-fullauth/references/composable-design.md
  • fastapi_fullauth/.agents/skills/fastapi-fullauth/references/getting-started.md
  • fastapi_fullauth/.agents/skills/fastapi-fullauth/references/migrations.md
  • fastapi_fullauth/.agents/skills/fastapi-fullauth/references/oauth.md
  • fastapi_fullauth/.agents/skills/fastapi-fullauth/references/passkeys.md
  • fastapi_fullauth/.agents/skills/fastapi-fullauth/references/production.md
  • fastapi_fullauth/.agents/skills/fastapi-fullauth/references/rbac.md
  • fastapi_fullauth/.agents/skills/fastapi-fullauth/references/testing.md
  • fastapi_fullauth/__init__.py
  • fastapi_fullauth/adapters/__init__.py
  • fastapi_fullauth/adapters/sqlalchemy.py
  • fastapi_fullauth/adapters/sqlalchemy/__init__.py
  • fastapi_fullauth/adapters/sqlalchemy/models/__init__.py
  • fastapi_fullauth/adapters/sqlmodel.py
  • fastapi_fullauth/adapters/sqlmodel/__init__.py
  • fastapi_fullauth/adapters/sqlmodel/models/__init__.py
  • fastapi_fullauth/config.py
  • fastapi_fullauth/core/blacklist.py
  • fastapi_fullauth/core/crypto.py
  • fastapi_fullauth/core/redis_blacklist.py
  • fastapi_fullauth/core/tokens.py
  • fastapi_fullauth/dependencies/__init__.py
  • fastapi_fullauth/dependencies/current_user.py
  • fastapi_fullauth/dependencies/rbac.py
  • fastapi_fullauth/exceptions.py
  • fastapi_fullauth/flows/__init__.py
  • fastapi_fullauth/flows/email_verify.py
  • fastapi_fullauth/flows/login.py
  • fastapi_fullauth/flows/passkey.py
  • fastapi_fullauth/flows/password_reset.py
  • fastapi_fullauth/flows/profile.py
  • fastapi_fullauth/fullauth.py
  • fastapi_fullauth/middleware/__init__.py
  • fastapi_fullauth/middleware/csrf.py
  • fastapi_fullauth/middleware/ratelimit.py
  • fastapi_fullauth/migrations.py
  • fastapi_fullauth/models/__init__.py
  • fastapi_fullauth/models/sqlalchemy/__init__.py
  • fastapi_fullauth/models/sqlalchemy/base.py
  • fastapi_fullauth/models/sqlalchemy/oauth.py
  • fastapi_fullauth/models/sqlalchemy/passkey.py
  • fastapi_fullauth/models/sqlalchemy/permission.py
  • fastapi_fullauth/models/sqlalchemy/role.py
  • fastapi_fullauth/models/sqlmodel/__init__.py
  • fastapi_fullauth/models/sqlmodel/base.py
  • fastapi_fullauth/models/sqlmodel/oauth.py
  • fastapi_fullauth/models/sqlmodel/passkey.py
  • fastapi_fullauth/models/sqlmodel/permission.py
  • fastapi_fullauth/models/sqlmodel/role.py
  • fastapi_fullauth/protection/__init__.py
  • fastapi_fullauth/protection/ratelimit.py
  • fastapi_fullauth/router/__init__.py
  • fastapi_fullauth/routers/__init__.py
  • fastapi_fullauth/routers/_schemas.py
  • fastapi_fullauth/routers/admin.py
  • fastapi_fullauth/routers/auth.py
  • fastapi_fullauth/routers/oauth.py
  • fastapi_fullauth/routers/passkey.py
  • fastapi_fullauth/routers/profile.py
  • fastapi_fullauth/routers/verify.py
  • pyproject.toml
  • tests/conftest.py
  • tests/test_auth.py
  • tests/test_config.py
  • tests/test_hooks.py
  • tests/test_oauth.py
  • tests/test_passkey.py
  • tests/test_polish.py
  • tests/test_profile.py
  • tests/test_rbac.py
  • tests/test_security.py
  • tests/test_sqlalchemy_adapter.py
  • tests/test_sqlmodel_adapter.py
  • tests/test_tokens.py

📝 Walkthrough

Walkthrough

Refactors to mixin-based models and injected adapter models, updates routers to include_routers, removes auto-wired middleware, adds config validators and security hardening, consolidates blacklist backends, and updates docs, examples, and tests to the new v0.10.0 contracts.

Changes

v0.10.0 Architecture and API Refactor

Layer / File(s) Summary
Model mixins and adapter injection
fastapi_fullauth/models/*, fastapi_fullauth/adapters/*, examples/*, tests/*
Introduce SQLAlchemy/SQLModel mixins; adapters now require concrete models via kwargs; examples and tests define local tables and pass them into adapters.
Router and middleware behavior
fastapi_fullauth/fullauth.py, fastapi_fullauth/routers/*, fastapi_fullauth/middleware/*, docs/*
init_app(include_routers=...) selects routers; middleware is not auto-wired; CSRF requires explicit secret; rate-limit middleware moved to middleware package.
Security, tokens, and config
fastapi_fullauth/core/*, fastapi_fullauth/config.py, flows/, dependencies/
Add centralized blacklist backends; tighten UUID parsing, timing-attack option, secret key length, backend/origin propagation and Redis URL validation.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant FullAuth
  participant AuthRouters
  participant SQLModelAdapter
  Client->>AuthRouters: Login/OAuth/Passkey
  AuthRouters->>FullAuth: Delegate flow
  FullAuth->>SQLModelAdapter: Use injected models (User/Refresh/OAuth/Passkey)
  SQLModelAdapter-->>FullAuth: Entities/updates
  FullAuth-->>Client: Responses (user always included on success)
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Poem

In moonlit code, the mixins hop,
Adapters sip from model crops.
Routers weave an allow-list trail,
Middleware waits—no auto sail.
Tokens blacklist, secrets grow,
A rabbit bows: v0.10—let’s go! 🐇✨

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/v0.10.0-mixin-pivot

@mdfarhankc mdfarhankc merged commit 0f4af1b into main May 18, 2026
6 of 7 checks passed
@mdfarhankc mdfarhankc deleted the feat/v0.10.0-mixin-pivot branch May 18, 2026 14:33
@coderabbitai coderabbitai Bot mentioned this pull request May 20, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant