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.
Files changed (29) hide show
  1. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/PKG-INFO +10 -7
  2. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/README.md +6 -3
  3. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/pyproject.toml +9 -6
  4. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/pyproject.toml.orig +6 -6
  5. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/__init__.py +23 -3
  6. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/abc.py +297 -25
  7. fastapi_multiauth-0.8.0/src/fastapi_multiauth/amr.py +54 -0
  8. fastapi_multiauth-0.8.0/src/fastapi_multiauth/exceptions.py +137 -0
  9. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/jwt.py +240 -115
  10. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/oauth/__init__.py +10 -1
  11. fastapi_multiauth-0.8.0/src/fastapi_multiauth/oauth/id_token.py +143 -0
  12. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/oauth/utils.py +74 -34
  13. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/basic.py +10 -6
  14. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/bearer.py +7 -3
  15. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/cookie.py +56 -8
  16. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/header.py +2 -2
  17. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/multi.py +86 -11
  18. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/query.py +2 -2
  19. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/surface.py +14 -2
  20. fastapi_multiauth-0.8.0/src/fastapi_multiauth/utils.py +259 -0
  21. fastapi_multiauth-0.6.0/src/fastapi_multiauth/exceptions.py +0 -66
  22. fastapi_multiauth-0.6.0/src/fastapi_multiauth/utils.py +0 -85
  23. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/LICENSE +0 -0
  24. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/_http.py +0 -0
  25. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/_imports.py +0 -0
  26. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/oauth/client.py +0 -0
  27. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/py.typed +0 -0
  28. {fastapi_multiauth-0.6.0 → fastapi_multiauth-0.8.0}/src/fastapi_multiauth/sources/__init__.py +0 -0
  29. {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.6.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.10
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
  [![ty](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ty/main/assets/badge/v0.json)](https://github.com/astral-sh/ty)
50
50
  [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
51
51
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
52
- [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
52
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
53
53
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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
- - **OAuth 2.0 / OIDC helpers** (`fastapi-multiauth[oauth]` extra): async discovery with TTL caching, HTTPS enforcement, CSRF-protected `state` encoding, PKCE (S256), and code exchange delegated to [httpx-oauth](https://github.com/frankie567/httpx-oauth).
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
  [![ty](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ty/main/assets/badge/v0.json)](https://github.com/astral-sh/ty)
9
9
  [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
10
10
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
11
- [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
11
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
12
12
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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
- - **OAuth 2.0 / OIDC helpers** (`fastapi-multiauth[oauth]` extra): async discovery with TTL caching, HTTPS enforcement, CSRF-protected `state` encoding, PKCE (S256), and code exchange delegated to [httpx-oauth](https://github.com/frankie567/httpx-oauth).
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.6.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.10"
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.13.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 = ["S"]
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.6.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.10"
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.13.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 .exceptions import ForbiddenError, UnauthorizedError
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 hash_token, verify_token_hash
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
- __version__ = "0.6.0"
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
  ]