fastapi-fullauth 0.4.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastapi_fullauth-0.5.0/.github/workflows/docs.yml +26 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/.gitignore +6 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/CHANGELOG.md +23 -0
- fastapi_fullauth-0.5.0/PKG-INFO +281 -0
- fastapi_fullauth-0.5.0/README.md +235 -0
- fastapi_fullauth-0.5.0/docs/adapters/index.md +49 -0
- fastapi_fullauth-0.5.0/docs/adapters/memory.md +32 -0
- fastapi_fullauth-0.5.0/docs/adapters/sqlalchemy.md +76 -0
- fastapi_fullauth-0.5.0/docs/adapters/sqlmodel.md +128 -0
- fastapi_fullauth-0.5.0/docs/api-reference.md +168 -0
- fastapi_fullauth-0.5.0/docs/auth/custom-claims.md +53 -0
- fastapi_fullauth-0.5.0/docs/auth/dependencies.md +125 -0
- fastapi_fullauth-0.5.0/docs/auth/hooks.md +94 -0
- fastapi_fullauth-0.5.0/docs/auth/passwords.md +62 -0
- fastapi_fullauth-0.5.0/docs/configuration.md +135 -0
- fastapi_fullauth-0.5.0/docs/getting-started.md +154 -0
- fastapi_fullauth-0.5.0/docs/index.md +117 -0
- fastapi_fullauth-0.5.0/docs/migrations.md +102 -0
- fastapi_fullauth-0.5.0/docs/oauth.md +166 -0
- fastapi_fullauth-0.5.0/docs/security/middleware.md +94 -0
- fastapi_fullauth-0.5.0/docs/security/rate-limiting.md +116 -0
- fastapi_fullauth-0.5.0/docs/stylesheets/home.css +90 -0
- fastapi_fullauth-0.5.0/examples/sqlalchemy_app/auth.py +28 -0
- fastapi_fullauth-0.5.0/examples/sqlalchemy_app/config.py +5 -0
- fastapi_fullauth-0.5.0/examples/sqlalchemy_app/main.py +26 -0
- fastapi_fullauth-0.5.0/examples/sqlalchemy_app/models.py +19 -0
- fastapi_fullauth-0.5.0/examples/sqlmodel_app/routes.py +15 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/__init__.py +1 -1
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/sqlmodel/__init__.py +2 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/sqlmodel/adapter.py +4 -2
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/config.py +1 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/core/tokens.py +12 -1
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/email_verify.py +7 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/login.py +9 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/oauth.py +18 -1
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/password_reset.py +9 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/register.py +7 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/fullauth.py +9 -1
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/middleware/csrf.py +6 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/oauth/github.py +11 -3
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/oauth/google.py +9 -2
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/protection/lockout.py +8 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/protection/ratelimit.py +9 -1
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/router/auth.py +42 -3
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/router/oauth.py +6 -2
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/utils.py +17 -0
- fastapi_fullauth-0.5.0/mkdocs.yml +74 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/pyproject.toml +3 -2
- fastapi_fullauth-0.5.0/tests/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_middleware.py +80 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_oauth.py +18 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_refresh_tokens.py +53 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/uv.lock +435 -1
- fastapi_fullauth-0.4.0/PKG-INFO +0 -307
- fastapi_fullauth-0.4.0/README.md +0 -261
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/.github/workflows/ci.yml +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/.github/workflows/publish.yml +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/.python-version +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/LICENSE +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/memory_app/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/memory_app/auth.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/memory_app/main.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/memory_app/routes.py +0 -0
- {fastapi_fullauth-0.4.0/examples/sqlmodel_app → fastapi_fullauth-0.5.0/examples/sqlalchemy_app}/__init__.py +0 -0
- {fastapi_fullauth-0.4.0/examples/sqlmodel_app → fastapi_fullauth-0.5.0/examples/sqlalchemy_app}/routes.py +0 -0
- {fastapi_fullauth-0.4.0/fastapi_fullauth/rbac → fastapi_fullauth-0.5.0/examples/sqlmodel_app}/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/sqlmodel_app/auth.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/sqlmodel_app/config.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/sqlmodel_app/main.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/sqlmodel_app/models.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/base.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/memory.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/sqlalchemy/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/sqlalchemy/adapter.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/sqlalchemy/models.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/sqlmodel/models.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/backends/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/backends/base.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/backends/bearer.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/backends/cookie.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/core/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/core/crypto.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/core/redis_blacklist.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/dependencies/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/dependencies/current_user.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/dependencies/require_role.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/exceptions.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/logout.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/hooks.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/middleware/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/middleware/ratelimit.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/middleware/security_headers.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/migrations/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/migrations/helpers.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/oauth/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/oauth/base.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/protection/__init__.py +0 -0
- {fastapi_fullauth-0.4.0/fastapi_fullauth/router → fastapi_fullauth-0.5.0/fastapi_fullauth/rbac}/__init__.py +0 -0
- {fastapi_fullauth-0.4.0/tests → fastapi_fullauth-0.5.0/fastapi_fullauth/router}/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/types.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/validators.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/conftest.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_auth_flows.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_crypto.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_customization.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_dx_improvements.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_email_verify.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_lockout.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_new_endpoints.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_roles.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_tokens.py +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- "docs/**"
|
|
8
|
+
- "mkdocs.yml"
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
deploy:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.12"
|
|
23
|
+
|
|
24
|
+
- run: pip install mkdocs-material
|
|
25
|
+
|
|
26
|
+
- run: mkdocs gh-deploy --force
|
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Structured logging** across all auth flows, security middleware, and OAuth — failed logins, account lockouts, token reuse, CSRF violations, rate limit hits, role changes, and account deletions are all logged via `logging.getLogger("fastapi_fullauth.*")`
|
|
8
|
+
- **Documentation site** — MkDocs with Material theme, auto-deployed to GitHub Pages via CI
|
|
9
|
+
- **Proxy-aware rate limiting** — new `TRUSTED_PROXY_HEADERS` config to read real client IPs from `X-Forwarded-For` and similar headers
|
|
10
|
+
- **SQLAlchemy example app** (`examples/sqlalchemy_app/`)
|
|
11
|
+
- **`update_user` field validation** — rejects unknown fields with 422 instead of passing them to the DB
|
|
12
|
+
- SQLModel adapter now accepts both SQLModel's and SQLAlchemy's `AsyncSession`
|
|
13
|
+
- `OAuthAccountRecord` exported from `fastapi_fullauth.adapters.sqlmodel`
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **OAuth state token TTL was ignored** — `OAUTH_STATE_EXPIRE_SECONDS` config had no effect; state tokens used `ACCESS_TOKEN_EXPIRE_MINUTES` (30 min) instead of the configured 5 min
|
|
18
|
+
- **Refresh token reuse detection race condition** — two concurrent `/refresh` requests could both succeed before either revoked the token; added explicit blacklist check before issuing new tokens
|
|
19
|
+
- **OAuth error messages leaked provider internals** — raw API responses from Google/GitHub were exposed in HTTP error details; now logged internally and replaced with generic messages
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- README rewritten with centered hero layout, badges, and documentation links
|
|
24
|
+
- Documentation URL updated in `pyproject.toml` to point to GitHub Pages
|
|
25
|
+
|
|
3
26
|
## 0.4.0
|
|
4
27
|
|
|
5
28
|
### Added
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fastapi-fullauth
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Production-grade, async-native authentication and authorization library for FastAPI
|
|
5
|
+
Project-URL: Homepage, https://github.com/mdfarhankc/fastapi-fullauth
|
|
6
|
+
Project-URL: Documentation, https://mdfarhankc.github.io/fastapi-fullauth
|
|
7
|
+
Project-URL: Repository, https://github.com/mdfarhankc/fastapi-fullauth
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: argon2,authentication,authorization,fastapi,jwt,security
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Framework :: FastAPI
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Security
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: argon2-cffi>=23.0
|
|
24
|
+
Requires-Dist: fastapi>=0.110
|
|
25
|
+
Requires-Dist: pydantic-settings>=2.0
|
|
26
|
+
Requires-Dist: pydantic[email]>=2.0
|
|
27
|
+
Requires-Dist: pyjwt>=2.8
|
|
28
|
+
Requires-Dist: uuid-utils>=0.14.1
|
|
29
|
+
Provides-Extra: all
|
|
30
|
+
Requires-Dist: alembic>=1.13; extra == 'all'
|
|
31
|
+
Requires-Dist: httpx>=0.25; extra == 'all'
|
|
32
|
+
Requires-Dist: redis>=5.0; extra == 'all'
|
|
33
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0; extra == 'all'
|
|
34
|
+
Requires-Dist: sqlmodel>=0.0.16; extra == 'all'
|
|
35
|
+
Provides-Extra: oauth
|
|
36
|
+
Requires-Dist: httpx>=0.25; extra == 'oauth'
|
|
37
|
+
Provides-Extra: redis
|
|
38
|
+
Requires-Dist: redis>=5.0; extra == 'redis'
|
|
39
|
+
Provides-Extra: sqlalchemy
|
|
40
|
+
Requires-Dist: alembic>=1.13; extra == 'sqlalchemy'
|
|
41
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0; extra == 'sqlalchemy'
|
|
42
|
+
Provides-Extra: sqlmodel
|
|
43
|
+
Requires-Dist: alembic>=1.13; extra == 'sqlmodel'
|
|
44
|
+
Requires-Dist: sqlmodel>=0.0.16; extra == 'sqlmodel'
|
|
45
|
+
Description-Content-Type: text/markdown
|
|
46
|
+
|
|
47
|
+
<p align="center">
|
|
48
|
+
<img src="https://img.icons8.com/fluency/96/shield.png" alt="FastAPI FullAuth" width="96" height="96">
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<h1 align="center">FastAPI FullAuth</h1>
|
|
52
|
+
|
|
53
|
+
<p align="center">
|
|
54
|
+
<em>Production-grade, async-native authentication and authorization for FastAPI.</em>
|
|
55
|
+
</p>
|
|
56
|
+
|
|
57
|
+
<p align="center">
|
|
58
|
+
<a href="https://pypi.org/project/fastapi-fullauth/"><img src="https://img.shields.io/pypi/v/fastapi-fullauth?color=009688&label=pypi" alt="PyPI"></a>
|
|
59
|
+
<a href="https://pypi.org/project/fastapi-fullauth/"><img src="https://img.shields.io/pypi/pyversions/fastapi-fullauth?color=009688" alt="Python"></a>
|
|
60
|
+
<a href="https://github.com/mdfarhankc/fastapi-fullauth/actions/workflows/ci.yml"><img src="https://github.com/mdfarhankc/fastapi-fullauth/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
61
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-009688" alt="License"></a>
|
|
62
|
+
<a href="https://mdfarhankc.github.io/fastapi-fullauth"><img src="https://img.shields.io/badge/docs-mdfarhankc.github.io-009688" alt="Docs"></a>
|
|
63
|
+
</p>
|
|
64
|
+
|
|
65
|
+
<p align="center">
|
|
66
|
+
<strong>Documentation</strong>: <a href="https://mdfarhankc.github.io/fastapi-fullauth">https://mdfarhankc.github.io/fastapi-fullauth</a>
|
|
67
|
+
<br>
|
|
68
|
+
<strong>Source Code</strong>: <a href="https://github.com/mdfarhankc/fastapi-fullauth">https://github.com/mdfarhankc/fastapi-fullauth</a>
|
|
69
|
+
</p>
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
Add a complete authentication and authorization system to your **FastAPI** project. FastAPI FullAuth is designed to be production-ready, async-native, and pluggable — handling JWT tokens, refresh rotation, password hashing, email verification, OAuth2 social login, and role-based access out of the box.
|
|
74
|
+
|
|
75
|
+
## Features
|
|
76
|
+
|
|
77
|
+
- **JWT access + refresh tokens** with configurable expiry
|
|
78
|
+
- **Refresh token rotation** with reuse detection — revokes entire session family on replay
|
|
79
|
+
- **Password hashing** via Argon2id (default) or bcrypt, with transparent rehashing
|
|
80
|
+
- **Email verification** and **password reset** flows with event hooks
|
|
81
|
+
- **OAuth2 social login** — Google and GitHub, with multi-redirect-URI support
|
|
82
|
+
- **Role-based access control** — `CurrentUser`, `VerifiedUser`, `SuperUser`, `require_role()`
|
|
83
|
+
- **Rate limiting** — per-route auth limits + global middleware (memory or Redis)
|
|
84
|
+
- **CSRF protection** and **security headers** middleware, auto-wired
|
|
85
|
+
- **Pluggable adapters** — SQLModel, SQLAlchemy, or in-memory
|
|
86
|
+
- **Auto-derived schemas** — custom user fields picked up automatically
|
|
87
|
+
- **Event hooks** — `after_register`, `after_login`, `send_verification_email`, etc.
|
|
88
|
+
- **Custom JWT claims** — embed app-specific data in tokens
|
|
89
|
+
- **Structured logging** — all auth events, security violations, and failures logged
|
|
90
|
+
- **Redis support** — token blacklist and rate limiter backends
|
|
91
|
+
- **Python 3.10 – 3.14** supported
|
|
92
|
+
|
|
93
|
+
## Installation
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pip install fastapi-fullauth
|
|
97
|
+
|
|
98
|
+
# with an ORM adapter
|
|
99
|
+
pip install fastapi-fullauth[sqlmodel]
|
|
100
|
+
pip install fastapi-fullauth[sqlalchemy]
|
|
101
|
+
|
|
102
|
+
# with Redis for token blacklisting
|
|
103
|
+
pip install fastapi-fullauth[sqlmodel,redis]
|
|
104
|
+
|
|
105
|
+
# with OAuth2 social login
|
|
106
|
+
pip install fastapi-fullauth[sqlmodel,oauth]
|
|
107
|
+
|
|
108
|
+
# everything
|
|
109
|
+
pip install fastapi-fullauth[all]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Quick start
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from fastapi import FastAPI
|
|
116
|
+
from fastapi_fullauth import FullAuth
|
|
117
|
+
from fastapi_fullauth.adapters.memory import InMemoryAdapter
|
|
118
|
+
|
|
119
|
+
app = FastAPI()
|
|
120
|
+
|
|
121
|
+
fullauth = FullAuth(
|
|
122
|
+
secret_key="your-secret-key",
|
|
123
|
+
adapter=InMemoryAdapter(),
|
|
124
|
+
)
|
|
125
|
+
fullauth.init_app(app)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
That's it — 15+ auth routes are registered under `/api/v1/auth/` automatically.
|
|
129
|
+
|
|
130
|
+
Omit `secret_key` in dev and a random one is generated (tokens won't survive restarts).
|
|
131
|
+
|
|
132
|
+
## Routes
|
|
133
|
+
|
|
134
|
+
| Method | Path | Description |
|
|
135
|
+
|--------|------|-------------|
|
|
136
|
+
| `POST` | `/auth/register` | Create a new user |
|
|
137
|
+
| `POST` | `/auth/login` | Authenticate, get tokens |
|
|
138
|
+
| `POST` | `/auth/logout` | Blacklist token |
|
|
139
|
+
| `POST` | `/auth/refresh` | Rotate token pair |
|
|
140
|
+
| `GET` | `/auth/me` | Get current user |
|
|
141
|
+
| `GET` | `/auth/me/verified` | Verified users only |
|
|
142
|
+
| `PATCH` | `/auth/me` | Update profile |
|
|
143
|
+
| `DELETE` | `/auth/me` | Delete account |
|
|
144
|
+
| `POST` | `/auth/change-password` | Change password |
|
|
145
|
+
| `POST` | `/auth/verify-email/request` | Request verification email |
|
|
146
|
+
| `POST` | `/auth/verify-email/confirm` | Confirm email |
|
|
147
|
+
| `POST` | `/auth/password-reset/request` | Request password reset |
|
|
148
|
+
| `POST` | `/auth/password-reset/confirm` | Reset password |
|
|
149
|
+
| `POST` | `/auth/admin/assign-role` | Assign role (superuser) |
|
|
150
|
+
| `POST` | `/auth/admin/remove-role` | Remove role (superuser) |
|
|
151
|
+
|
|
152
|
+
With OAuth enabled, additional routes are registered under `/auth/oauth/`. All routes are prefixed with `/api/v1` by default.
|
|
153
|
+
|
|
154
|
+
## Custom user fields
|
|
155
|
+
|
|
156
|
+
Define your model — schemas are auto-derived:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from sqlmodel import Field, Relationship
|
|
160
|
+
from fastapi_fullauth.adapters.sqlmodel import (
|
|
161
|
+
UserBase, Role, UserRoleLink, RefreshTokenRecord, SQLModelAdapter,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
class User(UserBase, table=True):
|
|
165
|
+
__tablename__ = "fullauth_users"
|
|
166
|
+
|
|
167
|
+
display_name: str = Field(default="", max_length=100)
|
|
168
|
+
phone: str = Field(default="", max_length=20)
|
|
169
|
+
|
|
170
|
+
roles: list[Role] = Relationship(link_model=UserRoleLink)
|
|
171
|
+
refresh_tokens: list[RefreshTokenRecord] = Relationship()
|
|
172
|
+
|
|
173
|
+
fullauth = FullAuth(
|
|
174
|
+
secret_key="...",
|
|
175
|
+
adapter=SQLModelAdapter(session_maker, user_model=User),
|
|
176
|
+
)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Registration and response schemas pick up `display_name` and `phone` automatically. No separate schema classes needed.
|
|
180
|
+
|
|
181
|
+
## Protected routes
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
from fastapi import Depends
|
|
185
|
+
from fastapi_fullauth.dependencies import CurrentUser, VerifiedUser, SuperUser, require_role
|
|
186
|
+
|
|
187
|
+
@app.get("/profile")
|
|
188
|
+
async def profile(user: CurrentUser):
|
|
189
|
+
return user
|
|
190
|
+
|
|
191
|
+
@app.get("/dashboard")
|
|
192
|
+
async def dashboard(user: VerifiedUser):
|
|
193
|
+
return {"email": user.email}
|
|
194
|
+
|
|
195
|
+
@app.delete("/admin/users/{id}")
|
|
196
|
+
async def delete_user(user: SuperUser):
|
|
197
|
+
...
|
|
198
|
+
|
|
199
|
+
@app.get("/editor")
|
|
200
|
+
async def editor_panel(user=Depends(require_role("editor"))):
|
|
201
|
+
...
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## OAuth2 social login
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
fullauth = FullAuth(
|
|
208
|
+
secret_key="...",
|
|
209
|
+
adapter=adapter,
|
|
210
|
+
oauth_providers={
|
|
211
|
+
"google": {
|
|
212
|
+
"client_id": "your-google-client-id",
|
|
213
|
+
"client_secret": "your-google-secret",
|
|
214
|
+
"redirect_uris": [
|
|
215
|
+
"http://localhost:3000/auth/callback",
|
|
216
|
+
"https://myapp.com/auth/callback",
|
|
217
|
+
],
|
|
218
|
+
},
|
|
219
|
+
"github": {
|
|
220
|
+
"client_id": "your-github-client-id",
|
|
221
|
+
"client_secret": "your-github-secret",
|
|
222
|
+
"redirect_uri": "http://localhost:3000/auth/callback",
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Requires `httpx`: `pip install fastapi-fullauth[oauth]`
|
|
229
|
+
|
|
230
|
+
## Event hooks
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
async def welcome(user):
|
|
234
|
+
await send_email(user.email, "Welcome!")
|
|
235
|
+
|
|
236
|
+
async def send_verify(email, token):
|
|
237
|
+
await send_email(email, f"Verify: https://myapp.com/verify?token={token}")
|
|
238
|
+
|
|
239
|
+
fullauth.hooks.on("after_register", welcome)
|
|
240
|
+
fullauth.hooks.on("send_verification_email", send_verify)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
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`
|
|
244
|
+
|
|
245
|
+
## Configuration
|
|
246
|
+
|
|
247
|
+
Pass inline kwargs or a config object. All options read from env vars with `FULLAUTH_` prefix.
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
fullauth = FullAuth(
|
|
251
|
+
secret_key="...",
|
|
252
|
+
adapter=adapter,
|
|
253
|
+
access_token_expire_minutes=60,
|
|
254
|
+
api_prefix="/api/v2",
|
|
255
|
+
login_field="username",
|
|
256
|
+
password_hash_algorithm="bcrypt",
|
|
257
|
+
blacklist_backend="redis",
|
|
258
|
+
redis_url="redis://localhost:6379/0",
|
|
259
|
+
rate_limit_enabled=True,
|
|
260
|
+
trusted_proxy_headers=["X-Forwarded-For"],
|
|
261
|
+
)
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
See [Configuration docs](https://mdfarhankc.github.io/fastapi-fullauth/configuration/) for all options.
|
|
265
|
+
|
|
266
|
+
## Development
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
git clone https://github.com/mdfarhankc/fastapi-fullauth.git
|
|
270
|
+
cd fastapi-fullauth
|
|
271
|
+
uv sync --dev --extra sqlalchemy --extra sqlmodel
|
|
272
|
+
uv run pytest tests/ -v
|
|
273
|
+
|
|
274
|
+
# run examples
|
|
275
|
+
uv run uvicorn examples.memory_app.main:app --reload
|
|
276
|
+
uv run uvicorn examples.sqlmodel_app.main:app --reload
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## License
|
|
280
|
+
|
|
281
|
+
MIT
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://img.icons8.com/fluency/96/shield.png" alt="FastAPI FullAuth" width="96" height="96">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">FastAPI FullAuth</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<em>Production-grade, async-native authentication and authorization for FastAPI.</em>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://pypi.org/project/fastapi-fullauth/"><img src="https://img.shields.io/pypi/v/fastapi-fullauth?color=009688&label=pypi" alt="PyPI"></a>
|
|
13
|
+
<a href="https://pypi.org/project/fastapi-fullauth/"><img src="https://img.shields.io/pypi/pyversions/fastapi-fullauth?color=009688" alt="Python"></a>
|
|
14
|
+
<a href="https://github.com/mdfarhankc/fastapi-fullauth/actions/workflows/ci.yml"><img src="https://github.com/mdfarhankc/fastapi-fullauth/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
15
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-009688" alt="License"></a>
|
|
16
|
+
<a href="https://mdfarhankc.github.io/fastapi-fullauth"><img src="https://img.shields.io/badge/docs-mdfarhankc.github.io-009688" alt="Docs"></a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<strong>Documentation</strong>: <a href="https://mdfarhankc.github.io/fastapi-fullauth">https://mdfarhankc.github.io/fastapi-fullauth</a>
|
|
21
|
+
<br>
|
|
22
|
+
<strong>Source Code</strong>: <a href="https://github.com/mdfarhankc/fastapi-fullauth">https://github.com/mdfarhankc/fastapi-fullauth</a>
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
Add a complete authentication and authorization system to your **FastAPI** project. FastAPI FullAuth is designed to be production-ready, async-native, and pluggable — handling JWT tokens, refresh rotation, password hashing, email verification, OAuth2 social login, and role-based access out of the box.
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
- **JWT access + refresh tokens** with configurable expiry
|
|
32
|
+
- **Refresh token rotation** with reuse detection — revokes entire session family on replay
|
|
33
|
+
- **Password hashing** via Argon2id (default) or bcrypt, with transparent rehashing
|
|
34
|
+
- **Email verification** and **password reset** flows with event hooks
|
|
35
|
+
- **OAuth2 social login** — Google and GitHub, with multi-redirect-URI support
|
|
36
|
+
- **Role-based access control** — `CurrentUser`, `VerifiedUser`, `SuperUser`, `require_role()`
|
|
37
|
+
- **Rate limiting** — per-route auth limits + global middleware (memory or Redis)
|
|
38
|
+
- **CSRF protection** and **security headers** middleware, auto-wired
|
|
39
|
+
- **Pluggable adapters** — SQLModel, SQLAlchemy, or in-memory
|
|
40
|
+
- **Auto-derived schemas** — custom user fields picked up automatically
|
|
41
|
+
- **Event hooks** — `after_register`, `after_login`, `send_verification_email`, etc.
|
|
42
|
+
- **Custom JWT claims** — embed app-specific data in tokens
|
|
43
|
+
- **Structured logging** — all auth events, security violations, and failures logged
|
|
44
|
+
- **Redis support** — token blacklist and rate limiter backends
|
|
45
|
+
- **Python 3.10 – 3.14** supported
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install fastapi-fullauth
|
|
51
|
+
|
|
52
|
+
# with an ORM adapter
|
|
53
|
+
pip install fastapi-fullauth[sqlmodel]
|
|
54
|
+
pip install fastapi-fullauth[sqlalchemy]
|
|
55
|
+
|
|
56
|
+
# with Redis for token blacklisting
|
|
57
|
+
pip install fastapi-fullauth[sqlmodel,redis]
|
|
58
|
+
|
|
59
|
+
# with OAuth2 social login
|
|
60
|
+
pip install fastapi-fullauth[sqlmodel,oauth]
|
|
61
|
+
|
|
62
|
+
# everything
|
|
63
|
+
pip install fastapi-fullauth[all]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from fastapi import FastAPI
|
|
70
|
+
from fastapi_fullauth import FullAuth
|
|
71
|
+
from fastapi_fullauth.adapters.memory import InMemoryAdapter
|
|
72
|
+
|
|
73
|
+
app = FastAPI()
|
|
74
|
+
|
|
75
|
+
fullauth = FullAuth(
|
|
76
|
+
secret_key="your-secret-key",
|
|
77
|
+
adapter=InMemoryAdapter(),
|
|
78
|
+
)
|
|
79
|
+
fullauth.init_app(app)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
That's it — 15+ auth routes are registered under `/api/v1/auth/` automatically.
|
|
83
|
+
|
|
84
|
+
Omit `secret_key` in dev and a random one is generated (tokens won't survive restarts).
|
|
85
|
+
|
|
86
|
+
## Routes
|
|
87
|
+
|
|
88
|
+
| Method | Path | Description |
|
|
89
|
+
|--------|------|-------------|
|
|
90
|
+
| `POST` | `/auth/register` | Create a new user |
|
|
91
|
+
| `POST` | `/auth/login` | Authenticate, get tokens |
|
|
92
|
+
| `POST` | `/auth/logout` | Blacklist token |
|
|
93
|
+
| `POST` | `/auth/refresh` | Rotate token pair |
|
|
94
|
+
| `GET` | `/auth/me` | Get current user |
|
|
95
|
+
| `GET` | `/auth/me/verified` | Verified users only |
|
|
96
|
+
| `PATCH` | `/auth/me` | Update profile |
|
|
97
|
+
| `DELETE` | `/auth/me` | Delete account |
|
|
98
|
+
| `POST` | `/auth/change-password` | Change password |
|
|
99
|
+
| `POST` | `/auth/verify-email/request` | Request verification email |
|
|
100
|
+
| `POST` | `/auth/verify-email/confirm` | Confirm email |
|
|
101
|
+
| `POST` | `/auth/password-reset/request` | Request password reset |
|
|
102
|
+
| `POST` | `/auth/password-reset/confirm` | Reset password |
|
|
103
|
+
| `POST` | `/auth/admin/assign-role` | Assign role (superuser) |
|
|
104
|
+
| `POST` | `/auth/admin/remove-role` | Remove role (superuser) |
|
|
105
|
+
|
|
106
|
+
With OAuth enabled, additional routes are registered under `/auth/oauth/`. All routes are prefixed with `/api/v1` by default.
|
|
107
|
+
|
|
108
|
+
## Custom user fields
|
|
109
|
+
|
|
110
|
+
Define your model — schemas are auto-derived:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from sqlmodel import Field, Relationship
|
|
114
|
+
from fastapi_fullauth.adapters.sqlmodel import (
|
|
115
|
+
UserBase, Role, UserRoleLink, RefreshTokenRecord, SQLModelAdapter,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
class User(UserBase, table=True):
|
|
119
|
+
__tablename__ = "fullauth_users"
|
|
120
|
+
|
|
121
|
+
display_name: str = Field(default="", max_length=100)
|
|
122
|
+
phone: str = Field(default="", max_length=20)
|
|
123
|
+
|
|
124
|
+
roles: list[Role] = Relationship(link_model=UserRoleLink)
|
|
125
|
+
refresh_tokens: list[RefreshTokenRecord] = Relationship()
|
|
126
|
+
|
|
127
|
+
fullauth = FullAuth(
|
|
128
|
+
secret_key="...",
|
|
129
|
+
adapter=SQLModelAdapter(session_maker, user_model=User),
|
|
130
|
+
)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Registration and response schemas pick up `display_name` and `phone` automatically. No separate schema classes needed.
|
|
134
|
+
|
|
135
|
+
## Protected routes
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from fastapi import Depends
|
|
139
|
+
from fastapi_fullauth.dependencies import CurrentUser, VerifiedUser, SuperUser, require_role
|
|
140
|
+
|
|
141
|
+
@app.get("/profile")
|
|
142
|
+
async def profile(user: CurrentUser):
|
|
143
|
+
return user
|
|
144
|
+
|
|
145
|
+
@app.get("/dashboard")
|
|
146
|
+
async def dashboard(user: VerifiedUser):
|
|
147
|
+
return {"email": user.email}
|
|
148
|
+
|
|
149
|
+
@app.delete("/admin/users/{id}")
|
|
150
|
+
async def delete_user(user: SuperUser):
|
|
151
|
+
...
|
|
152
|
+
|
|
153
|
+
@app.get("/editor")
|
|
154
|
+
async def editor_panel(user=Depends(require_role("editor"))):
|
|
155
|
+
...
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## OAuth2 social login
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
fullauth = FullAuth(
|
|
162
|
+
secret_key="...",
|
|
163
|
+
adapter=adapter,
|
|
164
|
+
oauth_providers={
|
|
165
|
+
"google": {
|
|
166
|
+
"client_id": "your-google-client-id",
|
|
167
|
+
"client_secret": "your-google-secret",
|
|
168
|
+
"redirect_uris": [
|
|
169
|
+
"http://localhost:3000/auth/callback",
|
|
170
|
+
"https://myapp.com/auth/callback",
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
"github": {
|
|
174
|
+
"client_id": "your-github-client-id",
|
|
175
|
+
"client_secret": "your-github-secret",
|
|
176
|
+
"redirect_uri": "http://localhost:3000/auth/callback",
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Requires `httpx`: `pip install fastapi-fullauth[oauth]`
|
|
183
|
+
|
|
184
|
+
## Event hooks
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
async def welcome(user):
|
|
188
|
+
await send_email(user.email, "Welcome!")
|
|
189
|
+
|
|
190
|
+
async def send_verify(email, token):
|
|
191
|
+
await send_email(email, f"Verify: https://myapp.com/verify?token={token}")
|
|
192
|
+
|
|
193
|
+
fullauth.hooks.on("after_register", welcome)
|
|
194
|
+
fullauth.hooks.on("send_verification_email", send_verify)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
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`
|
|
198
|
+
|
|
199
|
+
## Configuration
|
|
200
|
+
|
|
201
|
+
Pass inline kwargs or a config object. All options read from env vars with `FULLAUTH_` prefix.
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
fullauth = FullAuth(
|
|
205
|
+
secret_key="...",
|
|
206
|
+
adapter=adapter,
|
|
207
|
+
access_token_expire_minutes=60,
|
|
208
|
+
api_prefix="/api/v2",
|
|
209
|
+
login_field="username",
|
|
210
|
+
password_hash_algorithm="bcrypt",
|
|
211
|
+
blacklist_backend="redis",
|
|
212
|
+
redis_url="redis://localhost:6379/0",
|
|
213
|
+
rate_limit_enabled=True,
|
|
214
|
+
trusted_proxy_headers=["X-Forwarded-For"],
|
|
215
|
+
)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
See [Configuration docs](https://mdfarhankc.github.io/fastapi-fullauth/configuration/) for all options.
|
|
219
|
+
|
|
220
|
+
## Development
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
git clone https://github.com/mdfarhankc/fastapi-fullauth.git
|
|
224
|
+
cd fastapi-fullauth
|
|
225
|
+
uv sync --dev --extra sqlalchemy --extra sqlmodel
|
|
226
|
+
uv run pytest tests/ -v
|
|
227
|
+
|
|
228
|
+
# run examples
|
|
229
|
+
uv run uvicorn examples.memory_app.main:app --reload
|
|
230
|
+
uv run uvicorn examples.sqlmodel_app.main:app --reload
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## License
|
|
234
|
+
|
|
235
|
+
MIT
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Adapters
|
|
2
|
+
|
|
3
|
+
Adapters are the database layer for fastapi-fullauth. They implement `AbstractUserAdapter`, which defines how users, refresh tokens, roles, and OAuth accounts are stored and retrieved.
|
|
4
|
+
|
|
5
|
+
## Available adapters
|
|
6
|
+
|
|
7
|
+
| Adapter | Backend | Install |
|
|
8
|
+
|---------|---------|---------|
|
|
9
|
+
| [SQLModel](sqlmodel.md) | Any SQLAlchemy-supported DB | `pip install fastapi-fullauth[sqlmodel]` |
|
|
10
|
+
| [SQLAlchemy](sqlalchemy.md) | Any SQLAlchemy-supported DB | `pip install fastapi-fullauth[sqlalchemy]` |
|
|
11
|
+
| [In-Memory](memory.md) | Python dicts | Included (no extras) |
|
|
12
|
+
|
|
13
|
+
## Choosing an adapter
|
|
14
|
+
|
|
15
|
+
- **SQLModel** — recommended for most projects. Clean model definitions, good type support.
|
|
16
|
+
- **SQLAlchemy** — use if your project already uses SQLAlchemy's declarative base.
|
|
17
|
+
- **In-Memory** — for testing and prototyping only. Data is lost on restart.
|
|
18
|
+
|
|
19
|
+
## Custom adapters
|
|
20
|
+
|
|
21
|
+
You can implement your own adapter for any database by subclassing `AbstractUserAdapter`:
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from fastapi_fullauth.adapters.base import AbstractUserAdapter
|
|
25
|
+
from fastapi_fullauth.types import CreateUserSchema, RefreshToken, UserSchema
|
|
26
|
+
|
|
27
|
+
class MongoAdapter(AbstractUserAdapter):
|
|
28
|
+
async def get_user_by_id(self, user_id: str) -> UserSchema | None:
|
|
29
|
+
...
|
|
30
|
+
|
|
31
|
+
async def get_user_by_email(self, email: str) -> UserSchema | None:
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
async def create_user(self, data: CreateUserSchema, hashed_password: str) -> UserSchema:
|
|
35
|
+
...
|
|
36
|
+
|
|
37
|
+
# ... implement all abstract methods
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
See the [source of AbstractUserAdapter](https://github.com/mdfarhankc/fastapi-fullauth/blob/main/fastapi_fullauth/adapters/base.py) for the full interface.
|
|
41
|
+
|
|
42
|
+
## Auto-derived schemas
|
|
43
|
+
|
|
44
|
+
All adapters support automatic schema derivation. When you add custom fields to your user model, fastapi-fullauth detects them and includes them in:
|
|
45
|
+
|
|
46
|
+
- **Registration schema** — extra fields appear in `POST /auth/register`
|
|
47
|
+
- **User response schema** — extra fields appear in `GET /auth/me` and other user responses
|
|
48
|
+
|
|
49
|
+
No need to create separate Pydantic models. You can still pass explicit `user_schema` or `create_user_schema` to `SQLModelAdapter` / `FullAuth` if you want full control.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# In-Memory Adapter
|
|
2
|
+
|
|
3
|
+
A simple adapter that stores everything in Python dictionaries. Useful for testing and quick prototyping.
|
|
4
|
+
|
|
5
|
+
!!! warning
|
|
6
|
+
All data is lost when the process restarts. Do not use in production.
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
from fastapi_fullauth import FullAuth
|
|
12
|
+
from fastapi_fullauth.adapters.memory import InMemoryAdapter
|
|
13
|
+
|
|
14
|
+
fullauth = FullAuth(
|
|
15
|
+
secret_key="dev-secret",
|
|
16
|
+
adapter=InMemoryAdapter(),
|
|
17
|
+
)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
No database, no migrations, no setup. Just works.
|
|
21
|
+
|
|
22
|
+
## When to use
|
|
23
|
+
|
|
24
|
+
- **Unit tests** — all fastapi-fullauth tests use this adapter
|
|
25
|
+
- **Prototyping** — try out the library without setting up a database
|
|
26
|
+
- **Demos** — run the `examples/memory_app` example
|
|
27
|
+
|
|
28
|
+
## Limitations
|
|
29
|
+
|
|
30
|
+
- No persistence across restarts
|
|
31
|
+
- No concurrent access safety (single-process only)
|
|
32
|
+
- OAuth account methods are supported but also in-memory
|