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.
- fastapi_fullauth-0.6.0/.github/ISSUE_TEMPLATE/bug_report.yml +60 -0
- fastapi_fullauth-0.6.0/.github/ISSUE_TEMPLATE/feature_request.yml +30 -0
- fastapi_fullauth-0.6.0/.github/pull_request_template.md +17 -0
- fastapi_fullauth-0.6.0/.github/workflows/docs.yml +26 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/.gitignore +6 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/CHANGELOG.md +63 -0
- fastapi_fullauth-0.6.0/CONTRIBUTING.md +83 -0
- fastapi_fullauth-0.6.0/PKG-INFO +338 -0
- fastapi_fullauth-0.6.0/README.md +292 -0
- fastapi_fullauth-0.6.0/docs/adapters/index.md +49 -0
- fastapi_fullauth-0.6.0/docs/adapters/memory.md +34 -0
- fastapi_fullauth-0.6.0/docs/adapters/sqlalchemy.md +90 -0
- fastapi_fullauth-0.6.0/docs/adapters/sqlmodel.md +135 -0
- fastapi_fullauth-0.6.0/docs/api-reference.md +158 -0
- fastapi_fullauth-0.6.0/docs/auth/custom-claims.md +56 -0
- fastapi_fullauth-0.6.0/docs/auth/dependencies.md +201 -0
- fastapi_fullauth-0.6.0/docs/auth/hooks.md +94 -0
- fastapi_fullauth-0.6.0/docs/auth/passwords.md +66 -0
- fastapi_fullauth-0.6.0/docs/configuration.md +128 -0
- fastapi_fullauth-0.6.0/docs/contributing.md +72 -0
- fastapi_fullauth-0.6.0/docs/getting-started.md +177 -0
- fastapi_fullauth-0.6.0/docs/index.md +143 -0
- fastapi_fullauth-0.6.0/docs/migrations.md +102 -0
- fastapi_fullauth-0.6.0/docs/oauth.md +173 -0
- fastapi_fullauth-0.6.0/docs/security/middleware.md +98 -0
- fastapi_fullauth-0.6.0/docs/security/rate-limiting.md +128 -0
- fastapi_fullauth-0.6.0/docs/stylesheets/home.css +5 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/memory_app/auth.py +2 -2
- fastapi_fullauth-0.6.0/examples/sqlalchemy_app/auth.py +28 -0
- fastapi_fullauth-0.6.0/examples/sqlalchemy_app/config.py +5 -0
- fastapi_fullauth-0.6.0/examples/sqlalchemy_app/main.py +26 -0
- fastapi_fullauth-0.6.0/examples/sqlalchemy_app/models.py +19 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/sqlmodel_app/auth.py +2 -2
- fastapi_fullauth-0.6.0/examples/sqlmodel_app/routes.py +15 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/__init__.py +11 -3
- fastapi_fullauth-0.6.0/fastapi_fullauth/adapters/base.py +117 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/memory.py +38 -10
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/sqlalchemy/__init__.py +4 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/sqlalchemy/adapter.py +105 -62
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/sqlalchemy/models.py +19 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/sqlmodel/__init__.py +6 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/sqlmodel/adapter.py +105 -43
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/sqlmodel/models.py +15 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/config.py +1 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/core/crypto.py +6 -17
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/core/tokens.py +26 -1
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/dependencies/__init__.py +6 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/dependencies/current_user.py +68 -2
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/dependencies/require_role.py +22 -4
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/email_verify.py +10 -3
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/login.py +17 -6
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/oauth.py +27 -6
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/password_reset.py +13 -3
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/register.py +9 -1
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/fullauth.py +85 -126
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/middleware/csrf.py +6 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/oauth/github.py +11 -3
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/oauth/google.py +9 -2
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/protection/lockout.py +8 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/protection/ratelimit.py +28 -1
- fastapi_fullauth-0.6.0/fastapi_fullauth/rbac/__init__.py +3 -0
- fastapi_fullauth-0.6.0/fastapi_fullauth/router/__init__.py +11 -0
- fastapi_fullauth-0.6.0/fastapi_fullauth/router/_models.py +47 -0
- fastapi_fullauth-0.6.0/fastapi_fullauth/router/admin.py +108 -0
- fastapi_fullauth-0.6.0/fastapi_fullauth/router/auth.py +238 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/router/oauth.py +11 -6
- fastapi_fullauth-0.6.0/fastapi_fullauth/router/profile.py +123 -0
- fastapi_fullauth-0.6.0/fastapi_fullauth/router/verify.py +119 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/types.py +8 -16
- fastapi_fullauth-0.6.0/fastapi_fullauth/utils.py +42 -0
- fastapi_fullauth-0.6.0/mkdocs.yml +75 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/pyproject.toml +3 -2
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_customization.py +12 -20
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_dx_improvements.py +40 -45
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_middleware.py +80 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_new_endpoints.py +1 -2
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_oauth.py +18 -0
- fastapi_fullauth-0.6.0/tests/test_rbac.py +272 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_refresh_tokens.py +53 -0
- fastapi_fullauth-0.6.0/tests/test_sqlalchemy_adapter.py +338 -0
- fastapi_fullauth-0.6.0/tests/test_sqlmodel_adapter.py +398 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/uv.lock +435 -1
- fastapi_fullauth-0.4.0/PKG-INFO +0 -307
- fastapi_fullauth-0.4.0/README.md +0 -261
- fastapi_fullauth-0.4.0/fastapi_fullauth/adapters/base.py +0 -87
- fastapi_fullauth-0.4.0/fastapi_fullauth/router/auth.py +0 -505
- fastapi_fullauth-0.4.0/fastapi_fullauth/utils.py +0 -23
- fastapi_fullauth-0.4.0/tests/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/.github/workflows/ci.yml +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/.github/workflows/publish.yml +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/.python-version +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/LICENSE +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/memory_app/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/memory_app/main.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/memory_app/routes.py +0 -0
- {fastapi_fullauth-0.4.0/examples/sqlmodel_app → fastapi_fullauth-0.6.0/examples/sqlalchemy_app}/__init__.py +0 -0
- {fastapi_fullauth-0.4.0/examples/sqlmodel_app → fastapi_fullauth-0.6.0/examples/sqlalchemy_app}/routes.py +0 -0
- {fastapi_fullauth-0.4.0/fastapi_fullauth/rbac → fastapi_fullauth-0.6.0/examples/sqlmodel_app}/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/sqlmodel_app/config.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/sqlmodel_app/main.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/examples/sqlmodel_app/models.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/adapters/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/backends/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/backends/base.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/backends/bearer.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/backends/cookie.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/core/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/core/redis_blacklist.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/exceptions.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/flows/logout.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/hooks.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/middleware/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/middleware/ratelimit.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/middleware/security_headers.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/migrations/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/migrations/helpers.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/oauth/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/oauth/base.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/protection/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/fastapi_fullauth/validators.py +0 -0
- {fastapi_fullauth-0.4.0/fastapi_fullauth/router → fastapi_fullauth-0.6.0/tests}/__init__.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/conftest.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_auth_flows.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_crypto.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_email_verify.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_lockout.py +0 -0
- {fastapi_fullauth-0.4.0 → fastapi_fullauth-0.6.0}/tests/test_roles.py +0 -0
- {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
|
|
@@ -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
|