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.
Files changed (113) hide show
  1. fastapi_fullauth-0.5.0/.github/workflows/docs.yml +26 -0
  2. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/.gitignore +6 -0
  3. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/CHANGELOG.md +23 -0
  4. fastapi_fullauth-0.5.0/PKG-INFO +281 -0
  5. fastapi_fullauth-0.5.0/README.md +235 -0
  6. fastapi_fullauth-0.5.0/docs/adapters/index.md +49 -0
  7. fastapi_fullauth-0.5.0/docs/adapters/memory.md +32 -0
  8. fastapi_fullauth-0.5.0/docs/adapters/sqlalchemy.md +76 -0
  9. fastapi_fullauth-0.5.0/docs/adapters/sqlmodel.md +128 -0
  10. fastapi_fullauth-0.5.0/docs/api-reference.md +168 -0
  11. fastapi_fullauth-0.5.0/docs/auth/custom-claims.md +53 -0
  12. fastapi_fullauth-0.5.0/docs/auth/dependencies.md +125 -0
  13. fastapi_fullauth-0.5.0/docs/auth/hooks.md +94 -0
  14. fastapi_fullauth-0.5.0/docs/auth/passwords.md +62 -0
  15. fastapi_fullauth-0.5.0/docs/configuration.md +135 -0
  16. fastapi_fullauth-0.5.0/docs/getting-started.md +154 -0
  17. fastapi_fullauth-0.5.0/docs/index.md +117 -0
  18. fastapi_fullauth-0.5.0/docs/migrations.md +102 -0
  19. fastapi_fullauth-0.5.0/docs/oauth.md +166 -0
  20. fastapi_fullauth-0.5.0/docs/security/middleware.md +94 -0
  21. fastapi_fullauth-0.5.0/docs/security/rate-limiting.md +116 -0
  22. fastapi_fullauth-0.5.0/docs/stylesheets/home.css +90 -0
  23. fastapi_fullauth-0.5.0/examples/sqlalchemy_app/auth.py +28 -0
  24. fastapi_fullauth-0.5.0/examples/sqlalchemy_app/config.py +5 -0
  25. fastapi_fullauth-0.5.0/examples/sqlalchemy_app/main.py +26 -0
  26. fastapi_fullauth-0.5.0/examples/sqlalchemy_app/models.py +19 -0
  27. fastapi_fullauth-0.5.0/examples/sqlmodel_app/routes.py +15 -0
  28. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/__init__.py +1 -1
  29. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/sqlmodel/__init__.py +2 -0
  30. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/sqlmodel/adapter.py +4 -2
  31. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/config.py +1 -0
  32. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/core/tokens.py +12 -1
  33. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/email_verify.py +7 -0
  34. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/login.py +9 -0
  35. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/oauth.py +18 -1
  36. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/password_reset.py +9 -0
  37. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/register.py +7 -0
  38. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/fullauth.py +9 -1
  39. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/middleware/csrf.py +6 -0
  40. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/oauth/github.py +11 -3
  41. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/oauth/google.py +9 -2
  42. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/protection/lockout.py +8 -0
  43. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/protection/ratelimit.py +9 -1
  44. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/router/auth.py +42 -3
  45. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/router/oauth.py +6 -2
  46. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/utils.py +17 -0
  47. fastapi_fullauth-0.5.0/mkdocs.yml +74 -0
  48. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/pyproject.toml +3 -2
  49. fastapi_fullauth-0.5.0/tests/__init__.py +0 -0
  50. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_middleware.py +80 -0
  51. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_oauth.py +18 -0
  52. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_refresh_tokens.py +53 -0
  53. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/uv.lock +435 -1
  54. fastapi_fullauth-0.4.0/PKG-INFO +0 -307
  55. fastapi_fullauth-0.4.0/README.md +0 -261
  56. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/.github/workflows/ci.yml +0 -0
  57. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/.github/workflows/publish.yml +0 -0
  58. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/.python-version +0 -0
  59. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/LICENSE +0 -0
  60. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/memory_app/__init__.py +0 -0
  61. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/memory_app/auth.py +0 -0
  62. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/memory_app/main.py +0 -0
  63. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/memory_app/routes.py +0 -0
  64. {fastapi_fullauth-0.4.0/examples/sqlmodel_app → fastapi_fullauth-0.5.0/examples/sqlalchemy_app}/__init__.py +0 -0
  65. {fastapi_fullauth-0.4.0/examples/sqlmodel_app → fastapi_fullauth-0.5.0/examples/sqlalchemy_app}/routes.py +0 -0
  66. {fastapi_fullauth-0.4.0/fastapi_fullauth/rbac → fastapi_fullauth-0.5.0/examples/sqlmodel_app}/__init__.py +0 -0
  67. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/sqlmodel_app/auth.py +0 -0
  68. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/sqlmodel_app/config.py +0 -0
  69. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/sqlmodel_app/main.py +0 -0
  70. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/examples/sqlmodel_app/models.py +0 -0
  71. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/__init__.py +0 -0
  72. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/base.py +0 -0
  73. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/memory.py +0 -0
  74. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/sqlalchemy/__init__.py +0 -0
  75. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/sqlalchemy/adapter.py +0 -0
  76. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/sqlalchemy/models.py +0 -0
  77. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/adapters/sqlmodel/models.py +0 -0
  78. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/backends/__init__.py +0 -0
  79. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/backends/base.py +0 -0
  80. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/backends/bearer.py +0 -0
  81. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/backends/cookie.py +0 -0
  82. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/core/__init__.py +0 -0
  83. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/core/crypto.py +0 -0
  84. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/core/redis_blacklist.py +0 -0
  85. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/dependencies/__init__.py +0 -0
  86. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/dependencies/current_user.py +0 -0
  87. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/dependencies/require_role.py +0 -0
  88. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/exceptions.py +0 -0
  89. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/__init__.py +0 -0
  90. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/flows/logout.py +0 -0
  91. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/hooks.py +0 -0
  92. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/middleware/__init__.py +0 -0
  93. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/middleware/ratelimit.py +0 -0
  94. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/middleware/security_headers.py +0 -0
  95. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/migrations/__init__.py +0 -0
  96. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/migrations/helpers.py +0 -0
  97. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/oauth/__init__.py +0 -0
  98. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/oauth/base.py +0 -0
  99. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/protection/__init__.py +0 -0
  100. {fastapi_fullauth-0.4.0/fastapi_fullauth/router → fastapi_fullauth-0.5.0/fastapi_fullauth/rbac}/__init__.py +0 -0
  101. {fastapi_fullauth-0.4.0/tests → fastapi_fullauth-0.5.0/fastapi_fullauth/router}/__init__.py +0 -0
  102. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/types.py +0 -0
  103. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/fastapi_fullauth/validators.py +0 -0
  104. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/conftest.py +0 -0
  105. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_auth_flows.py +0 -0
  106. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_crypto.py +0 -0
  107. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_customization.py +0 -0
  108. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_dx_improvements.py +0 -0
  109. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_email_verify.py +0 -0
  110. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_lockout.py +0 -0
  111. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_new_endpoints.py +0 -0
  112. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.5.0}/tests/test_roles.py +0 -0
  113. {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
@@ -28,7 +28,13 @@ Thumbs.db
28
28
  .coverage
29
29
  htmlcov/
30
30
 
31
+ # Linting
32
+ .ruff_cache/
33
+
31
34
  # Distribution
32
35
  *.tar.gz
33
36
  *.whl
34
37
  architecture.md
38
+
39
+ # Docs build
40
+ site/
@@ -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