fastapi-multiauth 0.6.0__tar.gz → 0.8.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_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/PKG-INFO +10 -7
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/README.md +6 -3
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/pyproject.toml +9 -6
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/pyproject.toml.orig +6 -6
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/__init__.py +23 -3
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/abc.py +297 -25
- fastapi_multiauth-0.8.0/src/fastapi_multiauth/amr.py +54 -0
- fastapi_multiauth-0.8.0/src/fastapi_multiauth/exceptions.py +137 -0
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/jwt.py +240 -115
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/oauth/__init__.py +10 -1
- fastapi_multiauth-0.8.0/src/fastapi_multiauth/oauth/id_token.py +143 -0
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/oauth/utils.py +74 -34
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/basic.py +10 -6
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/bearer.py +7 -3
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/cookie.py +56 -8
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/header.py +2 -2
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/multi.py +86 -11
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/query.py +2 -2
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/surface.py +14 -2
- fastapi_multiauth-0.8.0/src/fastapi_multiauth/utils.py +259 -0
- fastapi_multiauth-0.6.0/src/fastapi_multiauth/exceptions.py +0 -66
- fastapi_multiauth-0.6.0/src/fastapi_multiauth/utils.py +0 -85
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/LICENSE +0 -0
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/_http.py +0 -0
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/_imports.py +0 -0
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/oauth/client.py +0 -0
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/py.typed +0 -0
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/__init__.py +0 -0
- {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/oauth2.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-multiauth
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Composable authentication sources for FastAPI: bring your own validator, combine multiple schemes, correct OpenAPI by construction
|
|
5
5
|
Keywords: fastapi,authentication,security,oauth,api-key,bearer,cookie
|
|
6
6
|
Author: d3vyce
|
|
@@ -13,11 +13,11 @@ Classifier: Framework :: FastAPI
|
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Operating System :: OS Independent
|
|
15
15
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
21
21
|
Classifier: Topic :: Internet :: WWW/HTTP :: Session
|
|
22
22
|
Classifier: Topic :: Security
|
|
23
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
@@ -25,12 +25,12 @@ Classifier: Topic :: Software Development :: Libraries
|
|
|
25
25
|
Classifier: Typing :: Typed
|
|
26
26
|
Requires-Dist: anyio>=3.7
|
|
27
27
|
Requires-Dist: async-lru>=2.0
|
|
28
|
-
Requires-Dist: fastapi>=0.123.0
|
|
28
|
+
Requires-Dist: fastapi>=0.123.0,!=0.137.0,!=0.137.1
|
|
29
29
|
Requires-Dist: httpx>=0.25.0
|
|
30
30
|
Requires-Dist: itsdangerous>=2.1
|
|
31
31
|
Requires-Dist: pyjwt[crypto]>=2.13.0 ; extra == 'jwt'
|
|
32
32
|
Requires-Dist: httpx-oauth>=0.16 ; extra == 'oauth'
|
|
33
|
-
Requires-Python: >=3.
|
|
33
|
+
Requires-Python: >=3.11
|
|
34
34
|
Project-URL: Homepage, https://github.com/d3vyce/fastapi-multiauth
|
|
35
35
|
Project-URL: Documentation, https://fastapi-multiauth.d3vyce.fr/
|
|
36
36
|
Project-URL: Repository, https://github.com/d3vyce/fastapi-multiauth
|
|
@@ -49,7 +49,7 @@ Composable authentication sources for FastAPI: bring your own validator, combine
|
|
|
49
49
|
[](https://github.com/astral-sh/ty)
|
|
50
50
|
[](https://github.com/astral-sh/uv)
|
|
51
51
|
[](https://github.com/astral-sh/ruff)
|
|
52
|
-
[](https://www.python.org/downloads/)
|
|
53
53
|
[](https://opensource.org/licenses/MIT)
|
|
54
54
|
|
|
55
55
|
---
|
|
@@ -123,11 +123,14 @@ async def me(user=Security(auth)):
|
|
|
123
123
|
- **`APIKeyHeaderAuth`**: `X-API-Key`-style schemes, with **`APIKeyQueryAuth`** for legacy clients that can only pass a query parameter.
|
|
124
124
|
- **`HTTPBasicAuth`**: `validator(username, password)` with `WWW-Authenticate` realm support.
|
|
125
125
|
- **`OAuth2AuthorizationCodeBearerAuth`**, **`OAuth2PasswordBearerAuth`**, **`OpenIdConnectAuth`**: validate tokens an OAuth 2.0 / OIDC provider issued, and publish the scope catalogue so `/docs` offers a real Authorize dialog.
|
|
126
|
-
- **Token hashing helpers**: `hash_token`/`verify_token_hash` package the "store the hash, never the token" pattern with constant-time comparison.
|
|
126
|
+
- **Token hashing helpers**: `hash_token`/`verify_token_hash` package the "store the hash, never the token" pattern with constant-time comparison, and `checksum_token_generator`/`verify_token_checksum` add a GitHub-style CRC32 suffix that refuses typos before the lookup.
|
|
127
127
|
- **JWT validation** (`fastapi-multiauth[jwt]` extra): `JWTValidator` for `HTTPBearerAuth`: HS256 or provider JWKS (Keycloak/Auth0/Entra/Authentik) with TTL caching and rotation-aware `kid` refresh, `aud`/`iss`/`exp` checks, configurable scope claims, and a `claims_to_identity` hook.
|
|
128
128
|
- **Security scopes**: `Security(auth, scopes=[...])` forwards the declared scopes to validators that accept a `scopes` parameter.
|
|
129
|
+
- **WebSocket routes**: every source and `MultiAuth` guard `@app.websocket` routes too, refusing the handshake with the same 401/403.
|
|
130
|
+
- **Freshness / step-up auth**: `source.fresh(max_age=...)` refuses a credential proven too long ago on the endpoints that can take over an account, with the [RFC 9470](https://datatracker.ietf.org/doc/html/rfc9470) challenge that tells a client to re-authenticate. Signed cookies date themselves; anything else reads the instant off your identity. `source.stepped_up(acr_values=[...], acr=...)` asks for a stronger level instead, and composes with `fresh()` into one challenge; `AuthenticationMethodReference` names the [RFC 8176](https://datatracker.ietf.org/doc/html/rfc8176) `amr` values.
|
|
129
131
|
- **Correct HTTP semantics**: 401 with `WWW-Authenticate` challenges ([RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235)) and 403 via `ForbiddenError`.
|
|
130
|
-
- **
|
|
132
|
+
- **Security-event logging**: every refusal is a `WARNING` under `fastapi_multiauth.*` with a reason code (`invalid_signature`, `expired`, `stale`, …) in `extra`, never the credential or the identity; silent until your app configures logging.
|
|
133
|
+
- **OAuth 2.0 / OIDC helpers** (`fastapi-multiauth[oauth]` extra): async discovery with TTL caching, HTTPS enforcement, CSRF-protected `state` encoding, PKCE (S256), code exchange delegated to [httpx-oauth](https://github.com/frankie567/httpx-oauth), and OpenID Connect ID token validation with `nonce` and `at_hash` (plus the `jwt` extra).
|
|
131
134
|
|
|
132
135
|
## Comparison
|
|
133
136
|
|
|
@@ -8,7 +8,7 @@ Composable authentication sources for FastAPI: bring your own validator, combine
|
|
|
8
8
|
[](https://github.com/astral-sh/ty)
|
|
9
9
|
[](https://github.com/astral-sh/uv)
|
|
10
10
|
[](https://github.com/astral-sh/ruff)
|
|
11
|
-
[](https://www.python.org/downloads/)
|
|
12
12
|
[](https://opensource.org/licenses/MIT)
|
|
13
13
|
|
|
14
14
|
---
|
|
@@ -82,11 +82,14 @@ async def me(user=Security(auth)):
|
|
|
82
82
|
- **`APIKeyHeaderAuth`**: `X-API-Key`-style schemes, with **`APIKeyQueryAuth`** for legacy clients that can only pass a query parameter.
|
|
83
83
|
- **`HTTPBasicAuth`**: `validator(username, password)` with `WWW-Authenticate` realm support.
|
|
84
84
|
- **`OAuth2AuthorizationCodeBearerAuth`**, **`OAuth2PasswordBearerAuth`**, **`OpenIdConnectAuth`**: validate tokens an OAuth 2.0 / OIDC provider issued, and publish the scope catalogue so `/docs` offers a real Authorize dialog.
|
|
85
|
-
- **Token hashing helpers**: `hash_token`/`verify_token_hash` package the "store the hash, never the token" pattern with constant-time comparison.
|
|
85
|
+
- **Token hashing helpers**: `hash_token`/`verify_token_hash` package the "store the hash, never the token" pattern with constant-time comparison, and `checksum_token_generator`/`verify_token_checksum` add a GitHub-style CRC32 suffix that refuses typos before the lookup.
|
|
86
86
|
- **JWT validation** (`fastapi-multiauth[jwt]` extra): `JWTValidator` for `HTTPBearerAuth`: HS256 or provider JWKS (Keycloak/Auth0/Entra/Authentik) with TTL caching and rotation-aware `kid` refresh, `aud`/`iss`/`exp` checks, configurable scope claims, and a `claims_to_identity` hook.
|
|
87
87
|
- **Security scopes**: `Security(auth, scopes=[...])` forwards the declared scopes to validators that accept a `scopes` parameter.
|
|
88
|
+
- **WebSocket routes**: every source and `MultiAuth` guard `@app.websocket` routes too, refusing the handshake with the same 401/403.
|
|
89
|
+
- **Freshness / step-up auth**: `source.fresh(max_age=...)` refuses a credential proven too long ago on the endpoints that can take over an account, with the [RFC 9470](https://datatracker.ietf.org/doc/html/rfc9470) challenge that tells a client to re-authenticate. Signed cookies date themselves; anything else reads the instant off your identity. `source.stepped_up(acr_values=[...], acr=...)` asks for a stronger level instead, and composes with `fresh()` into one challenge; `AuthenticationMethodReference` names the [RFC 8176](https://datatracker.ietf.org/doc/html/rfc8176) `amr` values.
|
|
88
90
|
- **Correct HTTP semantics**: 401 with `WWW-Authenticate` challenges ([RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235)) and 403 via `ForbiddenError`.
|
|
89
|
-
- **
|
|
91
|
+
- **Security-event logging**: every refusal is a `WARNING` under `fastapi_multiauth.*` with a reason code (`invalid_signature`, `expired`, `stale`, …) in `extra`, never the credential or the identity; silent until your app configures logging.
|
|
92
|
+
- **OAuth 2.0 / OIDC helpers** (`fastapi-multiauth[oauth]` extra): async discovery with TTL caching, HTTPS enforcement, CSRF-protected `state` encoding, PKCE (S256), code exchange delegated to [httpx-oauth](https://github.com/frankie567/httpx-oauth), and OpenID Connect ID token validation with `nonce` and `at_hash` (plus the `jwt` extra).
|
|
90
93
|
|
|
91
94
|
## Comparison
|
|
92
95
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fastapi-multiauth"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.8.0"
|
|
4
4
|
description = "Composable authentication sources for FastAPI: bring your own validator, combine multiple schemes, correct OpenAPI by construction"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
license-files = ["LICENSE"]
|
|
8
|
-
requires-python = ">=3.
|
|
8
|
+
requires-python = ">=3.11"
|
|
9
9
|
keywords = [
|
|
10
10
|
"fastapi",
|
|
11
11
|
"authentication",
|
|
@@ -22,11 +22,11 @@ classifiers = [
|
|
|
22
22
|
"Intended Audience :: Developers",
|
|
23
23
|
"Operating System :: OS Independent",
|
|
24
24
|
"Programming Language :: Python :: 3 :: Only",
|
|
25
|
-
"Programming Language :: Python :: 3.10",
|
|
26
25
|
"Programming Language :: Python :: 3.11",
|
|
27
26
|
"Programming Language :: Python :: 3.12",
|
|
28
27
|
"Programming Language :: Python :: 3.13",
|
|
29
28
|
"Programming Language :: Python :: 3.14",
|
|
29
|
+
"Programming Language :: Python :: 3.15",
|
|
30
30
|
"Topic :: Internet :: WWW/HTTP :: Session",
|
|
31
31
|
"Topic :: Security",
|
|
32
32
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
@@ -36,7 +36,7 @@ classifiers = [
|
|
|
36
36
|
dependencies = [
|
|
37
37
|
"anyio>=3.7",
|
|
38
38
|
"async-lru>=2.0",
|
|
39
|
-
"fastapi>=0.123.0",
|
|
39
|
+
"fastapi>=0.123.0,!=0.137.0,!=0.137.1",
|
|
40
40
|
"httpx>=0.25.0",
|
|
41
41
|
"itsdangerous>=2.1",
|
|
42
42
|
]
|
|
@@ -78,11 +78,14 @@ docs = [
|
|
|
78
78
|
]
|
|
79
79
|
|
|
80
80
|
[build-system]
|
|
81
|
-
requires = ["uv_build>=0.11.21,<0.
|
|
81
|
+
requires = ["uv_build>=0.11.21,<0.14.0"]
|
|
82
82
|
build-backend = "uv_build"
|
|
83
83
|
|
|
84
84
|
[tool.ruff.lint]
|
|
85
|
-
extend-select = [
|
|
85
|
+
extend-select = [
|
|
86
|
+
"S",
|
|
87
|
+
"UP",
|
|
88
|
+
]
|
|
86
89
|
|
|
87
90
|
[tool.ruff.lint.per-file-ignores]
|
|
88
91
|
"tests/**" = [
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fastapi-multiauth"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.8.0"
|
|
4
4
|
description = "Composable authentication sources for FastAPI: bring your own validator, combine multiple schemes, correct OpenAPI by construction"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
license-files = ["LICENSE"]
|
|
8
|
-
requires-python = ">=3.
|
|
8
|
+
requires-python = ">=3.11"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "d3vyce", email = "contact@d3vyce.fr" }
|
|
11
11
|
]
|
|
@@ -17,11 +17,11 @@ classifiers = [
|
|
|
17
17
|
"Intended Audience :: Developers",
|
|
18
18
|
"Operating System :: OS Independent",
|
|
19
19
|
"Programming Language :: Python :: 3 :: Only",
|
|
20
|
-
"Programming Language :: Python :: 3.10",
|
|
21
20
|
"Programming Language :: Python :: 3.11",
|
|
22
21
|
"Programming Language :: Python :: 3.12",
|
|
23
22
|
"Programming Language :: Python :: 3.13",
|
|
24
23
|
"Programming Language :: Python :: 3.14",
|
|
24
|
+
"Programming Language :: Python :: 3.15",
|
|
25
25
|
"Topic :: Internet :: WWW/HTTP :: Session",
|
|
26
26
|
"Topic :: Security",
|
|
27
27
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
@@ -31,7 +31,7 @@ classifiers = [
|
|
|
31
31
|
dependencies = [
|
|
32
32
|
"anyio>=3.7",
|
|
33
33
|
"async-lru>=2.0",
|
|
34
|
-
"fastapi>=0.123.0",
|
|
34
|
+
"fastapi>=0.123.0,!=0.137.0,!=0.137.1",
|
|
35
35
|
"httpx>=0.25.0",
|
|
36
36
|
"itsdangerous>=2.1",
|
|
37
37
|
]
|
|
@@ -73,12 +73,12 @@ docs = [
|
|
|
73
73
|
]
|
|
74
74
|
|
|
75
75
|
[build-system]
|
|
76
|
-
requires = ["uv_build>=0.11.21,<0.
|
|
76
|
+
requires = ["uv_build>=0.11.21,<0.14.0"]
|
|
77
77
|
build-backend = "uv_build"
|
|
78
78
|
|
|
79
79
|
[tool.ruff.lint]
|
|
80
80
|
# "S" = flake8-bandit security rules, scoped to the library source.
|
|
81
|
-
extend-select = ["S"]
|
|
81
|
+
extend-select = ["S", "UP"]
|
|
82
82
|
|
|
83
83
|
[tool.ruff.lint.per-file-ignores]
|
|
84
84
|
"tests/**" = ["S", "B008"]
|
|
@@ -9,9 +9,17 @@ exported here, and require the ``oauth`` extra. Import them explicitly::
|
|
|
9
9
|
redirect = oauth.oauth_build_authorization_redirect(...)
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
+
import logging
|
|
13
|
+
|
|
12
14
|
from . import oauth
|
|
13
15
|
from .abc import AuthSource
|
|
14
|
-
from .
|
|
16
|
+
from .amr import AuthenticationMethodReference
|
|
17
|
+
from .exceptions import (
|
|
18
|
+
ForbiddenError,
|
|
19
|
+
InsufficientAuthenticationError,
|
|
20
|
+
StaleCredentialError,
|
|
21
|
+
UnauthorizedError,
|
|
22
|
+
)
|
|
15
23
|
from .jwt import JWTValidator
|
|
16
24
|
from .sources import (
|
|
17
25
|
APIKeyCookieAuth,
|
|
@@ -25,18 +33,27 @@ from .sources import (
|
|
|
25
33
|
OpenIdConnectAuth,
|
|
26
34
|
)
|
|
27
35
|
from .surface import RouteAuth, SchemeRequirement, auth_surface
|
|
28
|
-
from .utils import
|
|
36
|
+
from .utils import (
|
|
37
|
+
checksum_token_generator,
|
|
38
|
+
hash_token,
|
|
39
|
+
verify_token_checksum,
|
|
40
|
+
verify_token_hash,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
__version__ = "0.8.0"
|
|
29
44
|
|
|
30
|
-
|
|
45
|
+
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
|
31
46
|
|
|
32
47
|
__all__ = [
|
|
33
48
|
"APIKeyCookieAuth",
|
|
34
49
|
"APIKeyHeaderAuth",
|
|
35
50
|
"APIKeyQueryAuth",
|
|
36
51
|
"AuthSource",
|
|
52
|
+
"AuthenticationMethodReference",
|
|
37
53
|
"ForbiddenError",
|
|
38
54
|
"HTTPBasicAuth",
|
|
39
55
|
"HTTPBearerAuth",
|
|
56
|
+
"InsufficientAuthenticationError",
|
|
40
57
|
"JWTValidator",
|
|
41
58
|
"MultiAuth",
|
|
42
59
|
"OAuth2AuthorizationCodeBearerAuth",
|
|
@@ -44,9 +61,12 @@ __all__ = [
|
|
|
44
61
|
"OpenIdConnectAuth",
|
|
45
62
|
"RouteAuth",
|
|
46
63
|
"SchemeRequirement",
|
|
64
|
+
"StaleCredentialError",
|
|
47
65
|
"UnauthorizedError",
|
|
48
66
|
"auth_surface",
|
|
67
|
+
"checksum_token_generator",
|
|
49
68
|
"hash_token",
|
|
50
69
|
"oauth",
|
|
70
|
+
"verify_token_checksum",
|
|
51
71
|
"verify_token_hash",
|
|
52
72
|
]
|