fastapi-fullauth 0.4.0__tar.gz → 0.6.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 (129) hide show
  1. fastapi_fullauth-0.6.0/.github/ISSUE_TEMPLATE/bug_report.yml +60 -0
  2. fastapi_fullauth-0.6.0/.github/ISSUE_TEMPLATE/feature_request.yml +30 -0
  3. fastapi_fullauth-0.6.0/.github/pull_request_template.md +17 -0
  4. fastapi_fullauth-0.6.0/.github/workflows/docs.yml +26 -0
  5. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/.gitignore +6 -0
  6. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/CHANGELOG.md +63 -0
  7. fastapi_fullauth-0.6.0/CONTRIBUTING.md +83 -0
  8. fastapi_fullauth-0.6.0/PKG-INFO +338 -0
  9. fastapi_fullauth-0.6.0/README.md +292 -0
  10. fastapi_fullauth-0.6.0/docs/adapters/index.md +49 -0
  11. fastapi_fullauth-0.6.0/docs/adapters/memory.md +34 -0
  12. fastapi_fullauth-0.6.0/docs/adapters/sqlalchemy.md +90 -0
  13. fastapi_fullauth-0.6.0/docs/adapters/sqlmodel.md +135 -0
  14. fastapi_fullauth-0.6.0/docs/api-reference.md +158 -0
  15. fastapi_fullauth-0.6.0/docs/auth/custom-claims.md +56 -0
  16. fastapi_fullauth-0.6.0/docs/auth/dependencies.md +201 -0
  17. fastapi_fullauth-0.6.0/docs/auth/hooks.md +94 -0
  18. fastapi_fullauth-0.6.0/docs/auth/passwords.md +66 -0
  19. fastapi_fullauth-0.6.0/docs/configuration.md +128 -0
  20. fastapi_fullauth-0.6.0/docs/contributing.md +72 -0
  21. fastapi_fullauth-0.6.0/docs/getting-started.md +177 -0
  22. fastapi_fullauth-0.6.0/docs/index.md +143 -0
  23. fastapi_fullauth-0.6.0/docs/migrations.md +102 -0
  24. fastapi_fullauth-0.6.0/docs/oauth.md +173 -0
  25. fastapi_fullauth-0.6.0/docs/security/middleware.md +98 -0
  26. fastapi_fullauth-0.6.0/docs/security/rate-limiting.md +128 -0
  27. fastapi_fullauth-0.6.0/docs/stylesheets/home.css +5 -0
  28. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/memory_app/auth.py +2 -2
  29. fastapi_fullauth-0.6.0/examples/sqlalchemy_app/auth.py +28 -0
  30. fastapi_fullauth-0.6.0/examples/sqlalchemy_app/config.py +5 -0
  31. fastapi_fullauth-0.6.0/examples/sqlalchemy_app/main.py +26 -0
  32. fastapi_fullauth-0.6.0/examples/sqlalchemy_app/models.py +19 -0
  33. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/sqlmodel_app/auth.py +2 -2
  34. fastapi_fullauth-0.6.0/examples/sqlmodel_app/routes.py +15 -0
  35. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/__init__.py +11 -3
  36. fastapi_fullauth-0.6.0/fastapi_fullauth/adapters/base.py +117 -0
  37. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/memory.py +38 -10
  38. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/sqlalchemy/__init__.py +4 -0
  39. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/sqlalchemy/adapter.py +105 -62
  40. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/sqlalchemy/models.py +19 -0
  41. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/sqlmodel/__init__.py +6 -0
  42. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/sqlmodel/adapter.py +105 -43
  43. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/sqlmodel/models.py +15 -0
  44. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/config.py +1 -0
  45. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/core/crypto.py +6 -17
  46. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/core/tokens.py +26 -1
  47. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/dependencies/__init__.py +6 -0
  48. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/dependencies/current_user.py +68 -2
  49. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/dependencies/require_role.py +22 -4
  50. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/email_verify.py +10 -3
  51. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/login.py +17 -6
  52. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/oauth.py +27 -6
  53. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/password_reset.py +13 -3
  54. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/register.py +9 -1
  55. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/fullauth.py +85 -126
  56. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/middleware/csrf.py +6 -0
  57. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/oauth/github.py +11 -3
  58. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/oauth/google.py +9 -2
  59. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/protection/lockout.py +8 -0
  60. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/protection/ratelimit.py +28 -1
  61. fastapi_fullauth-0.6.0/fastapi_fullauth/rbac/__init__.py +3 -0
  62. fastapi_fullauth-0.6.0/fastapi_fullauth/router/__init__.py +11 -0
  63. fastapi_fullauth-0.6.0/fastapi_fullauth/router/_models.py +47 -0
  64. fastapi_fullauth-0.6.0/fastapi_fullauth/router/admin.py +108 -0
  65. fastapi_fullauth-0.6.0/fastapi_fullauth/router/auth.py +238 -0
  66. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/router/oauth.py +11 -6
  67. fastapi_fullauth-0.6.0/fastapi_fullauth/router/profile.py +123 -0
  68. fastapi_fullauth-0.6.0/fastapi_fullauth/router/verify.py +119 -0
  69. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/types.py +8 -16
  70. fastapi_fullauth-0.6.0/fastapi_fullauth/utils.py +42 -0
  71. fastapi_fullauth-0.6.0/mkdocs.yml +75 -0
  72. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/pyproject.toml +3 -2
  73. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_customization.py +12 -20
  74. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_dx_improvements.py +40 -45
  75. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_middleware.py +80 -0
  76. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_new_endpoints.py +1 -2
  77. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_oauth.py +18 -0
  78. fastapi_fullauth-0.6.0/tests/test_rbac.py +272 -0
  79. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_refresh_tokens.py +53 -0
  80. fastapi_fullauth-0.6.0/tests/test_sqlalchemy_adapter.py +338 -0
  81. fastapi_fullauth-0.6.0/tests/test_sqlmodel_adapter.py +398 -0
  82. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/uv.lock +435 -1
  83. fastapi_fullauth-0.4.0/PKG-INFO +0 -307
  84. fastapi_fullauth-0.4.0/README.md +0 -261
  85. fastapi_fullauth-0.4.0/fastapi_fullauth/adapters/base.py +0 -87
  86. fastapi_fullauth-0.4.0/fastapi_fullauth/router/auth.py +0 -505
  87. fastapi_fullauth-0.4.0/fastapi_fullauth/utils.py +0 -23
  88. fastapi_fullauth-0.4.0/tests/__init__.py +0 -0
  89. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/.github/workflows/ci.yml +0 -0
  90. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/.github/workflows/publish.yml +0 -0
  91. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/.python-version +0 -0
  92. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/LICENSE +0 -0
  93. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/memory_app/__init__.py +0 -0
  94. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/memory_app/main.py +0 -0
  95. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/memory_app/routes.py +0 -0
  96. {fastapi_fullauth-0.4.0/examples/sqlmodel_app → fastapi_fullauth-0.6.0/examples/sqlalchemy_app}/__init__.py +0 -0
  97. {fastapi_fullauth-0.4.0/examples/sqlmodel_app → fastapi_fullauth-0.6.0/examples/sqlalchemy_app}/routes.py +0 -0
  98. {fastapi_fullauth-0.4.0/fastapi_fullauth/rbac → fastapi_fullauth-0.6.0/examples/sqlmodel_app}/__init__.py +0 -0
  99. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/sqlmodel_app/config.py +0 -0
  100. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/sqlmodel_app/main.py +0 -0
  101. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/sqlmodel_app/models.py +0 -0
  102. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/__init__.py +0 -0
  103. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/backends/__init__.py +0 -0
  104. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/backends/base.py +0 -0
  105. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/backends/bearer.py +0 -0
  106. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/backends/cookie.py +0 -0
  107. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/core/__init__.py +0 -0
  108. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/core/redis_blacklist.py +0 -0
  109. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/exceptions.py +0 -0
  110. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/__init__.py +0 -0
  111. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/logout.py +0 -0
  112. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/hooks.py +0 -0
  113. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/middleware/__init__.py +0 -0
  114. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/middleware/ratelimit.py +0 -0
  115. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/middleware/security_headers.py +0 -0
  116. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/migrations/__init__.py +0 -0
  117. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/migrations/helpers.py +0 -0
  118. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/oauth/__init__.py +0 -0
  119. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/oauth/base.py +0 -0
  120. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/protection/__init__.py +0 -0
  121. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/validators.py +0 -0
  122. {fastapi_fullauth-0.4.0/fastapi_fullauth/router → fastapi_fullauth-0.6.0/tests}/__init__.py +0 -0
  123. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/conftest.py +0 -0
  124. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_auth_flows.py +0 -0
  125. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_crypto.py +0 -0
  126. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_email_verify.py +0 -0
  127. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_lockout.py +0 -0
  128. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_roles.py +0 -0
  129. {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_tokens.py +0 -0
@@ -0,0 +1,60 @@
1
+ name: Bug Report
2
+ description: Report a bug in fastapi-fullauth
3
+ labels: ["bug"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Thanks for reporting a bug! Please fill out the details below.
9
+
10
+ - type: input
11
+ id: version
12
+ attributes:
13
+ label: fastapi-fullauth version
14
+ placeholder: "0.5.0"
15
+ validations:
16
+ required: true
17
+
18
+ - type: input
19
+ id: python-version
20
+ attributes:
21
+ label: Python version
22
+ placeholder: "3.12"
23
+ validations:
24
+ required: true
25
+
26
+ - type: dropdown
27
+ id: adapter
28
+ attributes:
29
+ label: Adapter
30
+ options:
31
+ - SQLModel
32
+ - SQLAlchemy
33
+ - InMemory
34
+ - Custom
35
+ validations:
36
+ required: true
37
+
38
+ - type: textarea
39
+ id: description
40
+ attributes:
41
+ label: Description
42
+ description: What happened? What did you expect to happen?
43
+ validations:
44
+ required: true
45
+
46
+ - type: textarea
47
+ id: reproduction
48
+ attributes:
49
+ label: Steps to reproduce
50
+ description: Minimal code or steps to reproduce the bug.
51
+ render: python
52
+ validations:
53
+ required: true
54
+
55
+ - type: textarea
56
+ id: logs
57
+ attributes:
58
+ label: Error output / traceback
59
+ description: Paste any relevant error messages or tracebacks.
60
+ render: shell
@@ -0,0 +1,30 @@
1
+ name: Feature Request
2
+ description: Suggest a new feature for fastapi-fullauth
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Thanks for suggesting a feature! Please describe what you'd like.
9
+
10
+ - type: textarea
11
+ id: problem
12
+ attributes:
13
+ label: Problem
14
+ description: What problem does this feature solve? What's the use case?
15
+ validations:
16
+ required: true
17
+
18
+ - type: textarea
19
+ id: solution
20
+ attributes:
21
+ label: Proposed solution
22
+ description: How would you like this to work? Code examples are welcome.
23
+ validations:
24
+ required: true
25
+
26
+ - type: textarea
27
+ id: alternatives
28
+ attributes:
29
+ label: Alternatives considered
30
+ description: Any workarounds or alternative approaches you've considered?
@@ -0,0 +1,17 @@
1
+ ## Summary
2
+
3
+ <!-- What does this PR do? Keep it brief. -->
4
+
5
+ ## Changes
6
+
7
+ <!-- Bullet list of what changed. -->
8
+
9
+ -
10
+
11
+ ## Test plan
12
+
13
+ <!-- How was this tested? -->
14
+
15
+ - [ ] All existing tests pass
16
+ - [ ] New tests added for new functionality
17
+ - [ ] Lint and format clean (`ruff check .` + `ruff format --check .`)
@@ -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,68 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Breaking changes
6
+
7
+ - **Config-only API** — `FullAuth` no longer accepts `secret_key=`, `**config_kwargs`, or positional `config`. Pass `config=FullAuthConfig(SECRET_KEY="...")` or set `FULLAUTH_SECRET_KEY` env var. All params are keyword-only.
8
+ - **`enabled_routes` removed** — replaced by composable routers. Include only the routers you need instead of filtering route names.
9
+ - **`RouteName` type removed** — no longer needed with composable routers.
10
+ - **`configure_hasher()` removed** — hash algorithm is now passed explicitly from config through flows. No more global mutable state.
11
+ - **Schema auto-derivation removed** — `_derive_user_schema()` and `_resolve_create_schema()` deleted from all adapters and FullAuth. Define your own schemas extending `UserSchema` / `CreateUserSchema` and pass them to the adapter.
12
+ - **`create_user_schema` moved to adapter** — pass it to the adapter, not FullAuth: `InMemoryAdapter(user_schema=MyUser, create_user_schema=MyCreate)`.
13
+
14
+ ### Added
15
+
16
+ - **Generic type parameters** — `AbstractUserAdapter[UserSchemaType, CreateUserSchemaType]`, `FullAuth[UserSchemaType, CreateUserSchemaType]` with PEP 696 defaults for full type safety
17
+ - **Composable routers** — `fullauth.auth_router`, `fullauth.profile_router`, `fullauth.verify_router`, `fullauth.admin_router`, `fullauth.oauth_router`. Each lazily created, include only what you need
18
+ - **Typed dependency factories** — `get_current_user_dependency(MyUser)`, `get_verified_user_dependency(MyUser)`, `get_superuser_dependency(MyUser)` for custom schema type safety
19
+ - `create_blacklist(config)` — extracted from FullAuth to `core/tokens.py`
20
+ - `create_rate_limiter(config, max, window)` — extracted from FullAuth to `protection/ratelimit.py`
21
+ - `UserSchemaType`, `CreateUserSchemaType` TypeVars exported from top-level package
22
+ - `UserSchema`, `CreateUserSchema` base classes exported from top-level package
23
+
24
+ ### Changed
25
+
26
+ - **Router split** — 613-line monolithic `create_auth_router()` split into `create_auth_router()` (login/register/logout/refresh), `create_profile_router()` (me/update/delete/change-password), `create_verify_router()` (email verify/password reset), `create_admin_router()` (roles/permissions)
27
+ - **FullAuth slimmed** — factory methods extracted, composable router properties added, `_OAUTH_PROVIDER_REGISTRY` stays on class for now
28
+ - `fullauth.router` still works as before (composes all sub-routers), `fullauth.init_app(app)` unchanged
29
+ - `hash_password()` and `password_needs_rehash()` now accept explicit `algorithm` parameter (default `argon2id`)
30
+ - Shared request/response models extracted to `router/_models.py`
31
+ - RBAC permissions (`require_role`, `require_permission`) available via `fastapi_fullauth.dependencies` (removed `rbac/` re-export package will happen in next release)
32
+
33
+ ### Removed
34
+
35
+ - `FullAuth._resolve_create_schema()` — auto-derivation of create schema from ORM model
36
+ - `SQLModelAdapter._derive_user_schema()` — auto-derivation of user schema
37
+ - `SQLAlchemyAdapter._derive_user_schema()` — auto-derivation of user schema
38
+ - `_SA_TYPE_MAP` and `_get_sa_type_map()` — SQLAlchemy type mapping for auto-derivation
39
+ - `FullAuth._create_blacklist()` — moved to `core/tokens.create_blacklist()`
40
+ - `FullAuth._create_rate_limiter()` — moved to `protection.ratelimit.create_rate_limiter()`
41
+ - `configure_hasher()` and `_algorithm` global from `core/crypto.py`
42
+
43
+ ## 0.5.0
44
+
45
+ ### Added
46
+
47
+ - **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.*")`
48
+ - **Documentation site** — MkDocs with Material theme, auto-deployed to GitHub Pages via CI
49
+ - **Proxy-aware rate limiting** — new `TRUSTED_PROXY_HEADERS` config to read real client IPs from `X-Forwarded-For` and similar headers
50
+ - **SQLAlchemy example app** (`examples/sqlalchemy_app/`)
51
+ - **`update_user` field validation** — rejects unknown fields with 422 instead of passing them to the DB
52
+ - SQLModel adapter now accepts both SQLModel's and SQLAlchemy's `AsyncSession`
53
+ - `OAuthAccountRecord` exported from `fastapi_fullauth.adapters.sqlmodel`
54
+
55
+ ### Fixed
56
+
57
+ - **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
58
+ - **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
59
+ - **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
60
+
61
+ ### Changed
62
+
63
+ - README rewritten with centered hero layout, badges, and documentation links
64
+ - Documentation URL updated in `pyproject.toml` to point to GitHub Pages
65
+
3
66
  ## 0.4.0
4
67
 
5
68
  ### Added
@@ -0,0 +1,83 @@
1
+ # Contributing to FastAPI FullAuth
2
+
3
+ Thanks for your interest in contributing! Here's how to get started.
4
+
5
+ ## Development setup
6
+
7
+ ```bash
8
+ git clone https://github.com/mdfarhankc/fastapi-fullauth.git
9
+ cd fastapi-fullauth
10
+ uv sync --dev --extra sqlalchemy --extra sqlmodel --extra redis --extra oauth
11
+ ```
12
+
13
+ ## Running tests
14
+
15
+ ```bash
16
+ uv run pytest tests/ -v
17
+ ```
18
+
19
+ ## Linting and formatting
20
+
21
+ ```bash
22
+ uv run ruff check .
23
+ uv run ruff format .
24
+ ```
25
+
26
+ Both must pass before submitting a PR. CI enforces this.
27
+
28
+ ## Making changes
29
+
30
+ 1. Fork the repo and create a branch from `main`
31
+ 2. Make your changes
32
+ 3. Add tests for new functionality
33
+ 4. Ensure all tests pass and lint is clean
34
+ 5. Submit a pull request
35
+
36
+ ## Branch naming
37
+
38
+ - `feat/description` — new features
39
+ - `fix/description` — bug fixes
40
+ - `refactor/description` — code improvements
41
+ - `docs/description` — documentation changes
42
+
43
+ ## Commit messages
44
+
45
+ Keep them short and descriptive. Use imperative mood:
46
+
47
+ - `add permission-based RBAC`
48
+ - `fix OAuth state token TTL`
49
+ - `update README with docs link`
50
+
51
+ ## What to contribute
52
+
53
+ - Bug fixes
54
+ - New OAuth providers (Apple, Discord, Microsoft, etc.)
55
+ - Adapter implementations (MongoDB, Tortoise ORM, etc.)
56
+ - Documentation improvements
57
+ - Test coverage improvements
58
+ - Performance improvements
59
+
60
+ ## Reporting bugs
61
+
62
+ Use the [bug report template](https://github.com/mdfarhankc/fastapi-fullauth/issues/new?template=bug_report.yml) on GitHub Issues. Include:
63
+
64
+ - Python version
65
+ - fastapi-fullauth version
66
+ - Minimal reproduction steps
67
+ - Expected vs actual behavior
68
+
69
+ ## Requesting features
70
+
71
+ Use the [feature request template](https://github.com/mdfarhankc/fastapi-fullauth/issues/new?template=feature_request.yml) on GitHub Issues.
72
+
73
+ ## Code style
74
+
75
+ - Follow existing patterns in the codebase
76
+ - Use type annotations
77
+ - Keep functions focused and small
78
+ - Log security-sensitive events via `logging.getLogger("fastapi_fullauth.*")`
79
+ - Don't add docstrings/comments unless the logic isn't self-evident
80
+
81
+ ## License
82
+
83
+ By contributing, you agree that your contributions will be licensed under the MIT License.
@@ -0,0 +1,338 @@
1
+ Metadata-Version: 2.4
2
+ Name: fastapi-fullauth
3
+ Version: 0.6.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
+ - **Generic type parameters** — define your own schemas with full IDE support and type safety
87
+ - **Composable routers** — include only the route groups you need
88
+ - **Event hooks** — `after_register`, `after_login`, `send_verification_email`, etc.
89
+ - **Custom JWT claims** — embed app-specific data in tokens
90
+ - **Structured logging** — all auth events, security violations, and failures logged
91
+ - **Redis support** — token blacklist and rate limiter backends
92
+ - **Python 3.10 – 3.14** supported
93
+
94
+ ## Installation
95
+
96
+ ```bash
97
+ pip install fastapi-fullauth
98
+
99
+ # with an ORM adapter
100
+ pip install fastapi-fullauth[sqlmodel]
101
+ pip install fastapi-fullauth[sqlalchemy]
102
+
103
+ # with Redis for token blacklisting
104
+ pip install fastapi-fullauth[sqlmodel,redis]
105
+
106
+ # with OAuth2 social login
107
+ pip install fastapi-fullauth[sqlmodel,oauth]
108
+
109
+ # everything
110
+ pip install fastapi-fullauth[all]
111
+ ```
112
+
113
+ ## Quick start
114
+
115
+ ```python
116
+ from fastapi import FastAPI
117
+ from fastapi_fullauth import FullAuth, FullAuthConfig
118
+ from fastapi_fullauth.adapters.memory import InMemoryAdapter
119
+
120
+ app = FastAPI()
121
+
122
+ fullauth = FullAuth(
123
+ adapter=InMemoryAdapter(),
124
+ config=FullAuthConfig(SECRET_KEY="your-secret-key"),
125
+ )
126
+ fullauth.init_app(app)
127
+ ```
128
+
129
+ That's it — all auth routes are registered under `/api/v1/auth/` automatically.
130
+
131
+ Omit `config` in dev and a random secret key is generated (tokens won't survive restarts).
132
+
133
+ ### Composable routers
134
+
135
+ Include only the route groups you need:
136
+
137
+ ```python
138
+ app = FastAPI()
139
+ app.state.fullauth = fullauth
140
+
141
+ # pick what you want
142
+ app.include_router(fullauth.auth_router, prefix="/api/v1/auth")
143
+ app.include_router(fullauth.profile_router, prefix="/api/v1/auth")
144
+ # skip verify, admin, oauth
145
+ ```
146
+
147
+ | Router | Routes |
148
+ |--------|--------|
149
+ | `auth_router` | register, login, logout, refresh |
150
+ | `profile_router` | me, verified-me, update profile, delete account, change password |
151
+ | `verify_router` | email verification, password reset |
152
+ | `admin_router` | assign/remove roles and permissions (superuser) |
153
+ | `oauth_router` | OAuth provider routes (only if configured) |
154
+
155
+ `fullauth.init_app(app)` includes all of them. Use individual routers for granular control.
156
+
157
+ ## Routes
158
+
159
+ | Method | Path | Description |
160
+ |--------|------|-------------|
161
+ | `POST` | `/auth/register` | Create a new user |
162
+ | `POST` | `/auth/login` | Authenticate, get tokens |
163
+ | `POST` | `/auth/logout` | Blacklist token |
164
+ | `POST` | `/auth/refresh` | Rotate token pair |
165
+ | `GET` | `/auth/me` | Get current user |
166
+ | `GET` | `/auth/me/verified` | Verified users only |
167
+ | `PATCH` | `/auth/me` | Update profile |
168
+ | `DELETE` | `/auth/me` | Delete account |
169
+ | `POST` | `/auth/change-password` | Change password |
170
+ | `POST` | `/auth/verify-email/request` | Request verification email |
171
+ | `POST` | `/auth/verify-email/confirm` | Confirm email |
172
+ | `POST` | `/auth/password-reset/request` | Request password reset |
173
+ | `POST` | `/auth/password-reset/confirm` | Reset password |
174
+ | `POST` | `/auth/admin/assign-role` | Assign role (superuser) |
175
+ | `POST` | `/auth/admin/remove-role` | Remove role (superuser) |
176
+ | `POST` | `/auth/admin/assign-permission` | Assign permission to role (superuser) |
177
+ | `POST` | `/auth/admin/remove-permission` | Remove permission from role (superuser) |
178
+ | `GET` | `/auth/admin/role-permissions/{role}` | List role's permissions (superuser) |
179
+
180
+ With OAuth enabled, additional routes are registered under `/auth/oauth/`. All routes are prefixed with `/api/v1` by default.
181
+
182
+ ## Custom user schemas
183
+
184
+ Define your model and schemas — pass them explicitly to the adapter:
185
+
186
+ ```python
187
+ from sqlmodel import Field, Relationship
188
+ from fastapi_fullauth import FullAuth, FullAuthConfig, UserSchema, CreateUserSchema
189
+ from fastapi_fullauth.adapters.sqlmodel import (
190
+ UserBase, Role, UserRoleLink, RefreshTokenRecord, SQLModelAdapter,
191
+ )
192
+
193
+ class User(UserBase, table=True):
194
+ __tablename__ = "fullauth_users"
195
+
196
+ display_name: str = Field(default="", max_length=100)
197
+ phone: str = Field(default="", max_length=20)
198
+
199
+ roles: list[Role] = Relationship(link_model=UserRoleLink)
200
+ refresh_tokens: list[RefreshTokenRecord] = Relationship()
201
+
202
+ class MyUserSchema(UserSchema):
203
+ display_name: str = ""
204
+ phone: str = ""
205
+
206
+ class MyCreateSchema(CreateUserSchema):
207
+ display_name: str = ""
208
+
209
+ fullauth = FullAuth(
210
+ adapter=SQLModelAdapter(
211
+ session_maker,
212
+ user_model=User,
213
+ user_schema=MyUserSchema,
214
+ create_user_schema=MyCreateSchema,
215
+ ),
216
+ config=FullAuthConfig(SECRET_KEY="..."),
217
+ )
218
+ ```
219
+
220
+ Full IDE autocompletion and type checking on custom fields. Use `get_current_user_dependency()` for typed dependencies:
221
+
222
+ ```python
223
+ from typing import Annotated
224
+ from fastapi import Depends
225
+ from fastapi_fullauth.dependencies import get_current_user_dependency
226
+
227
+ MyCurrentUser = Annotated[MyUserSchema, Depends(get_current_user_dependency(MyUserSchema))]
228
+
229
+ @app.get("/profile")
230
+ async def profile(user: MyCurrentUser):
231
+ return {"name": user.display_name} # IDE knows this field exists
232
+ ```
233
+
234
+ ## Protected routes
235
+
236
+ ```python
237
+ from fastapi import Depends
238
+ from fastapi_fullauth.dependencies import CurrentUser, VerifiedUser, SuperUser, require_role
239
+
240
+ @app.get("/profile")
241
+ async def profile(user: CurrentUser):
242
+ return user
243
+
244
+ @app.get("/dashboard")
245
+ async def dashboard(user: VerifiedUser):
246
+ return {"email": user.email}
247
+
248
+ @app.delete("/admin/users/{id}")
249
+ async def delete_user(user: SuperUser):
250
+ ...
251
+
252
+ @app.get("/editor")
253
+ async def editor_panel(user=Depends(require_role("editor"))):
254
+ ...
255
+ ```
256
+
257
+ ## OAuth2 social login
258
+
259
+ ```python
260
+ fullauth = FullAuth(
261
+ adapter=adapter,
262
+ config=FullAuthConfig(
263
+ SECRET_KEY="...",
264
+ OAUTH_PROVIDERS={
265
+ "google": {
266
+ "client_id": "your-google-client-id",
267
+ "client_secret": "your-google-secret",
268
+ "redirect_uris": [
269
+ "http://localhost:3000/auth/callback",
270
+ "https://myapp.com/auth/callback",
271
+ ],
272
+ },
273
+ "github": {
274
+ "client_id": "your-github-client-id",
275
+ "client_secret": "your-github-secret",
276
+ "redirect_uri": "http://localhost:3000/auth/callback",
277
+ },
278
+ },
279
+ ),
280
+ )
281
+ ```
282
+
283
+ Requires `httpx`: `pip install fastapi-fullauth[oauth]`
284
+
285
+ ## Event hooks
286
+
287
+ ```python
288
+ async def welcome(user):
289
+ await send_email(user.email, "Welcome!")
290
+
291
+ async def send_verify(email, token):
292
+ await send_email(email, f"Verify: https://myapp.com/verify?token={token}")
293
+
294
+ fullauth.hooks.on("after_register", welcome)
295
+ fullauth.hooks.on("send_verification_email", send_verify)
296
+ ```
297
+
298
+ 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`
299
+
300
+ ## Configuration
301
+
302
+ Pass a `FullAuthConfig` object or set env vars with `FULLAUTH_` prefix.
303
+
304
+ ```python
305
+ fullauth = FullAuth(
306
+ adapter=adapter,
307
+ config=FullAuthConfig(
308
+ SECRET_KEY="...",
309
+ ACCESS_TOKEN_EXPIRE_MINUTES=60,
310
+ API_PREFIX="/api/v2",
311
+ LOGIN_FIELD="username",
312
+ PASSWORD_HASH_ALGORITHM="bcrypt",
313
+ BLACKLIST_BACKEND="redis",
314
+ REDIS_URL="redis://localhost:6379/0",
315
+ AUTH_RATE_LIMIT_ENABLED=True,
316
+ TRUSTED_PROXY_HEADERS=["X-Forwarded-For"],
317
+ ),
318
+ )
319
+ ```
320
+
321
+ See [Configuration docs](https://mdfarhankc.github.io/fastapi-fullauth/configuration/) for all options.
322
+
323
+ ## Development
324
+
325
+ ```bash
326
+ git clone https://github.com/mdfarhankc/fastapi-fullauth.git
327
+ cd fastapi-fullauth
328
+ uv sync --dev --extra sqlalchemy --extra sqlmodel
329
+ uv run pytest tests/ -v
330
+
331
+ # run examples
332
+ uv run uvicorn examples.memory_app.main:app --reload
333
+ uv run uvicorn examples.sqlmodel_app.main:app --reload
334
+ ```
335
+
336
+ ## License
337
+
338
+ MIT