fastapi-startkit-auth 0.3.0__tar.gz → 0.6.1__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_startkit_auth-0.6.1/CHANGELOG.md +147 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/PKG-INFO +125 -17
- fastapi_startkit_auth-0.3.0/readme.md → fastapi_startkit_auth-0.6.1/README.md +118 -12
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/pyproject.toml +14 -7
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/__init__.py +103 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/apitokens/__init__.py +0 -2
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/apitokens/manager.py +83 -20
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/apitokens/orm.py +96 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/clients/models.py +4 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/clients/repository.py +2 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/concurrency.py +48 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/config.py +12 -6
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/dependencies.py +8 -7
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/facade.py +81 -5
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/grants/__init__.py +17 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/grants/authorization_code.py +164 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/grants/client_credentials.py +11 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/grants/password.py +67 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/grants/refresh.py +70 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/guards/__init__.py +14 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/guards/guard.py +40 -13
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/guards/session.py +132 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/guards/token.py +91 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/manager.py +153 -67
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/middleware/session.py +5 -8
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/orm.py +105 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/passwords/__init__.py +4 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/passwords/broker.py +131 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/provider.py +17 -1
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/providers/base.py +118 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/providers/fields.py +35 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/providers/memory.py +9 -1
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/providers/model.py +136 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/publishable/migrations/2026_09_30_000001_create_sessions_table.py +17 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/publishable/migrations/2026_09_30_000002_create_personal_api_tokens_table.py +18 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/publishable/migrations/2026_09_30_000003_create_oauth_access_tokens_table.py +20 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/publishable/migrations/2026_09_30_000004_create_oauth_refresh_tokens_table.py +18 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/publishable/migrations/2026_09_30_000005_create_oauth_auth_codes_table.py +17 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/routes.py +34 -28
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/routes_spa.py +4 -2
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/sessions/__init__.py +1 -2
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/sessions/orm.py +102 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/startkit.py +3 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/tokens/orm.py +212 -0
- fastapi_startkit_auth-0.6.1/src/fastapi_startkit_auth/tokens/service.py +316 -0
- fastapi_startkit_auth-0.6.1/tests/conftest.py +165 -0
- fastapi_startkit_auth-0.6.1/tests/test_api_tokens.py +464 -0
- fastapi_startkit_auth-0.6.1/tests/test_async_auth.py +443 -0
- fastapi_startkit_auth-0.6.1/tests/test_async_safety.py +496 -0
- fastapi_startkit_auth-0.6.1/tests/test_async_stores.py +200 -0
- fastapi_startkit_auth-0.6.1/tests/test_clients.py +58 -0
- fastapi_startkit_auth-0.6.1/tests/test_grants.py +130 -0
- fastapi_startkit_auth-0.6.1/tests/test_guard_registry.py +71 -0
- fastapi_startkit_auth-0.6.1/tests/test_hashing.py +34 -0
- fastapi_startkit_auth-0.6.1/tests/test_integration.py +214 -0
- fastapi_startkit_auth-0.6.1/tests/test_jwt.py +57 -0
- fastapi_startkit_auth-0.6.1/tests/test_manager.py +75 -0
- fastapi_startkit_auth-0.6.1/tests/test_model_provider.py +69 -0
- fastapi_startkit_auth-0.6.1/tests/test_multi_provider.py +231 -0
- fastapi_startkit_auth-0.6.1/tests/test_password_reset.py +88 -0
- fastapi_startkit_auth-0.6.1/tests/test_reset_throttle_enumeration.py +43 -0
- fastapi_startkit_auth-0.6.1/tests/test_security_fixes.py +159 -0
- fastapi_startkit_auth-0.6.1/tests/test_session_auth.py +352 -0
- fastapi_startkit_auth-0.6.1/tests/test_session_store.py +132 -0
- fastapi_startkit_auth-0.6.1/tests/test_spa_csrf.py +320 -0
- fastapi_startkit_auth-0.6.1/tests/test_startkit_provider.py +131 -0
- fastapi_startkit_auth-0.6.1/tests/test_sync_regression.py +202 -0
- fastapi_startkit_auth-0.6.1/tests/test_token_repository.py +56 -0
- fastapi_startkit_auth-0.6.1/tests/test_token_service.py +110 -0
- fastapi_startkit_auth-0.6.1/tests/test_user_provider.py +76 -0
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/__init__.py +0 -67
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/apitokens/sql.py +0 -152
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/grants/__init__.py +0 -13
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/grants/authorization_code.py +0 -83
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/grants/password.py +0 -32
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/grants/refresh.py +0 -13
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/guards/__init__.py +0 -5
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/guards/session.py +0 -81
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/guards/token.py +0 -58
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/passwords/__init__.py +0 -4
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/passwords/broker.py +0 -69
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/providers/base.py +0 -38
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/providers/model.py +0 -70
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/sessions/sql.py +0 -158
- fastapi_startkit_auth-0.3.0/src/fastapi_startkit_auth/tokens/service.py +0 -189
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/LICENSE +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/apitokens/models.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/apitokens/repository.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/application.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/clients/__init__.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/exceptions.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/grants/pkce.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/middleware/__init__.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/middleware/csrf.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/passwords/repository.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/providers/__init__.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/publishable/cors.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/py.typed +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/security/__init__.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/security/hashing.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/security/jwt.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/sessions/models.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/sessions/state.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/sessions/store.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/tokens/__init__.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/tokens/models.py +0 -0
- {fastapi_startkit_auth-0.3.0 → fastapi_startkit_auth-0.6.1}/src/fastapi_startkit_auth/tokens/repository.py +0 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `fastapi-startkit-auth` are documented in this file.
|
|
4
|
+
|
|
5
|
+
Release notes are also published on
|
|
6
|
+
[GitHub Releases](https://github.com/fastapi-startkit/fastapi-startkit-auth/releases).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Breaking:** persistence now goes through the fastapi-startkit ORM with models
|
|
13
|
+
shipped in `fastapi_startkit_auth.orm`; no raw SQL remains. Use
|
|
14
|
+
`{"store": "orm"}` (optional ORM `connection` name) for sessions, API tokens and
|
|
15
|
+
OAuth tokens.
|
|
16
|
+
- **Breaking:** the `startkit` extra now requires `fastapi-startkit[database]>=0.60`.
|
|
17
|
+
- Run the published migrations (`provider:publish -p auth`, then `migrate`) to
|
|
18
|
+
create the tables; stores no longer create tables themselves.
|
|
19
|
+
|
|
20
|
+
### Removed
|
|
21
|
+
|
|
22
|
+
- **Breaking:** the `sql` / `async_sql` stores and the `SqlSessionStore`,
|
|
23
|
+
`SqlApiTokenRepository`, `AsyncSql*` classes and database adapters.
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- `Client.provider` (and `register(provider=...)`) binds an OAuth client to a
|
|
28
|
+
user provider. `AuthManager.owner_provider(client_id)` resolves it, falling
|
|
29
|
+
back to the default guard's provider.
|
|
30
|
+
- `AuthManager.warm_up()` and `AsyncModelUserProvider.warm_up()`, run from the
|
|
31
|
+
app lifespan by `AuthProvider`, precompute the dummy hash at startup.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- Refresh, authorization-code exchange and introspection re-check the token
|
|
36
|
+
owner against the provider of the issuing client instead of always using the
|
|
37
|
+
default guard's provider. The password grant authenticates against the
|
|
38
|
+
client's provider, and `/oauth/authorize` rejects a client bound to another
|
|
39
|
+
provider.
|
|
40
|
+
- `AsyncModelUserProvider.is_active` only uses the threadpool for a sync
|
|
41
|
+
callable hook. Attribute checks and `async def` hooks run inline.
|
|
42
|
+
- The first unknown-user login no longer pays an extra bcrypt hash to create
|
|
43
|
+
the dummy hash.
|
|
44
|
+
|
|
45
|
+
## [0.4.0]
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
|
|
49
|
+
- Async support for async ORMs and drivers, side by side with the sync API:
|
|
50
|
+
- `AsyncModelUserProvider` (provider driver `"async_model"`) for models whose
|
|
51
|
+
`find` / `where(...).first()` / `save` are coroutines; bcrypt runs in a
|
|
52
|
+
worker thread.
|
|
53
|
+
- `AsyncPassportGuard`, `AsyncSessionGuard`, `AsyncTokenGuard`,
|
|
54
|
+
`AsyncTokenService`, `AsyncApiTokenManager`, `AsyncPasswordBroker`, the
|
|
55
|
+
`Async*Grant` variants and the `AsyncAuth` facade.
|
|
56
|
+
- `AuthManager` picks the async variant automatically when any provider
|
|
57
|
+
method or store method is async; sync configurations keep getting the sync
|
|
58
|
+
classes. Sync collaborators used from the async classes run in the
|
|
59
|
+
threadpool.
|
|
60
|
+
- `"async_sql"` stores for sessions (`AsyncSqlSessionStore`), personal API
|
|
61
|
+
tokens (`AsyncSqlApiTokenRepository`) and a new `AuthConfig.tokens` block
|
|
62
|
+
for OAuth access/refresh tokens and authorization codes
|
|
63
|
+
(`AsyncSqlTokenRepository`). They accept an asyncpg pool/connection, an
|
|
64
|
+
aiosqlite connection, or a zero-arg (async) factory. Supported backends are
|
|
65
|
+
PostgreSQL and SQLite. Refresh tokens and authorization codes are stored as
|
|
66
|
+
SHA-256 hashes; refresh revocation and code redemption are atomic and use
|
|
67
|
+
only portable SQL. Expired rows are purged via `expires_at` indexes.
|
|
68
|
+
- `fastapi-startkit` migrations for the five tables, published to
|
|
69
|
+
`databases/migrations/` by `AuthServiceProvider`.
|
|
70
|
+
- `password_key` provider option: the credentials key holding the plaintext
|
|
71
|
+
password, separate from the model column `password_field` (e.g.
|
|
72
|
+
`password_key="password"`, `password_field="hashed_password"`). Defaults to
|
|
73
|
+
`password_field`.
|
|
74
|
+
- `is_active` provider option (attribute name or callable; `async def` with
|
|
75
|
+
the `async_model` driver). Inactive or deleted users are rejected by the
|
|
76
|
+
password grant, the refresh and authorization-code grants, `Auth.attempt` /
|
|
77
|
+
`AsyncAuth.attempt` and every guard, and introspect as inactive.
|
|
78
|
+
- `AsyncMisconfiguration`: raised when a sync guard, grant, broker or `Auth`
|
|
79
|
+
receives an awaitable from a provider or store, so a half-async provider
|
|
80
|
+
fails closed. Sync providers reject an `async def` `is_active` hook.
|
|
81
|
+
- CI runs the asyncpg store and flow tests against a Postgres service.
|
|
82
|
+
- `Typing :: Typed` classifier (the package already ships `py.typed`).
|
|
83
|
+
|
|
84
|
+
### Changed
|
|
85
|
+
|
|
86
|
+
- **Breaking (signature):** `current_context` and `optional_user` are now
|
|
87
|
+
`async def` dependencies. `Depends(current_user)` and friends keep working
|
|
88
|
+
unchanged; code calling them directly as plain functions must now await
|
|
89
|
+
them. Sync guards still run in the threadpool.
|
|
90
|
+
- The built-in OAuth, password-reset and SPA csrf-cookie routes await async
|
|
91
|
+
collaborators; `SessionMiddleware` accepts an async session store.
|
|
92
|
+
- `Auth` (sync facade) raises `RuntimeError` for async session guards; use
|
|
93
|
+
`AsyncAuth` there.
|
|
94
|
+
- Minimum supported Python is now 3.10. 0.3.0 advertised `>=3.9` but fails on
|
|
95
|
+
3.9 because runtime-evaluated annotations use `X | None` syntax.
|
|
96
|
+
- The `startkit` extra is bounded to `fastapi-startkit>=0.51,<1.0`.
|
|
97
|
+
- The package `__init__` imports its public API directly instead of through a
|
|
98
|
+
lazy export table.
|
|
99
|
+
- The source distribution now ships the test suite and this changelog.
|
|
100
|
+
- `bin/release.sh` uploads to PyPI with `twine upload`, matching
|
|
101
|
+
fastapi-startkit; the tag-triggered trusted-publishing workflow is removed.
|
|
102
|
+
|
|
103
|
+
## [0.3.0]
|
|
104
|
+
|
|
105
|
+
First release published to PyPI. Contains the 0.2.0 feature set, built with
|
|
106
|
+
the `uv_build` backend; no functional changes.
|
|
107
|
+
|
|
108
|
+
## [0.2.0]
|
|
109
|
+
|
|
110
|
+
Adds three new authentication modes alongside the existing OAuth2/JWT server,
|
|
111
|
+
so the package now covers the full Laravel-style auth surface.
|
|
112
|
+
|
|
113
|
+
### Added
|
|
114
|
+
|
|
115
|
+
- Guard-driver registry in `AuthManager`: guards resolve their driver
|
|
116
|
+
(`token`, `session`, …) from a pluggable registry, enabling multiple guard
|
|
117
|
+
types in one application (Phase 0).
|
|
118
|
+
- Cookie/session authentication: `Auth` facade, `SessionGuard`, session
|
|
119
|
+
middleware, and in-memory + SQL session stores (Phase 1).
|
|
120
|
+
- SPA authentication with CSRF protection: `/__auth__/csrf-cookie` endpoint,
|
|
121
|
+
double-submit-cookie middleware, and an `AuthServiceProvider` that publishes
|
|
122
|
+
the `config/cors.py` stub via `provider:publish -p auth` (Phase 2).
|
|
123
|
+
- Sanctum-style API tokens: `TokenGuard`, opaque hashed tokens with abilities,
|
|
124
|
+
and in-memory + SQL token stores (Phase 3).
|
|
125
|
+
|
|
126
|
+
### Security / Hardening
|
|
127
|
+
|
|
128
|
+
- Session guard verifies against a constant-time dummy hash when no user is
|
|
129
|
+
found, closing a timing side-channel.
|
|
130
|
+
- SQL session and API-token stores prune expired rows; purge cadence is
|
|
131
|
+
configurable.
|
|
132
|
+
- CSRF cookie endpoint hardened; token repr for `NewApiToken` redacts the
|
|
133
|
+
plaintext value so it cannot leak into logs.
|
|
134
|
+
- DB-API connection vs. connection-factory detection now probes `execute()`
|
|
135
|
+
instead of `callable()`, fixing misdetection of raw `sqlite3.Connection`
|
|
136
|
+
objects in the SQL session and API-token stores.
|
|
137
|
+
|
|
138
|
+
## [0.1.0]
|
|
139
|
+
|
|
140
|
+
Initial release.
|
|
141
|
+
|
|
142
|
+
- Passport-style OAuth2 authorization server for FastAPI: authorization code
|
|
143
|
+
(with PKCE), password, client credentials, and refresh token grants
|
|
144
|
+
- JWT access tokens with scopes, token guards, and route dependencies
|
|
145
|
+
- Personal access tokens
|
|
146
|
+
- Pluggable user/client providers (in-memory and Masonite ORM)
|
|
147
|
+
- Password reset flow with throttling hardened against account enumeration
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-startkit-auth
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: Laravel-style authentication for FastAPI: OAuth2/JWT authorization server, cookie/session guard, SPA + CSRF protection, and Sanctum-style API tokens.
|
|
5
5
|
Keywords: fastapi,oauth2,jwt,auth,passport,sanctum,authentication,authorization,security,tokens,session,cookie,csrf,spa,starter-kit
|
|
6
6
|
Author: Bedram Tamang
|
|
@@ -12,7 +12,6 @@ Classifier: Framework :: FastAPI
|
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -20,21 +19,24 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
20
19
|
Classifier: Topic :: Internet :: WWW/HTTP :: Session
|
|
21
20
|
Classifier: Topic :: Security
|
|
22
21
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
23
|
Requires-Dist: fastapi>=0.110
|
|
24
24
|
Requires-Dist: pyjwt>=2.8
|
|
25
25
|
Requires-Dist: bcrypt>=4.1
|
|
26
26
|
Requires-Dist: pydantic>=2
|
|
27
27
|
Requires-Dist: python-multipart>=0.0.9
|
|
28
28
|
Requires-Dist: masonite-orm>=2.18 ; extra == 'masoniteorm'
|
|
29
|
-
Requires-Dist: fastapi-startkit>=0.
|
|
29
|
+
Requires-Dist: fastapi-startkit[database]>=0.60,<1.0 ; python_full_version >= '3.12' and extra == 'startkit'
|
|
30
30
|
Requires-Dist: pytest>=8 ; extra == 'test'
|
|
31
31
|
Requires-Dist: pytest-asyncio>=0.23 ; extra == 'test'
|
|
32
32
|
Requires-Dist: httpx>=0.27 ; extra == 'test'
|
|
33
|
-
Requires-
|
|
33
|
+
Requires-Dist: aiosqlite>=0.20 ; extra == 'test'
|
|
34
|
+
Requires-Dist: asyncpg>=0.29 ; extra == 'test'
|
|
35
|
+
Requires-Python: >=3.10
|
|
34
36
|
Project-URL: Homepage, https://github.com/fastapi-startkit/fastapi-startkit-auth
|
|
35
37
|
Project-URL: Repository, https://github.com/fastapi-startkit/fastapi-startkit-auth
|
|
36
38
|
Project-URL: Issues, https://github.com/fastapi-startkit/fastapi-startkit-auth/issues
|
|
37
|
-
Project-URL: Changelog, https://github.com/fastapi-startkit/fastapi-startkit-auth/
|
|
39
|
+
Project-URL: Changelog, https://github.com/fastapi-startkit/fastapi-startkit-auth/blob/main/CHANGELOG.md
|
|
38
40
|
Provides-Extra: masoniteorm
|
|
39
41
|
Provides-Extra: startkit
|
|
40
42
|
Provides-Extra: test
|
|
@@ -67,12 +69,29 @@ OAuth2 grants and signed JWT access tokens (per the
|
|
|
67
69
|
|
|
68
70
|
## Installation
|
|
69
71
|
|
|
72
|
+
Requires Python 3.10+.
|
|
73
|
+
|
|
70
74
|
```bash
|
|
71
75
|
pip install fastapi-startkit-auth
|
|
72
|
-
#
|
|
76
|
+
# or
|
|
77
|
+
uv add fastapi-startkit-auth
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Optional extras:
|
|
81
|
+
|
|
82
|
+
| Extra | Installs | Use when |
|
|
83
|
+
| --- | --- | --- |
|
|
84
|
+
| `startkit` | `fastapi-startkit[database]>=0.60,<1.0` (Python 3.12+) | Registering `AuthServiceProvider`, publishing its config stub and migrations via `provider:publish -p auth`, and the `"orm"` stores |
|
|
85
|
+
| `masoniteorm` | `masonite-orm` | Using the `masoniteorm` user provider driver |
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install "fastapi-startkit-auth[startkit]"
|
|
73
89
|
pip install "fastapi-startkit-auth[masoniteorm]"
|
|
74
90
|
```
|
|
75
91
|
|
|
92
|
+
The `startkit` and `masoniteorm` extras are mutually exclusive: `masonite-orm`
|
|
93
|
+
pins `cleo<2` while `fastapi-startkit` requires `cleo>=2.1`.
|
|
94
|
+
|
|
76
95
|
> Uses `bcrypt` directly (not `passlib`, which imports the `crypt` stdlib module
|
|
77
96
|
> removed in Python 3.13+), so it runs on modern Python.
|
|
78
97
|
|
|
@@ -144,13 +163,94 @@ class AuthConfig:
|
|
|
144
163
|
| driver | meaning |
|
|
145
164
|
| --- | --- |
|
|
146
165
|
| `masoniteorm` / `orm` / `model` | wrap a model exposing `find(id)` and `where(field, value).first()` |
|
|
166
|
+
| `async_model` | same, for async ORMs where `find`, `first()` and `save()` are coroutines |
|
|
147
167
|
| `memory` | in-memory dict store (`users=[...]`) — great for tests/demos |
|
|
148
168
|
| `instance` | pass a ready `UserProvider` via `{"instance": ...}` |
|
|
149
169
|
| `factory` | pass a zero-arg callable returning a `UserProvider` |
|
|
150
170
|
|
|
151
171
|
Any object implementing the `UserProvider` protocol
|
|
152
172
|
(`retrieve_by_id`, `retrieve_by_credentials`, `validate_credentials`,
|
|
153
|
-
`get_identifier`, `update_password`) is a valid provider.
|
|
173
|
+
`get_identifier`, `update_password`) is a valid provider. Any of its methods
|
|
174
|
+
may be `async def`; one async method is enough for `AuthManager` to pick the
|
|
175
|
+
async guards, grants and broker. The sync classes refuse an awaitable result
|
|
176
|
+
with `AsyncMisconfiguration` instead of treating it as truthy.
|
|
177
|
+
|
|
178
|
+
Model-backed providers also accept `password_key` (the credentials key holding
|
|
179
|
+
the plaintext password, default: `password_field`) and `is_active` (a boolean
|
|
180
|
+
attribute name or a `callable(user) -> bool`; inactive users cannot log in,
|
|
181
|
+
authenticate, refresh or exchange a code, and introspect as inactive). The
|
|
182
|
+
`async_model` driver also takes an `async def` hook; the sync drivers reject
|
|
183
|
+
one at construction:
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
providers = {
|
|
187
|
+
"users": {
|
|
188
|
+
"driver": "async_model",
|
|
189
|
+
"model": User,
|
|
190
|
+
"password_field": "hashed_password",
|
|
191
|
+
"password_key": "password",
|
|
192
|
+
"is_active": "is_active",
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Multiple providers
|
|
198
|
+
|
|
199
|
+
With more than one provider, register each OAuth client with the provider whose
|
|
200
|
+
users it serves (Laravel Passport's `provider` column). The password grant then
|
|
201
|
+
authenticates against that provider, and refresh, code exchange and
|
|
202
|
+
introspection re-check the token owner against it. A client without a
|
|
203
|
+
`provider` uses the default guard's provider, and `/oauth/authorize` rejects a
|
|
204
|
+
client bound to a different provider with `unauthorized_client`:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
client, secret = manager.client_repository.register(name="admin-panel", provider="admins")
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### ORM stores and migrations
|
|
211
|
+
|
|
212
|
+
With an async provider or store, `AuthManager` builds the async guards, grants,
|
|
213
|
+
token service and password broker automatically (use the `AsyncAuth` facade for
|
|
214
|
+
session login/logout). Sessions, API tokens and OAuth tokens persist through the
|
|
215
|
+
fastapi-startkit ORM (`pip install "fastapi-startkit-auth[startkit]"`, which pulls
|
|
216
|
+
in `fastapi-startkit[database]`). The package ships its own models
|
|
217
|
+
(`fastapi_startkit_auth.orm`) and uses no raw SQL:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
session = {"store": "orm"}
|
|
221
|
+
api_tokens = {"store": "orm"}
|
|
222
|
+
tokens = {"store": "orm", "connection": "auth"} # optional ORM connection name
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
`connection` names an entry of your database config; omit it to use the default
|
|
226
|
+
connection. Publish and run the migrations once per app (they are reversible
|
|
227
|
+
and create the `sessions`, `personal_api_tokens`, `oauth_access_tokens`,
|
|
228
|
+
`oauth_refresh_tokens` and `oauth_auth_codes` tables with their indexes):
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
python artisan provider:publish -p auth # copies them to databases/migrations/
|
|
232
|
+
python artisan migrate
|
|
233
|
+
python artisan migrate:rollback # drops them again
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Single-use guarantees rely on conditional `UPDATE`/`DELETE` statements issued
|
|
237
|
+
through the ORM query builder: refresh-token rotation and authorization-code
|
|
238
|
+
redemption each have exactly one winner under concurrency.
|
|
239
|
+
|
|
240
|
+
The former `sql` and `async_sql` stores were removed; configuring them raises a
|
|
241
|
+
`ValueError` pointing at `"orm"`. Use `"memory"` or an `"instance"` store for
|
|
242
|
+
sync setups.
|
|
243
|
+
|
|
244
|
+
In mixed setups (async stores with a sync provider or a sync session store),
|
|
245
|
+
the sync calls — lookups, bcrypt, `is_active` hooks, a sync session store in
|
|
246
|
+
`SessionMiddleware` — run in the threadpool, never on the event loop.
|
|
247
|
+
An `is_active` attribute name or `async def` hook runs inline, since neither
|
|
248
|
+
blocks.
|
|
249
|
+
|
|
250
|
+
`AuthProvider` warms the providers up when the app starts (`await
|
|
251
|
+
manager.warm_up()`), so `AsyncModelUserProvider` computes its dummy hash off the
|
|
252
|
+
event loop before the first request. A login for an unknown user then costs
|
|
253
|
+
one bcrypt verify, the same as a wrong password.
|
|
154
254
|
|
|
155
255
|
## HTTP endpoints
|
|
156
256
|
|
|
@@ -212,15 +312,19 @@ inspect the `AuthContext` (`ctx.can(...)`, `ctx.can_any(...)`, `ctx.scopes`).
|
|
|
212
312
|
## Testing
|
|
213
313
|
|
|
214
314
|
```bash
|
|
215
|
-
|
|
216
|
-
pytest
|
|
315
|
+
uv sync --group dev
|
|
316
|
+
uv run pytest
|
|
317
|
+
uv run ruff check .
|
|
217
318
|
```
|
|
218
319
|
|
|
219
|
-
|
|
320
|
+
The async store and flow tests run on aiosqlite; set `TEST_ASYNCPG_DSN` to a
|
|
321
|
+
disposable Postgres database to also run them on asyncpg (CI does).
|
|
322
|
+
|
|
323
|
+
Or with pip:
|
|
220
324
|
|
|
221
325
|
```bash
|
|
222
|
-
|
|
223
|
-
|
|
326
|
+
pip install -e ".[test]"
|
|
327
|
+
pytest
|
|
224
328
|
```
|
|
225
329
|
|
|
226
330
|
## Releasing
|
|
@@ -232,11 +336,15 @@ Releases are cut from `main` with the release script (maintainers only):
|
|
|
232
336
|
./bin/release.sh minor # or: major
|
|
233
337
|
```
|
|
234
338
|
|
|
235
|
-
The script bumps the version
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
339
|
+
The script bumps the version (`pyproject.toml`, `__version__`, `uv.lock`),
|
|
340
|
+
builds sdist + wheel, validates them with `twine check`, uploads them to PyPI
|
|
341
|
+
with `twine upload`, then commits, tags `vX.Y.Z`, pushes, and creates a GitHub
|
|
342
|
+
release. Move the `Unreleased` notes in `CHANGELOG.md` under the new version
|
|
343
|
+
before running it.
|
|
344
|
+
|
|
345
|
+
It requires `uv`, an authenticated `gh`, and PyPI credentials for twine: either
|
|
346
|
+
a `[pypi]` entry in `~/.pypirc` (`username = __token__`, `password = pypi-...`)
|
|
347
|
+
or `TWINE_USERNAME=__token__` and `TWINE_PASSWORD=pypi-...` in the environment.
|
|
240
348
|
|
|
241
349
|
## License
|
|
242
350
|
|
|
@@ -25,12 +25,29 @@ OAuth2 grants and signed JWT access tokens (per the
|
|
|
25
25
|
|
|
26
26
|
## Installation
|
|
27
27
|
|
|
28
|
+
Requires Python 3.10+.
|
|
29
|
+
|
|
28
30
|
```bash
|
|
29
31
|
pip install fastapi-startkit-auth
|
|
30
|
-
#
|
|
32
|
+
# or
|
|
33
|
+
uv add fastapi-startkit-auth
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Optional extras:
|
|
37
|
+
|
|
38
|
+
| Extra | Installs | Use when |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| `startkit` | `fastapi-startkit[database]>=0.60,<1.0` (Python 3.12+) | Registering `AuthServiceProvider`, publishing its config stub and migrations via `provider:publish -p auth`, and the `"orm"` stores |
|
|
41
|
+
| `masoniteorm` | `masonite-orm` | Using the `masoniteorm` user provider driver |
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install "fastapi-startkit-auth[startkit]"
|
|
31
45
|
pip install "fastapi-startkit-auth[masoniteorm]"
|
|
32
46
|
```
|
|
33
47
|
|
|
48
|
+
The `startkit` and `masoniteorm` extras are mutually exclusive: `masonite-orm`
|
|
49
|
+
pins `cleo<2` while `fastapi-startkit` requires `cleo>=2.1`.
|
|
50
|
+
|
|
34
51
|
> Uses `bcrypt` directly (not `passlib`, which imports the `crypt` stdlib module
|
|
35
52
|
> removed in Python 3.13+), so it runs on modern Python.
|
|
36
53
|
|
|
@@ -102,13 +119,94 @@ class AuthConfig:
|
|
|
102
119
|
| driver | meaning |
|
|
103
120
|
| --- | --- |
|
|
104
121
|
| `masoniteorm` / `orm` / `model` | wrap a model exposing `find(id)` and `where(field, value).first()` |
|
|
122
|
+
| `async_model` | same, for async ORMs where `find`, `first()` and `save()` are coroutines |
|
|
105
123
|
| `memory` | in-memory dict store (`users=[...]`) — great for tests/demos |
|
|
106
124
|
| `instance` | pass a ready `UserProvider` via `{"instance": ...}` |
|
|
107
125
|
| `factory` | pass a zero-arg callable returning a `UserProvider` |
|
|
108
126
|
|
|
109
127
|
Any object implementing the `UserProvider` protocol
|
|
110
128
|
(`retrieve_by_id`, `retrieve_by_credentials`, `validate_credentials`,
|
|
111
|
-
`get_identifier`, `update_password`) is a valid provider.
|
|
129
|
+
`get_identifier`, `update_password`) is a valid provider. Any of its methods
|
|
130
|
+
may be `async def`; one async method is enough for `AuthManager` to pick the
|
|
131
|
+
async guards, grants and broker. The sync classes refuse an awaitable result
|
|
132
|
+
with `AsyncMisconfiguration` instead of treating it as truthy.
|
|
133
|
+
|
|
134
|
+
Model-backed providers also accept `password_key` (the credentials key holding
|
|
135
|
+
the plaintext password, default: `password_field`) and `is_active` (a boolean
|
|
136
|
+
attribute name or a `callable(user) -> bool`; inactive users cannot log in,
|
|
137
|
+
authenticate, refresh or exchange a code, and introspect as inactive). The
|
|
138
|
+
`async_model` driver also takes an `async def` hook; the sync drivers reject
|
|
139
|
+
one at construction:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
providers = {
|
|
143
|
+
"users": {
|
|
144
|
+
"driver": "async_model",
|
|
145
|
+
"model": User,
|
|
146
|
+
"password_field": "hashed_password",
|
|
147
|
+
"password_key": "password",
|
|
148
|
+
"is_active": "is_active",
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Multiple providers
|
|
154
|
+
|
|
155
|
+
With more than one provider, register each OAuth client with the provider whose
|
|
156
|
+
users it serves (Laravel Passport's `provider` column). The password grant then
|
|
157
|
+
authenticates against that provider, and refresh, code exchange and
|
|
158
|
+
introspection re-check the token owner against it. A client without a
|
|
159
|
+
`provider` uses the default guard's provider, and `/oauth/authorize` rejects a
|
|
160
|
+
client bound to a different provider with `unauthorized_client`:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
client, secret = manager.client_repository.register(name="admin-panel", provider="admins")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### ORM stores and migrations
|
|
167
|
+
|
|
168
|
+
With an async provider or store, `AuthManager` builds the async guards, grants,
|
|
169
|
+
token service and password broker automatically (use the `AsyncAuth` facade for
|
|
170
|
+
session login/logout). Sessions, API tokens and OAuth tokens persist through the
|
|
171
|
+
fastapi-startkit ORM (`pip install "fastapi-startkit-auth[startkit]"`, which pulls
|
|
172
|
+
in `fastapi-startkit[database]`). The package ships its own models
|
|
173
|
+
(`fastapi_startkit_auth.orm`) and uses no raw SQL:
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
session = {"store": "orm"}
|
|
177
|
+
api_tokens = {"store": "orm"}
|
|
178
|
+
tokens = {"store": "orm", "connection": "auth"} # optional ORM connection name
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
`connection` names an entry of your database config; omit it to use the default
|
|
182
|
+
connection. Publish and run the migrations once per app (they are reversible
|
|
183
|
+
and create the `sessions`, `personal_api_tokens`, `oauth_access_tokens`,
|
|
184
|
+
`oauth_refresh_tokens` and `oauth_auth_codes` tables with their indexes):
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
python artisan provider:publish -p auth # copies them to databases/migrations/
|
|
188
|
+
python artisan migrate
|
|
189
|
+
python artisan migrate:rollback # drops them again
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Single-use guarantees rely on conditional `UPDATE`/`DELETE` statements issued
|
|
193
|
+
through the ORM query builder: refresh-token rotation and authorization-code
|
|
194
|
+
redemption each have exactly one winner under concurrency.
|
|
195
|
+
|
|
196
|
+
The former `sql` and `async_sql` stores were removed; configuring them raises a
|
|
197
|
+
`ValueError` pointing at `"orm"`. Use `"memory"` or an `"instance"` store for
|
|
198
|
+
sync setups.
|
|
199
|
+
|
|
200
|
+
In mixed setups (async stores with a sync provider or a sync session store),
|
|
201
|
+
the sync calls — lookups, bcrypt, `is_active` hooks, a sync session store in
|
|
202
|
+
`SessionMiddleware` — run in the threadpool, never on the event loop.
|
|
203
|
+
An `is_active` attribute name or `async def` hook runs inline, since neither
|
|
204
|
+
blocks.
|
|
205
|
+
|
|
206
|
+
`AuthProvider` warms the providers up when the app starts (`await
|
|
207
|
+
manager.warm_up()`), so `AsyncModelUserProvider` computes its dummy hash off the
|
|
208
|
+
event loop before the first request. A login for an unknown user then costs
|
|
209
|
+
one bcrypt verify, the same as a wrong password.
|
|
112
210
|
|
|
113
211
|
## HTTP endpoints
|
|
114
212
|
|
|
@@ -170,15 +268,19 @@ inspect the `AuthContext` (`ctx.can(...)`, `ctx.can_any(...)`, `ctx.scopes`).
|
|
|
170
268
|
## Testing
|
|
171
269
|
|
|
172
270
|
```bash
|
|
173
|
-
|
|
174
|
-
pytest
|
|
271
|
+
uv sync --group dev
|
|
272
|
+
uv run pytest
|
|
273
|
+
uv run ruff check .
|
|
175
274
|
```
|
|
176
275
|
|
|
177
|
-
|
|
276
|
+
The async store and flow tests run on aiosqlite; set `TEST_ASYNCPG_DSN` to a
|
|
277
|
+
disposable Postgres database to also run them on asyncpg (CI does).
|
|
278
|
+
|
|
279
|
+
Or with pip:
|
|
178
280
|
|
|
179
281
|
```bash
|
|
180
|
-
|
|
181
|
-
|
|
282
|
+
pip install -e ".[test]"
|
|
283
|
+
pytest
|
|
182
284
|
```
|
|
183
285
|
|
|
184
286
|
## Releasing
|
|
@@ -190,11 +292,15 @@ Releases are cut from `main` with the release script (maintainers only):
|
|
|
190
292
|
./bin/release.sh minor # or: major
|
|
191
293
|
```
|
|
192
294
|
|
|
193
|
-
The script bumps the version
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
295
|
+
The script bumps the version (`pyproject.toml`, `__version__`, `uv.lock`),
|
|
296
|
+
builds sdist + wheel, validates them with `twine check`, uploads them to PyPI
|
|
297
|
+
with `twine upload`, then commits, tags `vX.Y.Z`, pushes, and creates a GitHub
|
|
298
|
+
release. Move the `Unreleased` notes in `CHANGELOG.md` under the new version
|
|
299
|
+
before running it.
|
|
300
|
+
|
|
301
|
+
It requires `uv`, an authenticated `gh`, and PyPI credentials for twine: either
|
|
302
|
+
a `[pypi]` entry in `~/.pypirc` (`username = __token__`, `password = pypi-...`)
|
|
303
|
+
or `TWINE_USERNAME=__token__` and `TWINE_PASSWORD=pypi-...` in the environment.
|
|
198
304
|
|
|
199
305
|
## License
|
|
200
306
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fastapi-startkit-auth"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.6.1"
|
|
4
4
|
description = "Laravel-style authentication for FastAPI: OAuth2/JWT authorization server, cookie/session guard, SPA + CSRF protection, and Sanctum-style API tokens."
|
|
5
|
-
readme = "
|
|
5
|
+
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
license-files = ["LICENSE"]
|
|
8
8
|
keywords = [
|
|
@@ -25,14 +25,13 @@ keywords = [
|
|
|
25
25
|
authors = [
|
|
26
26
|
{name = "Bedram Tamang", email = "tmgbedu@gmail.com"}
|
|
27
27
|
]
|
|
28
|
-
requires-python = ">=3.
|
|
28
|
+
requires-python = ">=3.10"
|
|
29
29
|
classifiers = [
|
|
30
30
|
"Development Status :: 4 - Beta",
|
|
31
31
|
"Framework :: FastAPI",
|
|
32
32
|
"Intended Audience :: Developers",
|
|
33
33
|
"Operating System :: OS Independent",
|
|
34
34
|
"Programming Language :: Python :: 3",
|
|
35
|
-
"Programming Language :: Python :: 3.9",
|
|
36
35
|
"Programming Language :: Python :: 3.10",
|
|
37
36
|
"Programming Language :: Python :: 3.11",
|
|
38
37
|
"Programming Language :: Python :: 3.12",
|
|
@@ -40,6 +39,7 @@ classifiers = [
|
|
|
40
39
|
"Topic :: Internet :: WWW/HTTP :: Session",
|
|
41
40
|
"Topic :: Security",
|
|
42
41
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
42
|
+
"Typing :: Typed",
|
|
43
43
|
]
|
|
44
44
|
dependencies = [
|
|
45
45
|
"fastapi>=0.110",
|
|
@@ -53,17 +53,19 @@ dependencies = [
|
|
|
53
53
|
Homepage = "https://github.com/fastapi-startkit/fastapi-startkit-auth"
|
|
54
54
|
Repository = "https://github.com/fastapi-startkit/fastapi-startkit-auth"
|
|
55
55
|
Issues = "https://github.com/fastapi-startkit/fastapi-startkit-auth/issues"
|
|
56
|
-
Changelog = "https://github.com/fastapi-startkit/fastapi-startkit-auth/
|
|
56
|
+
Changelog = "https://github.com/fastapi-startkit/fastapi-startkit-auth/blob/main/CHANGELOG.md"
|
|
57
57
|
|
|
58
58
|
[project.optional-dependencies]
|
|
59
59
|
masoniteorm = ["masonite-orm>=2.18"]
|
|
60
60
|
# The framework itself only supports Python >=3.12; on older interpreters the
|
|
61
61
|
# extra resolves to nothing and the package stays standalone.
|
|
62
|
-
startkit = ["fastapi-startkit>=0.
|
|
62
|
+
startkit = ["fastapi-startkit[database]>=0.60,<1.0; python_version >= '3.12'"]
|
|
63
63
|
test = [
|
|
64
64
|
"pytest>=8",
|
|
65
65
|
"pytest-asyncio>=0.23",
|
|
66
66
|
"httpx>=0.27",
|
|
67
|
+
"aiosqlite>=0.20",
|
|
68
|
+
"asyncpg>=0.29",
|
|
67
69
|
]
|
|
68
70
|
|
|
69
71
|
[dependency-groups]
|
|
@@ -71,8 +73,10 @@ dev = [
|
|
|
71
73
|
"pytest>=8",
|
|
72
74
|
"pytest-asyncio>=0.23",
|
|
73
75
|
"httpx>=0.27",
|
|
76
|
+
"aiosqlite>=0.20",
|
|
77
|
+
"asyncpg>=0.29",
|
|
74
78
|
"ruff>=0.9.0",
|
|
75
|
-
"twine>=6.
|
|
79
|
+
"twine>=6.1.0",
|
|
76
80
|
]
|
|
77
81
|
|
|
78
82
|
[tool.uv]
|
|
@@ -105,3 +109,6 @@ norecursedirs = [".venv", "dist", "build", "__pycache__"]
|
|
|
105
109
|
[build-system]
|
|
106
110
|
requires = ["uv_build>=0.10.10,<0.11.0"]
|
|
107
111
|
build-backend = "uv_build"
|
|
112
|
+
|
|
113
|
+
[tool.uv.build-backend]
|
|
114
|
+
source-include = ["CHANGELOG.md", "tests/**"]
|