fastapi-fullauth 0.5.0__tar.gz → 0.7.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 (139) hide show
  1. fastapi_fullauth-0.7.0/.github/ISSUE_TEMPLATE/bug_report.yml +60 -0
  2. fastapi_fullauth-0.7.0/.github/ISSUE_TEMPLATE/feature_request.yml +30 -0
  3. fastapi_fullauth-0.7.0/.github/pull_request_template.md +17 -0
  4. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/CHANGELOG.md +92 -0
  5. fastapi_fullauth-0.7.0/CONTRIBUTING.md +83 -0
  6. fastapi_fullauth-0.7.0/Makefile +64 -0
  7. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/PKG-INFO +106 -39
  8. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/README.md +104 -37
  9. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/adapters/index.md +18 -8
  10. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/adapters/sqlalchemy.md +24 -10
  11. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/adapters/sqlmodel.md +15 -8
  12. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/api-reference.md +22 -21
  13. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/auth/custom-claims.md +4 -1
  14. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/auth/dependencies.md +77 -1
  15. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/auth/hooks.md +1 -1
  16. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/auth/passwords.md +8 -4
  17. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/configuration.md +13 -18
  18. fastapi_fullauth-0.7.0/docs/contributing.md +72 -0
  19. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/getting-started.md +31 -5
  20. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/index.md +60 -25
  21. fastapi_fullauth-0.7.0/docs/llms-full.txt +2141 -0
  22. fastapi_fullauth-0.7.0/docs/llms.txt +30 -0
  23. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/oauth.md +27 -17
  24. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/security/middleware.md +7 -3
  25. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/security/rate-limiting.md +26 -14
  26. fastapi_fullauth-0.7.0/docs/stylesheets/home.css +5 -0
  27. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/examples/sqlalchemy_app/auth.py +5 -3
  28. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/examples/sqlmodel_app/auth.py +5 -3
  29. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/__init__.py +11 -3
  30. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/__init__.py +1 -2
  31. fastapi_fullauth-0.7.0/fastapi_fullauth/adapters/base.py +117 -0
  32. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/sqlalchemy/__init__.py +4 -0
  33. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/sqlalchemy/adapter.py +100 -60
  34. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/sqlalchemy/models.py +19 -0
  35. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/sqlmodel/__init__.py +4 -0
  36. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/sqlmodel/adapter.py +100 -43
  37. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/sqlmodel/models.py +15 -0
  38. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/config.py +4 -2
  39. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/core/crypto.py +6 -17
  40. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/core/tokens.py +14 -0
  41. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/dependencies/__init__.py +6 -0
  42. fastapi_fullauth-0.7.0/fastapi_fullauth/dependencies/current_user.py +153 -0
  43. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/dependencies/require_role.py +22 -4
  44. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/exceptions.py +34 -0
  45. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/__init__.py +4 -0
  46. fastapi_fullauth-0.7.0/fastapi_fullauth/flows/change_password.py +31 -0
  47. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/email_verify.py +6 -5
  48. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/login.py +10 -9
  49. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/oauth.py +11 -8
  50. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/password_reset.py +11 -4
  51. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/register.py +7 -1
  52. fastapi_fullauth-0.7.0/fastapi_fullauth/flows/update_profile.py +27 -0
  53. fastapi_fullauth-0.7.0/fastapi_fullauth/fullauth.py +204 -0
  54. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/hooks.py +2 -2
  55. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/middleware/csrf.py +1 -1
  56. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/oauth/base.py +4 -15
  57. fastapi_fullauth-0.7.0/fastapi_fullauth/protection/__init__.py +15 -0
  58. fastapi_fullauth-0.7.0/fastapi_fullauth/protection/lockout.py +129 -0
  59. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/protection/ratelimit.py +19 -0
  60. fastapi_fullauth-0.7.0/fastapi_fullauth/router/__init__.py +11 -0
  61. fastapi_fullauth-0.7.0/fastapi_fullauth/router/_models.py +61 -0
  62. fastapi_fullauth-0.7.0/fastapi_fullauth/router/admin.py +108 -0
  63. fastapi_fullauth-0.7.0/fastapi_fullauth/router/auth.py +244 -0
  64. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/router/oauth.py +25 -21
  65. fastapi_fullauth-0.7.0/fastapi_fullauth/router/profile.py +108 -0
  66. fastapi_fullauth-0.7.0/fastapi_fullauth/router/verify.py +117 -0
  67. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/types.py +24 -19
  68. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/utils.py +4 -2
  69. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/mkdocs.yml +2 -2
  70. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/pyproject.toml +13 -1
  71. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/tests/conftest.py +33 -4
  72. fastapi_fullauth-0.7.0/tests/test_auth.py +809 -0
  73. fastapi_fullauth-0.7.0/tests/test_config.py +604 -0
  74. fastapi_fullauth-0.7.0/tests/test_hooks.py +185 -0
  75. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/tests/test_oauth.py +39 -16
  76. fastapi_fullauth-0.5.0/tests/test_new_endpoints.py → fastapi_fullauth-0.7.0/tests/test_profile.py +66 -118
  77. fastapi_fullauth-0.7.0/tests/test_rbac.py +446 -0
  78. fastapi_fullauth-0.5.0/tests/test_middleware.py → fastapi_fullauth-0.7.0/tests/test_security.py +112 -32
  79. fastapi_fullauth-0.7.0/tests/test_sqlalchemy_adapter.py +338 -0
  80. fastapi_fullauth-0.7.0/tests/test_sqlmodel_adapter.py +380 -0
  81. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/uv.lock +1 -1
  82. fastapi_fullauth-0.5.0/docs/adapters/memory.md +0 -32
  83. fastapi_fullauth-0.5.0/docs/stylesheets/home.css +0 -90
  84. fastapi_fullauth-0.5.0/examples/memory_app/auth.py +0 -8
  85. fastapi_fullauth-0.5.0/examples/memory_app/main.py +0 -13
  86. fastapi_fullauth-0.5.0/examples/sqlmodel_app/routes.py +0 -15
  87. fastapi_fullauth-0.5.0/fastapi_fullauth/adapters/base.py +0 -87
  88. fastapi_fullauth-0.5.0/fastapi_fullauth/adapters/memory.py +0 -133
  89. fastapi_fullauth-0.5.0/fastapi_fullauth/dependencies/current_user.py +0 -87
  90. fastapi_fullauth-0.5.0/fastapi_fullauth/fullauth.py +0 -289
  91. fastapi_fullauth-0.5.0/fastapi_fullauth/migrations/__init__.py +0 -3
  92. fastapi_fullauth-0.5.0/fastapi_fullauth/protection/__init__.py +0 -4
  93. fastapi_fullauth-0.5.0/fastapi_fullauth/protection/lockout.py +0 -41
  94. fastapi_fullauth-0.5.0/fastapi_fullauth/rbac/__init__.py +0 -0
  95. fastapi_fullauth-0.5.0/fastapi_fullauth/router/__init__.py +0 -0
  96. fastapi_fullauth-0.5.0/fastapi_fullauth/router/auth.py +0 -544
  97. fastapi_fullauth-0.5.0/tests/__init__.py +0 -0
  98. fastapi_fullauth-0.5.0/tests/test_auth_flows.py +0 -177
  99. fastapi_fullauth-0.5.0/tests/test_customization.py +0 -369
  100. fastapi_fullauth-0.5.0/tests/test_dx_improvements.py +0 -317
  101. fastapi_fullauth-0.5.0/tests/test_email_verify.py +0 -116
  102. fastapi_fullauth-0.5.0/tests/test_lockout.py +0 -52
  103. fastapi_fullauth-0.5.0/tests/test_refresh_tokens.py +0 -379
  104. fastapi_fullauth-0.5.0/tests/test_roles.py +0 -161
  105. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/.github/workflows/ci.yml +0 -0
  106. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/.github/workflows/docs.yml +0 -0
  107. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/.github/workflows/publish.yml +0 -0
  108. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/.gitignore +0 -0
  109. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/.python-version +0 -0
  110. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/LICENSE +0 -0
  111. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/docs/migrations.md +0 -0
  112. {fastapi_fullauth-0.5.0/examples/memory_app → fastapi_fullauth-0.7.0/examples/sqlalchemy_app}/__init__.py +0 -0
  113. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/examples/sqlalchemy_app/config.py +0 -0
  114. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/examples/sqlalchemy_app/main.py +0 -0
  115. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/examples/sqlalchemy_app/models.py +0 -0
  116. {fastapi_fullauth-0.5.0/examples/memory_app → fastapi_fullauth-0.7.0/examples/sqlalchemy_app}/routes.py +0 -0
  117. {fastapi_fullauth-0.5.0/examples/sqlalchemy_app → fastapi_fullauth-0.7.0/examples/sqlmodel_app}/__init__.py +0 -0
  118. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/examples/sqlmodel_app/config.py +0 -0
  119. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/examples/sqlmodel_app/main.py +0 -0
  120. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/examples/sqlmodel_app/models.py +0 -0
  121. {fastapi_fullauth-0.5.0/examples/sqlalchemy_app → fastapi_fullauth-0.7.0/examples/sqlmodel_app}/routes.py +0 -0
  122. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/backends/__init__.py +0 -0
  123. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/backends/base.py +0 -0
  124. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/backends/bearer.py +0 -0
  125. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/backends/cookie.py +0 -0
  126. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/core/__init__.py +0 -0
  127. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/core/redis_blacklist.py +0 -0
  128. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/logout.py +0 -0
  129. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/middleware/__init__.py +0 -0
  130. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/middleware/ratelimit.py +0 -0
  131. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/middleware/security_headers.py +0 -0
  132. /fastapi_fullauth-0.5.0/fastapi_fullauth/migrations/helpers.py → /fastapi_fullauth-0.7.0/fastapi_fullauth/migrations.py +0 -0
  133. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/oauth/__init__.py +0 -0
  134. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/oauth/github.py +0 -0
  135. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/oauth/google.py +0 -0
  136. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/validators.py +0 -0
  137. {fastapi_fullauth-0.5.0/examples/sqlmodel_app → fastapi_fullauth-0.7.0/tests}/__init__.py +0 -0
  138. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.0}/tests/test_crypto.py +0 -0
  139. {fastapi_fullauth-0.5.0 → fastapi_fullauth-0.7.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 .`)
@@ -1,5 +1,97 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Breaking changes
6
+
7
+ - **InMemory adapter removed** — use SQLModel + SQLite for prototyping instead.
8
+ - **`UserID` is now `UUID`** (was `str | int | UUID`) — all adapter methods, `RefreshToken.user_id`, `OAuthAccount.user_id`, and `RoleAssignment.user_id` are now `UUID`.
9
+ - **OAuth providers passed as objects** — `FullAuth(providers=[GoogleOAuthProvider(...)])` replaces `OAUTH_PROVIDERS` dict in config. `OAuthProviderConfig` removed.
10
+ - **`OAuthProvider` simplified** — only `redirect_uris: list[str]` (removed singular `redirect_uri`). `get_redirect_uri()` removed.
11
+ - **`redirect_uri` required in authorize URL** — clients must pass `?redirect_uri=` in the OAuth authorize request.
12
+
13
+ ### Breaking changes (audit cleanup)
14
+
15
+ - **`include_user_in_login` moved to config** — use `FullAuthConfig(INCLUDE_USER_IN_LOGIN=True)` or `FULLAUTH_INCLUDE_USER_IN_LOGIN=true` env var instead of `FullAuth(include_user_in_login=True)`.
16
+ - **Login response always includes `user` field** — when `INCLUDE_USER_IN_LOGIN=False`, `user` is `null` (previously the key was absent). When `True`, `user` contains the full user schema object.
17
+
18
+ ### Added
19
+
20
+ - **Redis lockout backend** — `LOCKOUT_BACKEND="redis"` for multi-worker deployments
21
+ - `LOCKOUT_ENABLED` config — disable account lockout entirely (`False`)
22
+ - `INCLUDE_USER_IN_LOGIN` config — include user object in login/OAuth callback response
23
+ - `LoginResponse` dynamic model — login and OAuth callback routes now have proper `response_model` with typed `user` field matching the configured user schema
24
+ - `validate_profile_updates` flow — profile field filtering extracted from router to `flows/update_profile.py`
25
+ - `NoValidFieldsError`, `UnknownFieldsError` exceptions for profile update validation
26
+ - `change_password` flow — business logic extracted from profile router
27
+ - `PROTECTED_FIELDS` ClassVar on `UserSchema` — users can extend in subclasses
28
+ - Password validation moved to flows (`register`, `reset_password`, `change_password`)
29
+ - `Makefile` with `make check`, `make test`, `make lint`, `make format`, `make docs`, etc.
30
+
31
+ ### Changed
32
+
33
+ - `LockoutManager` is now an abstract base class with async methods
34
+ - `InMemoryLockoutManager` replaces the old sync `LockoutManager`
35
+ - `migrations/` package flattened to single `migrations.py` module (import paths unchanged)
36
+ - 4 `type: ignore` comments fixed (replaced with `getattr`, assertions, `model_validate`)
37
+ - Misplaced `type: ignore` comments moved inline
38
+ - 204 routes (`delete_me`, `unlink_oauth_account`) no longer return unnecessary `Response` objects
39
+ - Logout route return type corrected to `Response` (needs it for cookie deletion)
40
+ - All tests migrated from InMemory to SQLModel + SQLite
41
+ - Tests regrouped: `test_auth`, `test_profile`, `test_config`, `test_hooks`, `test_security`, `test_rbac`
42
+ - `UUID(payload.sub)` conversion at token boundaries (dependencies, router, flows)
43
+ - Removed `isinstance` str-to-UUID guards from adapters
44
+ - Removed `str(user.id)` / `str(row.user_id)` conversions — UUID used directly
45
+
46
+ ### Removed
47
+
48
+ - `InMemoryAdapter` and `examples/memory_app/`
49
+ - `OAuthProviderConfig` from config
50
+ - `OAUTH_PROVIDERS` from `FullAuthConfig`
51
+ - `FullAuth._build_oauth_providers()` and `_OAUTH_PROVIDER_REGISTRY`
52
+ - `OAuthProvider.get_redirect_uri()` method
53
+ - `rbac/` package (was empty, just re-exported from `dependencies`)
54
+
55
+ ## 0.6.0
56
+
57
+ ### Breaking changes
58
+
59
+ - **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.
60
+ - **`enabled_routes` removed** — replaced by composable routers. Include only the routers you need instead of filtering route names.
61
+ - **`RouteName` type removed** — no longer needed with composable routers.
62
+ - **`configure_hasher()` removed** — hash algorithm is now passed explicitly from config through flows. No more global mutable state.
63
+ - **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.
64
+ - **`create_user_schema` moved to adapter** — pass it to the adapter, not FullAuth: `InMemoryAdapter(user_schema=MyUser, create_user_schema=MyCreate)`.
65
+
66
+ ### Added
67
+
68
+ - **Generic type parameters** — `AbstractUserAdapter[UserSchemaType, CreateUserSchemaType]`, `FullAuth[UserSchemaType, CreateUserSchemaType]` with PEP 696 defaults for full type safety
69
+ - **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
70
+ - **Typed dependency factories** — `get_current_user_dependency(MyUser)`, `get_verified_user_dependency(MyUser)`, `get_superuser_dependency(MyUser)` for custom schema type safety
71
+ - `create_blacklist(config)` — extracted from FullAuth to `core/tokens.py`
72
+ - `create_rate_limiter(config, max, window)` — extracted from FullAuth to `protection/ratelimit.py`
73
+ - `UserSchemaType`, `CreateUserSchemaType` TypeVars exported from top-level package
74
+ - `UserSchema`, `CreateUserSchema` base classes exported from top-level package
75
+
76
+ ### Changed
77
+
78
+ - **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)
79
+ - **FullAuth slimmed** — factory methods extracted, composable router properties added, `_OAUTH_PROVIDER_REGISTRY` stays on class for now
80
+ - `fullauth.router` still works as before (composes all sub-routers), `fullauth.init_app(app)` unchanged
81
+ - `hash_password()` and `password_needs_rehash()` now accept explicit `algorithm` parameter (default `argon2id`)
82
+ - Shared request/response models extracted to `router/_models.py`
83
+ - RBAC permissions (`require_role`, `require_permission`) available via `fastapi_fullauth.dependencies`
84
+
85
+ ### Removed
86
+
87
+ - `FullAuth._resolve_create_schema()` — auto-derivation of create schema from ORM model
88
+ - `SQLModelAdapter._derive_user_schema()` — auto-derivation of user schema
89
+ - `SQLAlchemyAdapter._derive_user_schema()` — auto-derivation of user schema
90
+ - `_SA_TYPE_MAP` and `_get_sa_type_map()` — SQLAlchemy type mapping for auto-derivation
91
+ - `FullAuth._create_blacklist()` — moved to `core/tokens.create_blacklist()`
92
+ - `FullAuth._create_rate_limiter()` — moved to `protection.ratelimit.create_rate_limiter()`
93
+ - `configure_hasher()` and `_algorithm` global from `core/crypto.py`
94
+
3
95
  ## 0.5.0
4
96
 
5
97
  ### 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,64 @@
1
+ .PHONY: install test lint format check fix clean build docs
2
+
3
+ # Install dependencies
4
+ install:
5
+ uv sync --dev --extra sqlalchemy --extra sqlmodel --extra oauth --extra redis
6
+
7
+ # Run tests
8
+ test:
9
+ uv run pytest tests/ -x --tb=short
10
+
11
+ # Run tests with verbose output
12
+ test-v:
13
+ uv run pytest tests/ -v
14
+
15
+ # Run a specific test file
16
+ # Usage: make test-file FILE=test_auth
17
+ test-file:
18
+ uv run pytest tests/$(FILE).py -x --tb=short -v
19
+
20
+ # Lint check (no changes)
21
+ lint:
22
+ uv run ruff check .
23
+
24
+ # Format check (no changes)
25
+ format-check:
26
+ uv run ruff format --check .
27
+
28
+ # Fix lint issues
29
+ fix:
30
+ uv run ruff check --fix .
31
+
32
+ # Format code
33
+ format:
34
+ uv run ruff format .
35
+
36
+ # Run all checks (format + lint + tests) — run before committing
37
+ check: format-check lint test
38
+
39
+ # Fix all issues then verify
40
+ fix-all: format fix test
41
+
42
+ # Build package
43
+ build:
44
+ uv build
45
+
46
+ # Serve docs locally
47
+ docs:
48
+ uv run mkdocs serve
49
+
50
+ # Build docs
51
+ docs-build:
52
+ uv run mkdocs build
53
+
54
+ # Run example apps
55
+ run-sqlmodel:
56
+ uv run uvicorn examples.sqlmodel_app.main:app --reload
57
+
58
+ run-sqlalchemy:
59
+ uv run uvicorn examples.sqlalchemy_app.main:app --reload
60
+
61
+ # Clean build artifacts
62
+ clean:
63
+ rm -rf dist/ build/ *.egg-info .pytest_cache .ruff_cache
64
+ find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-fullauth
3
- Version: 0.5.0
3
+ Version: 0.7.0
4
4
  Summary: Production-grade, async-native authentication and authorization library for FastAPI
5
5
  Project-URL: Homepage, https://github.com/mdfarhankc/fastapi-fullauth
6
6
  Project-URL: Documentation, https://mdfarhankc.github.io/fastapi-fullauth
7
7
  Project-URL: Repository, https://github.com/mdfarhankc/fastapi-fullauth
8
8
  License-Expression: MIT
9
9
  License-File: LICENSE
10
- Keywords: argon2,authentication,authorization,fastapi,jwt,security
10
+ Keywords: argon2,async,authentication,authorization,bcrypt,csrf,fastapi,jwt,oauth2,password-hashing,pydantic,rbac,redis,refresh-token,role-based-access-control,security,sqlalchemy,sqlmodel
11
11
  Classifier: Development Status :: 3 - Alpha
12
12
  Classifier: Framework :: FastAPI
13
13
  Classifier: Intended Audience :: Developers
@@ -82,8 +82,9 @@ Add a complete authentication and authorization system to your **FastAPI** proje
82
82
  - **Role-based access control** — `CurrentUser`, `VerifiedUser`, `SuperUser`, `require_role()`
83
83
  - **Rate limiting** — per-route auth limits + global middleware (memory or Redis)
84
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
85
+ - **Pluggable adapters** — SQLModel or SQLAlchemy
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
87
88
  - **Event hooks** — `after_register`, `after_login`, `send_verification_email`, etc.
88
89
  - **Custom JWT claims** — embed app-specific data in tokens
89
90
  - **Structured logging** — all auth events, security violations, and failures logged
@@ -113,21 +114,45 @@ pip install fastapi-fullauth[all]
113
114
 
114
115
  ```python
115
116
  from fastapi import FastAPI
116
- from fastapi_fullauth import FullAuth
117
- from fastapi_fullauth.adapters.memory import InMemoryAdapter
117
+ from fastapi_fullauth import FullAuth, FullAuthConfig
118
+ from fastapi_fullauth.adapters.sqlmodel import SQLModelAdapter
118
119
 
119
120
  app = FastAPI()
120
121
 
121
122
  fullauth = FullAuth(
122
- secret_key="your-secret-key",
123
- adapter=InMemoryAdapter(),
123
+ adapter=SQLModelAdapter(session_maker=session_maker, user_model=User),
124
+ config=FullAuthConfig(SECRET_KEY="your-secret-key"),
124
125
  )
125
126
  fullauth.init_app(app)
126
127
  ```
127
128
 
128
- That's it — 15+ auth routes are registered under `/api/v1/auth/` automatically.
129
+ That's it — all auth routes are registered under `/api/v1/auth/` automatically.
129
130
 
130
- Omit `secret_key` in dev and a random one is generated (tokens won't survive restarts).
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.
131
156
 
132
157
  ## Routes
133
158
 
@@ -148,15 +173,19 @@ Omit `secret_key` in dev and a random one is generated (tokens won't survive res
148
173
  | `POST` | `/auth/password-reset/confirm` | Reset password |
149
174
  | `POST` | `/auth/admin/assign-role` | Assign role (superuser) |
150
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) |
151
179
 
152
180
  With OAuth enabled, additional routes are registered under `/auth/oauth/`. All routes are prefixed with `/api/v1` by default.
153
181
 
154
- ## Custom user fields
182
+ ## Custom user schemas
155
183
 
156
- Define your model schemas are auto-derived:
184
+ Define your model and schemas pass them explicitly to the adapter:
157
185
 
158
186
  ```python
159
187
  from sqlmodel import Field, Relationship
188
+ from fastapi_fullauth import FullAuth, FullAuthConfig, UserSchema, CreateUserSchema
160
189
  from fastapi_fullauth.adapters.sqlmodel import (
161
190
  UserBase, Role, UserRoleLink, RefreshTokenRecord, SQLModelAdapter,
162
191
  )
@@ -170,13 +199,37 @@ class User(UserBase, table=True):
170
199
  roles: list[Role] = Relationship(link_model=UserRoleLink)
171
200
  refresh_tokens: list[RefreshTokenRecord] = Relationship()
172
201
 
202
+ class MyUserSchema(UserSchema):
203
+ display_name: str = ""
204
+ phone: str = ""
205
+
206
+ class MyCreateSchema(CreateUserSchema):
207
+ display_name: str = ""
208
+
173
209
  fullauth = FullAuth(
174
- secret_key="...",
175
- adapter=SQLModelAdapter(session_maker, user_model=User),
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="..."),
176
217
  )
