fastapi-fullauth 0.6.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.
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/CHANGELOG.md +53 -1
- fastapi_fullauth-0.7.0/Makefile +64 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/PKG-INFO +34 -24
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/README.md +32 -22
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/adapters/index.md +18 -8
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/api-reference.md +14 -3
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/configuration.md +3 -1
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/getting-started.md +4 -1
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/index.md +12 -3
- fastapi_fullauth-0.7.0/docs/llms-full.txt +2141 -0
- fastapi_fullauth-0.7.0/docs/llms.txt +30 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/oauth.md +23 -20
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/examples/sqlalchemy_app/auth.py +4 -2
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/examples/sqlmodel_app/auth.py +4 -2
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/__init__.py +1 -1
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/__init__.py +1 -2
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/sqlalchemy/adapter.py +4 -7
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/sqlmodel/adapter.py +8 -11
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/config.py +4 -2
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/dependencies/current_user.py +4 -4
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/exceptions.py +34 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/__init__.py +4 -0
- fastapi_fullauth-0.7.0/fastapi_fullauth/flows/change_password.py +31 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/email_verify.py +3 -2
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/login.py +6 -7
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/oauth.py +2 -3
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/password_reset.py +7 -1
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/register.py +5 -0
- fastapi_fullauth-0.7.0/fastapi_fullauth/flows/update_profile.py +27 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/fullauth.py +8 -44
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/hooks.py +2 -2
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/middleware/csrf.py +1 -1
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/oauth/base.py +4 -15
- fastapi_fullauth-0.7.0/fastapi_fullauth/protection/__init__.py +15 -0
- fastapi_fullauth-0.7.0/fastapi_fullauth/protection/lockout.py +129 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/router/_models.py +15 -1
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/router/auth.py +24 -18
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/router/oauth.py +20 -17
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/router/profile.py +24 -39
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/router/verify.py +3 -5
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/types.py +17 -4
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/mkdocs.yml +0 -1
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/pyproject.toml +13 -1
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/tests/conftest.py +33 -4
- fastapi_fullauth-0.7.0/tests/test_auth.py +809 -0
- fastapi_fullauth-0.7.0/tests/test_config.py +604 -0
- fastapi_fullauth-0.7.0/tests/test_hooks.py +185 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/tests/test_oauth.py +39 -16
- fastapi_fullauth-0.6.0/tests/test_new_endpoints.py → fastapi_fullauth-0.7.0/tests/test_profile.py +66 -117
- fastapi_fullauth-0.7.0/tests/test_rbac.py +446 -0
- fastapi_fullauth-0.6.0/tests/test_middleware.py → fastapi_fullauth-0.7.0/tests/test_security.py +112 -32
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/tests/test_sqlalchemy_adapter.py +2 -2
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/tests/test_sqlmodel_adapter.py +6 -24
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/uv.lock +1 -1
- fastapi_fullauth-0.6.0/docs/adapters/memory.md +0 -34
- fastapi_fullauth-0.6.0/examples/memory_app/auth.py +0 -8
- fastapi_fullauth-0.6.0/examples/memory_app/main.py +0 -13
- fastapi_fullauth-0.6.0/examples/sqlmodel_app/routes.py +0 -15
- fastapi_fullauth-0.6.0/fastapi_fullauth/adapters/memory.py +0 -161
- fastapi_fullauth-0.6.0/fastapi_fullauth/migrations/__init__.py +0 -3
- fastapi_fullauth-0.6.0/fastapi_fullauth/protection/__init__.py +0 -4
- fastapi_fullauth-0.6.0/fastapi_fullauth/protection/lockout.py +0 -41
- fastapi_fullauth-0.6.0/fastapi_fullauth/rbac/__init__.py +0 -3
- fastapi_fullauth-0.6.0/tests/__init__.py +0 -0
- fastapi_fullauth-0.6.0/tests/test_auth_flows.py +0 -177
- fastapi_fullauth-0.6.0/tests/test_customization.py +0 -361
- fastapi_fullauth-0.6.0/tests/test_dx_improvements.py +0 -312
- fastapi_fullauth-0.6.0/tests/test_email_verify.py +0 -116
- fastapi_fullauth-0.6.0/tests/test_lockout.py +0 -52
- fastapi_fullauth-0.6.0/tests/test_rbac.py +0 -272
- fastapi_fullauth-0.6.0/tests/test_refresh_tokens.py +0 -379
- fastapi_fullauth-0.6.0/tests/test_roles.py +0 -161
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/.github/pull_request_template.md +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/.github/workflows/ci.yml +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/.github/workflows/docs.yml +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/.github/workflows/publish.yml +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/.gitignore +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/.python-version +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/CONTRIBUTING.md +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/LICENSE +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/adapters/sqlalchemy.md +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/adapters/sqlmodel.md +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/auth/custom-claims.md +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/auth/dependencies.md +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/auth/hooks.md +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/auth/passwords.md +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/contributing.md +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/migrations.md +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/security/middleware.md +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/security/rate-limiting.md +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/docs/stylesheets/home.css +0 -0
- {fastapi_fullauth-0.6.0/examples/memory_app → fastapi_fullauth-0.7.0/examples/sqlalchemy_app}/__init__.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/examples/sqlalchemy_app/config.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/examples/sqlalchemy_app/main.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/examples/sqlalchemy_app/models.py +0 -0
- {fastapi_fullauth-0.6.0/examples/memory_app → fastapi_fullauth-0.7.0/examples/sqlalchemy_app}/routes.py +0 -0
- {fastapi_fullauth-0.6.0/examples/sqlalchemy_app → fastapi_fullauth-0.7.0/examples/sqlmodel_app}/__init__.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/examples/sqlmodel_app/config.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/examples/sqlmodel_app/main.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/examples/sqlmodel_app/models.py +0 -0
- {fastapi_fullauth-0.6.0/examples/sqlalchemy_app → fastapi_fullauth-0.7.0/examples/sqlmodel_app}/routes.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/base.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/sqlalchemy/__init__.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/sqlalchemy/models.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/sqlmodel/__init__.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/adapters/sqlmodel/models.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/backends/__init__.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/backends/base.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/backends/bearer.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/backends/cookie.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/core/__init__.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/core/crypto.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/core/redis_blacklist.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/core/tokens.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/dependencies/__init__.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/dependencies/require_role.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/flows/logout.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/middleware/__init__.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/middleware/ratelimit.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/middleware/security_headers.py +0 -0
- /fastapi_fullauth-0.6.0/fastapi_fullauth/migrations/helpers.py → /fastapi_fullauth-0.7.0/fastapi_fullauth/migrations.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/oauth/__init__.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/oauth/github.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/oauth/google.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/protection/ratelimit.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/router/__init__.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/router/admin.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/utils.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/fastapi_fullauth/validators.py +0 -0
- {fastapi_fullauth-0.6.0/examples/sqlmodel_app → fastapi_fullauth-0.7.0/tests}/__init__.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/tests/test_crypto.py +0 -0
- {fastapi_fullauth-0.6.0 → fastapi_fullauth-0.7.0}/tests/test_tokens.py +0 -0
|
@@ -1,5 +1,57 @@
|
|
|
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
|
+
|
|
3
55
|
## 0.6.0
|
|
4
56
|
|
|
5
57
|
### Breaking changes
|
|
@@ -28,7 +80,7 @@
|
|
|
28
80
|
- `fullauth.router` still works as before (composes all sub-routers), `fullauth.init_app(app)` unchanged
|
|
29
81
|
- `hash_password()` and `password_needs_rehash()` now accept explicit `algorithm` parameter (default `argon2id`)
|
|
30
82
|
- Shared request/response models extracted to `router/_models.py`
|
|
31
|
-
- RBAC permissions (`require_role`, `require_permission`) available via `fastapi_fullauth.dependencies`
|
|
83
|
+
- RBAC permissions (`require_role`, `require_permission`) available via `fastapi_fullauth.dependencies`
|
|
32
84
|
|
|
33
85
|
### Removed
|
|
34
86
|
|
|
@@ -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.
|
|
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,7 +82,7 @@ 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
|
|
85
|
+
- **Pluggable adapters** — SQLModel or SQLAlchemy
|
|
86
86
|
- **Generic type parameters** — define your own schemas with full IDE support and type safety
|
|
87
87
|
- **Composable routers** — include only the route groups you need
|
|
88
88
|
- **Event hooks** — `after_register`, `after_login`, `send_verification_email`, etc.
|
|
@@ -115,12 +115,12 @@ pip install fastapi-fullauth[all]
|
|
|
115
115
|
```python
|
|
116
116
|
from fastapi import FastAPI
|
|
117
117
|
from fastapi_fullauth import FullAuth, FullAuthConfig
|
|
118
|
-
from fastapi_fullauth.adapters.
|
|
118
|
+
from fastapi_fullauth.adapters.sqlmodel import SQLModelAdapter
|
|
119
119
|
|
|
120
120
|
app = FastAPI()
|
|
121
121
|
|
|
122
122
|
fullauth = FullAuth(
|
|
123
|
-
adapter=
|
|
123
|
+
adapter=SQLModelAdapter(session_maker=session_maker, user_model=User),
|
|
124
124
|
config=FullAuthConfig(SECRET_KEY="your-secret-key"),
|
|
125
125
|
)
|
|
126
126
|
fullauth.init_app(app)
|
|
@@ -257,26 +257,28 @@ async def editor_panel(user=Depends(require_role("editor"))):
|
|
|
257
257
|
## OAuth2 social login
|
|
258
258
|
|
|
259
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
|
+
|
|
260
264
|
fullauth = FullAuth(
|
|
261
265
|
adapter=adapter,
|
|
262
|
-
config=FullAuthConfig(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
"google"
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
"
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
"github"
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
},
|
|
279
|
-
),
|
|
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=[
|
|
272
|
+
"http://localhost:3000/auth/callback",
|
|
273
|
+
"https://myapp.com/auth/callback",
|
|
274
|
+
],
|
|
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
|
+
],
|
|
280
282
|
)
|
|
281
283
|
```
|
|
282
284
|
|
|
@@ -320,6 +322,15 @@ fullauth = FullAuth(
|
|
|
320
322
|
|
|
321
323
|
See [Configuration docs](https://mdfarhankc.github.io/fastapi-fullauth/configuration/) for all options.
|
|
322
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
|
+
|
|
323
334
|
## Development
|
|
324
335
|
|
|
325
336
|
```bash
|
|
@@ -329,7 +340,6 @@ uv sync --dev --extra sqlalchemy --extra sqlmodel
|
|
|
329
340
|
uv run pytest tests/ -v
|
|
330
341
|
|
|
331
342
|
# run examples
|
|
332
|
-
uv run uvicorn examples.memory_app.main:app --reload
|
|
333
343
|
uv run uvicorn examples.sqlmodel_app.main:app --reload
|
|
334
344
|
```
|
|
335
345
|
|
|
@@ -36,7 +36,7 @@ Add a complete authentication and authorization system to your **FastAPI** proje
|
|
|
36
36
|
- **Role-based access control** — `CurrentUser`, `VerifiedUser`, `SuperUser`, `require_role()`
|
|
37
37
|
- **Rate limiting** — per-route auth limits + global middleware (memory or Redis)
|
|
38
38
|
- **CSRF protection** and **security headers** middleware, auto-wired
|
|
39
|
-
- **Pluggable adapters** — SQLModel
|
|
39
|
+
- **Pluggable adapters** — SQLModel or SQLAlchemy
|
|
40
40
|
- **Generic type parameters** — define your own schemas with full IDE support and type safety
|
|
41
41
|
- **Composable routers** — include only the route groups you need
|
|
42
42
|
- **Event hooks** — `after_register`, `after_login`, `send_verification_email`, etc.
|
|
@@ -69,12 +69,12 @@ pip install fastapi-fullauth[all]
|
|
|
69
69
|
```python
|
|
70
70
|
from fastapi import FastAPI
|
|
71
71
|
from fastapi_fullauth import FullAuth, FullAuthConfig
|
|
72
|
-
from fastapi_fullauth.adapters.
|
|
72
|
+
from fastapi_fullauth.adapters.sqlmodel import SQLModelAdapter
|
|
73
73
|
|
|
74
74
|
app = FastAPI()
|
|
75
75
|
|
|
76
76
|
fullauth = FullAuth(
|
|
77
|
-
adapter=
|
|
77
|
+
adapter=SQLModelAdapter(session_maker=session_maker, user_model=User),
|
|
78
78
|
config=FullAuthConfig(SECRET_KEY="your-secret-key"),
|
|
79
79
|
)
|
|
80
80
|
fullauth.init_app(app)
|
|
@@ -211,26 +211,28 @@ async def editor_panel(user=Depends(require_role("editor"))):
|
|
|
211
211
|
## OAuth2 social login
|
|
212
212
|
|
|
213
213
|
```python
|
|
214
|
+
from fastapi_fullauth import FullAuth, FullAuthConfig
|
|
215
|
+
from fastapi_fullauth.oauth.google import GoogleOAuthProvider
|
|
216
|
+
from fastapi_fullauth.oauth.github import GitHubOAuthProvider
|
|
217
|
+
|
|
214
218
|
fullauth = FullAuth(
|
|
215
219
|
adapter=adapter,
|
|
216
|
-
config=FullAuthConfig(
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
"google"
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
"
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
"github"
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
},
|
|
233
|
-
),
|
|
220
|
+
config=FullAuthConfig(SECRET_KEY="..."),
|
|
221
|
+
providers=[
|
|
222
|
+
GoogleOAuthProvider(
|
|
223
|
+
client_id="your-google-client-id",
|
|
224
|
+
client_secret="your-google-secret",
|
|
225
|
+
redirect_uris=[
|
|
226
|
+
"http://localhost:3000/auth/callback",
|
|
227
|
+
"https://myapp.com/auth/callback",
|
|
228
|
+
],
|
|
229
|
+
),
|
|
230
|
+
GitHubOAuthProvider(
|
|
231
|
+
client_id="your-github-client-id",
|
|
232
|
+
client_secret="your-github-secret",
|
|
233
|
+
redirect_uris=["http://localhost:3000/auth/callback"],
|
|
234
|
+
),
|
|
235
|
+
],
|
|
234
236
|
)
|
|
235
237
|
```
|
|
236
238
|
|
|
@@ -274,6 +276,15 @@ fullauth = FullAuth(
|
|
|
274
276
|
|
|
275
277
|
See [Configuration docs](https://mdfarhankc.github.io/fastapi-fullauth/configuration/) for all options.
|
|
276
278
|
|
|
279
|
+
## AI-friendly docs
|
|
280
|
+
|
|
281
|
+
Using an AI coding assistant? Point it at our LLM-optimized docs:
|
|
282
|
+
|
|
283
|
+
- **[llms.txt](https://mdfarhankc.github.io/fastapi-fullauth/llms.txt)** — concise overview with links to all doc pages
|
|
284
|
+
- **[llms-full.txt](https://mdfarhankc.github.io/fastapi-fullauth/llms-full.txt)** — full documentation in a single file
|
|
285
|
+
|
|
286
|
+
Works with Claude, Cursor, Copilot, and any tool that accepts a docs URL.
|
|
287
|
+
|
|
277
288
|
## Development
|
|
278
289
|
|
|
279
290
|
```bash
|
|
@@ -283,7 +294,6 @@ uv sync --dev --extra sqlalchemy --extra sqlmodel
|
|
|
283
294
|
uv run pytest tests/ -v
|
|
284
295
|
|
|
285
296
|
# run examples
|
|
286
|
-
uv run uvicorn examples.memory_app.main:app --reload
|
|
287
297
|
uv run uvicorn examples.sqlmodel_app.main:app --reload
|
|
288
298
|
```
|
|
289
299
|
|
|
@@ -8,13 +8,11 @@ Adapters are the database layer for fastapi-fullauth. They implement `AbstractUs
|
|
|
8
8
|
|---------|---------|---------|
|
|
9
9
|
| [SQLModel](sqlmodel.md) | Any SQLAlchemy-supported DB | `pip install fastapi-fullauth[sqlmodel]` |
|
|
10
10
|
| [SQLAlchemy](sqlalchemy.md) | Any SQLAlchemy-supported DB | `pip install fastapi-fullauth[sqlalchemy]` |
|
|
11
|
-
| [In-Memory](memory.md) | Python dicts | Included (no extras) |
|
|
12
11
|
|
|
13
12
|
## Choosing an adapter
|
|
14
13
|
|
|
15
|
-
- **SQLModel** — recommended for most projects. Clean model definitions, good type support.
|
|
14
|
+
- **SQLModel** — recommended for most projects. Clean model definitions, good type support. Use SQLite for prototyping.
|
|
16
15
|
- **SQLAlchemy** — use if your project already uses SQLAlchemy's declarative base.
|
|
17
|
-
- **In-Memory** — for testing and prototyping only. Data is lost on restart.
|
|
18
16
|
|
|
19
17
|
## Custom adapters
|
|
20
18
|
|
|
@@ -39,11 +37,23 @@ class MongoAdapter(AbstractUserAdapter):
|
|
|
39
37
|
|
|
40
38
|
See the [source of AbstractUserAdapter](https://github.com/mdfarhankc/fastapi-fullauth/blob/main/fastapi_fullauth/adapters/base.py) for the full interface.
|
|
41
39
|
|
|
42
|
-
##
|
|
40
|
+
## Custom schemas
|
|
43
41
|
|
|
44
|
-
|
|
42
|
+
Define your own user schemas by extending `UserSchema` and `CreateUserSchema`, then pass them to the adapter:
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
```python
|
|
45
|
+
from fastapi_fullauth import UserSchema, CreateUserSchema
|
|
46
|
+
|
|
47
|
+
class MyUserSchema(UserSchema):
|
|
48
|
+
display_name: str = ""
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
class MyCreateSchema(CreateUserSchema):
|
|
51
|
+
display_name: str = ""
|
|
52
|
+
|
|
53
|
+
adapter = SQLModelAdapter(
|
|
54
|
+
session_maker=session_maker,
|
|
55
|
+
user_model=User,
|
|
56
|
+
user_schema=MyUserSchema,
|
|
57
|
+
create_user_schema=MyCreateSchema,
|
|
58
|
+
)
|
|
59
|
+
```
|
|
@@ -12,10 +12,9 @@ from fastapi_fullauth import FullAuth, FullAuthConfig
|
|
|
12
12
|
fullauth = FullAuth(
|
|
13
13
|
adapter=adapter, # required — database adapter
|
|
14
14
|
config=FullAuthConfig(...), # FullAuthConfig object (see Configuration)
|
|
15
|
+
providers=None, # list of OAuthProvider instances
|
|
15
16
|
backends=None, # [BearerBackend()] by default
|
|
16
17
|
password_validator=None, # PasswordValidator instance
|
|
17
|
-
include_user_in_login=False, # include user data in login response
|
|
18
|
-
create_user_schema=None, # custom registration schema
|
|
19
18
|
on_create_token_claims=None, # async callback for custom JWT claims
|
|
20
19
|
)
|
|
21
20
|
```
|
|
@@ -66,14 +65,22 @@ from fastapi_fullauth.types import (
|
|
|
66
65
|
|
|
67
66
|
```python
|
|
68
67
|
class UserSchema(BaseModel):
|
|
69
|
-
id:
|
|
68
|
+
id: UUID
|
|
70
69
|
email: EmailStr
|
|
71
70
|
is_active: bool = True
|
|
72
71
|
is_verified: bool = False
|
|
73
72
|
is_superuser: bool = False
|
|
74
73
|
roles: list[str] = []
|
|
74
|
+
|
|
75
|
+
PROTECTED_FIELDS: ClassVar[set[str]] = {
|
|
76
|
+
"id", "email", "hashed_password", "is_active",
|
|
77
|
+
"is_verified", "is_superuser", "roles", "password",
|
|
78
|
+
"created_at", "refresh_tokens",
|
|
79
|
+
}
|
|
75
80
|
```
|
|
76
81
|
|
|
82
|
+
Extend `PROTECTED_FIELDS` in subclasses to protect custom sensitive fields from profile updates.
|
|
83
|
+
|
|
77
84
|
### TokenPair
|
|
78
85
|
|
|
79
86
|
```python
|
|
@@ -84,6 +91,10 @@ class TokenPair(BaseModel):
|
|
|
84
91
|
expires_in: int | None = None
|
|
85
92
|
```
|
|
86
93
|
|
|
94
|
+
### LoginResponse
|
|
95
|
+
|
|
96
|
+
Returned by login and OAuth callback routes. Extends `TokenPair` with an optional `user` field. The `user` field contains the full user schema object when `INCLUDE_USER_IN_LOGIN=True`, otherwise `null`. The user type matches your configured user schema (e.g., `MyUserSchema`).
|
|
97
|
+
|
|
87
98
|
### TokenPayload
|
|
88
99
|
|
|
89
100
|
```python
|
|
@@ -64,6 +64,9 @@ Pass config inline or as an object:
|
|
|
64
64
|
| Option | Type | Default | Description |
|
|
65
65
|
|--------|------|---------|-------------|
|
|
66
66
|
| `LOGIN_FIELD` | `str` | `"email"` | Field used for login (`"email"`, `"username"`, etc.). |
|
|
67
|
+
| `INCLUDE_USER_IN_LOGIN` | `bool` | `False` | Include user object in login/OAuth callback response. |
|
|
68
|
+
| `LOCKOUT_ENABLED` | `bool` | `True` | Enable account lockout after failed login attempts. |
|
|
69
|
+
| `LOCKOUT_BACKEND` | `"memory" \| "redis"` | `"memory"` | Lockout storage backend. Use `"redis"` for multi-worker deployments. |
|
|
67
70
|
| `MAX_LOGIN_ATTEMPTS` | `int` | `5` | Failed attempts before account lockout. |
|
|
68
71
|
| `LOCKOUT_DURATION_MINUTES` | `int` | `15` | Lockout duration after max attempts. |
|
|
69
72
|
|
|
@@ -115,7 +118,6 @@ Pass config inline or as an object:
|
|
|
115
118
|
|
|
116
119
|
| Option | Type | Default | Description |
|
|
117
120
|
|--------|------|---------|-------------|
|
|
118
|
-
| `OAUTH_PROVIDERS` | `dict` | `{}` | OAuth provider configurations. See [OAuth2](oauth.md). |
|
|
119
121
|
| `OAUTH_STATE_EXPIRE_SECONDS` | `int` | `300` | OAuth state token TTL (5 min). |
|
|
120
122
|
| `OAUTH_AUTO_LINK_BY_EMAIL` | `bool` | `True` | Auto-link OAuth accounts to existing users by email. |
|
|
121
123
|
|
|
@@ -138,10 +138,13 @@ Response:
|
|
|
138
138
|
"access_token": "eyJ...",
|
|
139
139
|
"refresh_token": "eyJ...",
|
|
140
140
|
"token_type": "bearer",
|
|
141
|
-
"expires_in": 1800
|
|
141
|
+
"expires_in": 1800,
|
|
142
|
+
"user": null
|
|
142
143
|
}
|
|
143
144
|
```
|
|
144
145
|
|
|
146
|
+
When `INCLUDE_USER_IN_LOGIN=True`, `user` contains the full user object instead of `null`.
|
|
147
|
+
|
|
145
148
|
**Get current user:**
|
|
146
149
|
|
|
147
150
|
```bash
|
|
@@ -35,7 +35,7 @@ Add a complete authentication and authorization system to your **FastAPI** proje
|
|
|
35
35
|
- **Role-based access control** — `CurrentUser`, `VerifiedUser`, `SuperUser`, `require_role()`
|
|
36
36
|
- **Rate limiting** — per-route auth limits + global middleware (memory or Redis)
|
|
37
37
|
- **CSRF protection** and **security headers** middleware
|
|
38
|
-
- **Pluggable adapters** — SQLModel
|
|
38
|
+
- **Pluggable adapters** — SQLModel or SQLAlchemy
|
|
39
39
|
- **Generic type parameters** — define your own schemas with full IDE support and type safety
|
|
40
40
|
- **Composable routers** — include only the route groups you need
|
|
41
41
|
- **Event hooks** — `after_register`, `after_login`, `send_verification_email`, etc.
|
|
@@ -67,12 +67,12 @@ pip install fastapi-fullauth[all]
|
|
|
67
67
|
```python
|
|
68
68
|
from fastapi import FastAPI
|
|
69
69
|
from fastapi_fullauth import FullAuth, FullAuthConfig
|
|
70
|
-
from fastapi_fullauth.adapters.
|
|
70
|
+
from fastapi_fullauth.adapters.sqlmodel import SQLModelAdapter
|
|
71
71
|
|
|
72
72
|
app = FastAPI()
|
|
73
73
|
|
|
74
74
|
fullauth = FullAuth(
|
|
75
|
-
adapter=
|
|
75
|
+
adapter=SQLModelAdapter(session_maker=session_maker, user_model=User),
|
|
76
76
|
config=FullAuthConfig(
|
|
77
77
|
SECRET_KEY="your-secret-key",
|
|
78
78
|
),
|
|
@@ -138,6 +138,15 @@ With OAuth enabled, additional routes are registered under `/auth/oauth/`. See [
|
|
|
138
138
|
|
|
139
139
|
All routes are prefixed with `/api/v1` by default (configurable via `API_PREFIX`).
|
|
140
140
|
|
|
141
|
+
## AI-friendly docs
|
|
142
|
+
|
|
143
|
+
Using an AI coding assistant? Point it at our LLM-optimized docs:
|
|
144
|
+
|
|
145
|
+
- **[llms.txt](llms.txt)** — concise overview with links to all doc pages
|
|
146
|
+
- **[llms-full.txt](llms-full.txt)** — full documentation in a single file
|
|
147
|
+
|
|
148
|
+
Works with Claude, Cursor, Copilot, and any tool that accepts a docs URL.
|
|
149
|
+
|
|
141
150
|
## License
|
|
142
151
|
|
|
143
152
|
MIT
|