177
218
  ```
178
219
 
179
- Registration and response schemas pick up `display_name` and `phone` automatically. No separate schema classes needed.
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
+ ```
180
233
 
181
234
  ## Protected routes
182
235
 
@@ -204,24 +257,28 @@ async def editor_panel(user=Depends(require_role("editor"))):
204
257
  ## OAuth2 social login
205
258
 
206
259
  ```python
260
+ from fastapi_fullauth import FullAuth, FullAuthConfig
261
+ from fastapi_fullauth.oauth.google import GoogleOAuthProvider
262
+ from fastapi_fullauth.oauth.github import GitHubOAuthProvider
263
+
207
264
  fullauth = FullAuth(
208
- secret_key="...",
209
265
  adapter=adapter,
210
- oauth_providers={
211
- "google": {
212
- "client_id": "your-google-client-id",
213
- "client_secret": "your-google-secret",
214
- "redirect_uris": [
266
+ config=FullAuthConfig(SECRET_KEY="..."),
267
+ providers=[
268
+ GoogleOAuthProvider(
269
+ client_id="your-google-client-id",
270
+ client_secret="your-google-secret",
271
+ redirect_uris=[
215
272
  "http://localhost:3000/auth/callback",
216
273
  "https://myapp.com/auth/callback",
217
274
  ],
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
- },
275
+ ),
276
+ GitHubOAuthProvider(
277
+ client_id="your-github-client-id",
278
+ client_secret="your-github-secret",
279
+ redirect_uris=["http://localhost:3000/auth/callback"],
280
+ ),
281
+ ],
225
282
  )
226
283
  ```
227
284
 
@@ -244,25 +301,36 @@ Events: `after_register`, `after_login`, `after_logout`, `after_password_change`
244
301
 
245
302
  ## Configuration
246
303
 
247
- Pass inline kwargs or a config object. All options read from env vars with `FULLAUTH_` prefix.
304
+ Pass a `FullAuthConfig` object or set env vars with `FULLAUTH_` prefix.
248
305
 
249
306
  ```python
250
307
  fullauth = FullAuth(
251
- secret_key="...",
252
308
  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"],
309
+ config=FullAuthConfig(
310
+ SECRET_KEY="...",
311
+ ACCESS_TOKEN_EXPIRE_MINUTES=60,
312
+ API_PREFIX="/api/v2",
313
+ LOGIN_FIELD="username",
314
+ PASSWORD_HASH_ALGORITHM="bcrypt",
315
+ BLACKLIST_BACKEND="redis",
316
+ REDIS_URL="redis://localhost:6379/0",
317
+ AUTH_RATE_LIMIT_ENABLED=True,
318
+ TRUSTED_PROXY_HEADERS=["X-Forwarded-For"],
319
+ ),
261
320
  )
262
321
  ```
263
322
 
264
323
  See [Configuration docs](https://mdfarhankc.github.io/fastapi-fullauth/configuration/) for all options.
265
324
 
325
+ ## AI-friendly docs
326
+
327
+ Using an AI coding assistant? Point it at our LLM-optimized docs:
328
+
329
+ - **[llms.txt](https://mdfarhankc.github.io/fastapi-fullauth/llms.txt)** — concise overview with links to all doc pages
330
+ - **[llms-full.txt](https://mdfarhankc.github.io/fastapi-fullauth/llms-full.txt)** — full documentation in a single file
331
+
332
+ Works with Claude, Cursor, Copilot, and any tool that accepts a docs URL.
333
+
266
334
  ## Development
267
335
 
268
336
  ```bash
@@ -272,7 +340,6 @@ uv sync --dev --extra sqlalchemy --extra sqlmodel
272
340
  uv run pytest tests/ -v
273
341
 
274
342
  # run examples
275
- uv run uvicorn examples.memory_app.main:app --reload
276
343
  uv run uvicorn examples.sqlmodel_app.main:app --reload
277
344
  ```
278
345