fastapi-multiauth 0.3.0__tar.gz → 0.4.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.3.0 → fastapi_multiauth-0.4.0}/PKG-INFO +3 -2
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/README.md +2 -1
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/pyproject.toml +6 -1
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/pyproject.toml.orig +3 -1
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/__init__.py +1 -1
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/abc.py +36 -32
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/sources/cookie.py +71 -8
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/LICENSE +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/_http.py +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/_imports.py +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/exceptions.py +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/jwt.py +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/oauth/__init__.py +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/oauth/client.py +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/oauth/utils.py +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/py.typed +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/sources/__init__.py +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/sources/basic.py +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/sources/bearer.py +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/sources/header.py +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/sources/multi.py +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/sources/query.py +0 -0
- {fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-multiauth
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.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
|
|
@@ -45,6 +45,7 @@ Composable authentication sources for FastAPI: bring your own validator, combine
|
|
|
45
45
|
|
|
46
46
|
[](https://github.com/d3vyce/fastapi-multiauth/actions/workflows/ci.yml)
|
|
47
47
|
[](https://codecov.io/gh/d3vyce/fastapi-multiauth)
|
|
48
|
+
[](https://app.codspeed.io//d3vyce/fastapi-multiauth?utm_source=badge)
|
|
48
49
|
[](https://github.com/astral-sh/ty)
|
|
49
50
|
[](https://github.com/astral-sh/uv)
|
|
50
51
|
[](https://github.com/astral-sh/ruff)
|
|
@@ -118,7 +119,7 @@ async def me(user=Security(auth)):
|
|
|
118
119
|
- **`MultiAuth`**: try several sources in order on a single route (e.g. web session cookie + API bearer token), with all schemes documented in OpenAPI.
|
|
119
120
|
- **Built-in sources**: covering the standard `fastapi.security` schemes:
|
|
120
121
|
- **`HTTPBearerAuth`**: bearer tokens with optional Stripe-style `user_`/`org_` prefixes to route different token types to different validators, plus `generate_token()` for secure token creation.
|
|
121
|
-
- **`APIKeyCookieAuth`**: cookie sessions with optional HMAC-SHA256 signing (via [itsdangerous](https://itsdangerous.palletsprojects.com/)), embedded expiry, and
|
|
122
|
+
- **`APIKeyCookieAuth`**: cookie sessions with optional HMAC-SHA256 signing (via [itsdangerous](https://itsdangerous.palletsprojects.com/)), embedded expiry, key rotation, and optional per-session ids so your app can list and revoke sessions individually.
|
|
122
123
|
- **`APIKeyHeaderAuth`**: `X-API-Key`-style schemes, with **`APIKeyQueryAuth`** for legacy clients that can only pass a query parameter.
|
|
123
124
|
- **`HTTPBasicAuth`**: `validator(username, password)` with `WWW-Authenticate` realm support.
|
|
124
125
|
- **Token hashing helpers**: `hash_token`/`verify_token_hash` package the "store the hash, never the token" pattern with constant-time comparison.
|
|
@@ -4,6 +4,7 @@ Composable authentication sources for FastAPI: bring your own validator, combine
|
|
|
4
4
|
|
|
5
5
|
[](https://github.com/d3vyce/fastapi-multiauth/actions/workflows/ci.yml)
|
|
6
6
|
[](https://codecov.io/gh/d3vyce/fastapi-multiauth)
|
|
7
|
+
[](https://app.codspeed.io//d3vyce/fastapi-multiauth?utm_source=badge)
|
|
7
8
|
[](https://github.com/astral-sh/ty)
|
|
8
9
|
[](https://github.com/astral-sh/uv)
|
|
9
10
|
[](https://github.com/astral-sh/ruff)
|
|
@@ -77,7 +78,7 @@ async def me(user=Security(auth)):
|
|
|
77
78
|
- **`MultiAuth`**: try several sources in order on a single route (e.g. web session cookie + API bearer token), with all schemes documented in OpenAPI.
|
|
78
79
|
- **Built-in sources**: covering the standard `fastapi.security` schemes:
|
|
79
80
|
- **`HTTPBearerAuth`**: bearer tokens with optional Stripe-style `user_`/`org_` prefixes to route different token types to different validators, plus `generate_token()` for secure token creation.
|
|
80
|
-
- **`APIKeyCookieAuth`**: cookie sessions with optional HMAC-SHA256 signing (via [itsdangerous](https://itsdangerous.palletsprojects.com/)), embedded expiry, and
|
|
81
|
+
- **`APIKeyCookieAuth`**: cookie sessions with optional HMAC-SHA256 signing (via [itsdangerous](https://itsdangerous.palletsprojects.com/)), embedded expiry, key rotation, and optional per-session ids so your app can list and revoke sessions individually.
|
|
81
82
|
- **`APIKeyHeaderAuth`**: `X-API-Key`-style schemes, with **`APIKeyQueryAuth`** for legacy clients that can only pass a query parameter.
|
|
82
83
|
- **`HTTPBasicAuth`**: `validator(username, password)` with `WWW-Authenticate` realm support.
|
|
83
84
|
- **Token hashing helpers**: `hash_token`/`verify_token_hash` package the "store the hash, never the token" pattern with constant-time comparison.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fastapi-multiauth"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.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"
|
|
@@ -67,6 +67,7 @@ dev = [
|
|
|
67
67
|
tests = [
|
|
68
68
|
"coverage>=7.0.0",
|
|
69
69
|
"pytest-anyio>=0.0.0",
|
|
70
|
+
"pytest-codspeed>=5.0",
|
|
70
71
|
"pytest-cov>=4.0.0",
|
|
71
72
|
"pytest>=8.0.0",
|
|
72
73
|
"respx>=0.22",
|
|
@@ -88,6 +89,10 @@ extend-select = ["S"]
|
|
|
88
89
|
"S",
|
|
89
90
|
"B008",
|
|
90
91
|
]
|
|
92
|
+
"benchmarks/**" = [
|
|
93
|
+
"S",
|
|
94
|
+
"B008",
|
|
95
|
+
]
|
|
91
96
|
|
|
92
97
|
[tool.pytest.ini_options]
|
|
93
98
|
testpaths = ["tests"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fastapi-multiauth"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.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"
|
|
@@ -62,6 +62,7 @@ dev = [
|
|
|
62
62
|
tests = [
|
|
63
63
|
"coverage>=7.0.0",
|
|
64
64
|
"pytest-anyio>=0.0.0",
|
|
65
|
+
"pytest-codspeed>=5.0",
|
|
65
66
|
"pytest-cov>=4.0.0",
|
|
66
67
|
"pytest>=8.0.0",
|
|
67
68
|
"respx>=0.22",
|
|
@@ -81,6 +82,7 @@ extend-select = ["S"]
|
|
|
81
82
|
|
|
82
83
|
[tool.ruff.lint.per-file-ignores]
|
|
83
84
|
"tests/**" = ["S", "B008"]
|
|
85
|
+
"benchmarks/**" = ["S", "B008"]
|
|
84
86
|
|
|
85
87
|
[tool.pytest.ini_options]
|
|
86
88
|
testpaths = ["tests"]
|
|
@@ -17,23 +17,29 @@ if TYPE_CHECKING:
|
|
|
17
17
|
from typing_extensions import Self
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
_RESERVED_KWARGS = {
|
|
21
|
+
"scopes": "injected from the route by Security(..., scopes=[...])",
|
|
22
|
+
"session_id": "injected by APIKeyCookieAuth(session_id=True)",
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _reject_reserved_kwargs(kwargs: dict[str, Any]) -> None:
|
|
27
|
+
"""Reject validator kwargs the library injects itself."""
|
|
28
|
+
for name, injected in _RESERVED_KWARGS.items():
|
|
29
|
+
if name in kwargs:
|
|
30
|
+
raise ValueError(
|
|
31
|
+
f"'{name}' is a reserved validator kwarg ({injected}): "
|
|
32
|
+
"the library sets it. Use a different keyword name."
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _accepts_kwarg(fn: Callable[..., Any], name: str) -> bool:
|
|
37
|
+
"""Return whether *fn* declares a *name* parameter."""
|
|
32
38
|
try:
|
|
33
39
|
parameters = inspect.signature(fn).parameters
|
|
34
40
|
except (TypeError, ValueError):
|
|
35
41
|
return False
|
|
36
|
-
param = parameters.get(
|
|
42
|
+
param = parameters.get(name)
|
|
37
43
|
return param is not None and param.kind in (
|
|
38
44
|
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
|
39
45
|
inspect.Parameter.KEYWORD_ONLY,
|
|
@@ -51,17 +57,6 @@ def _unenforceable_scopes_error(owner: object, scopes: list[str]) -> RuntimeErro
|
|
|
51
57
|
)
|
|
52
58
|
|
|
53
59
|
|
|
54
|
-
def _scope_kwargs(
|
|
55
|
-
owner: object, accepts_scopes: bool, scopes: list[str]
|
|
56
|
-
) -> dict[str, Any]:
|
|
57
|
-
"""Return the ``scopes`` kwarg for a validator, failing closed when unsupported."""
|
|
58
|
-
if accepts_scopes:
|
|
59
|
-
return {"scopes": scopes}
|
|
60
|
-
if scopes:
|
|
61
|
-
raise _unenforceable_scopes_error(owner, scopes)
|
|
62
|
-
return {}
|
|
63
|
-
|
|
64
|
-
|
|
65
60
|
class _DocOnlyScheme(SecurityBase):
|
|
66
61
|
"""Inert stand-in for a ``fastapi.security`` scheme.
|
|
67
62
|
|
|
@@ -193,18 +188,24 @@ class ValidatedAuthSource(AuthSource):
|
|
|
193
188
|
validator: Sync or async callable returning the identity.
|
|
194
189
|
scheme: Optional ``fastapi.security`` scheme for OpenAPI.
|
|
195
190
|
**kwargs: Extra keyword arguments forwarded to the validator on
|
|
196
|
-
every call.
|
|
191
|
+
every call. Names the library injects itself are reserved:
|
|
192
|
+
``scopes`` and ``session_id``.
|
|
197
193
|
"""
|
|
198
|
-
|
|
194
|
+
_reject_reserved_kwargs(kwargs)
|
|
199
195
|
self._validator = ensure_async(validator)
|
|
200
|
-
self._accepts_scopes =
|
|
196
|
+
self._accepts_scopes = _accepts_kwarg(validator, "scopes")
|
|
201
197
|
self._kwargs = kwargs
|
|
202
198
|
super().__init__(scheme)
|
|
203
199
|
|
|
204
|
-
async def _call_validator(
|
|
200
|
+
async def _call_validator(
|
|
201
|
+
self, *args: Any, scopes: list[str], **injected: Any
|
|
202
|
+
) -> Any:
|
|
205
203
|
"""Invoke the validator with scope and configured kwargs forwarding."""
|
|
206
|
-
|
|
207
|
-
|
|
204
|
+
if self._accepts_scopes:
|
|
205
|
+
injected["scopes"] = scopes
|
|
206
|
+
elif scopes: # fail closed: the validator cannot check them
|
|
207
|
+
raise _unenforceable_scopes_error(self, scopes)
|
|
208
|
+
return await self._validator(*args, **self._kwargs, **injected)
|
|
208
209
|
|
|
209
210
|
async def authenticate(self, credential: str) -> Any:
|
|
210
211
|
"""Validate a credential and return the identity (no route scopes)."""
|
|
@@ -215,8 +216,11 @@ class ValidatedAuthSource(AuthSource):
|
|
|
215
216
|
return await self._call_validator(credential, scopes=scopes)
|
|
216
217
|
|
|
217
218
|
def require(self, **kwargs: Any) -> "Self":
|
|
218
|
-
"""Return a copy of this source with additional (or overriding) validator kwargs.
|
|
219
|
-
|
|
219
|
+
"""Return a copy of this source with additional (or overriding) validator kwargs.
|
|
220
|
+
|
|
221
|
+
Reserved names (``scopes``, ``session_id``) are rejected here too.
|
|
222
|
+
"""
|
|
223
|
+
_reject_reserved_kwargs(kwargs)
|
|
220
224
|
clone = copy.copy(self)
|
|
221
225
|
clone._kwargs = {**self._kwargs, **kwargs}
|
|
222
226
|
return clone
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Cookie-based authentication source."""
|
|
2
2
|
|
|
3
3
|
import hashlib
|
|
4
|
+
import secrets
|
|
4
5
|
from collections.abc import Callable, Sequence
|
|
5
6
|
from typing import Any, Literal
|
|
6
7
|
|
|
@@ -10,7 +11,7 @@ from itsdangerous import BadSignature, TimestampSigner
|
|
|
10
11
|
|
|
11
12
|
from fastapi_multiauth.exceptions import UnauthorizedError
|
|
12
13
|
|
|
13
|
-
from ..abc import ValidatedAuthSource
|
|
14
|
+
from ..abc import ValidatedAuthSource, _accepts_kwarg
|
|
14
15
|
|
|
15
16
|
_MIN_SECRET_KEY_BYTES = 32
|
|
16
17
|
_SALT_PREFIX = "fastapi-multiauth.cookie."
|
|
@@ -48,6 +49,10 @@ class APIKeyCookieAuth(ValidatedAuthSource):
|
|
|
48
49
|
after signature verification when signed) and returning the identity.
|
|
49
50
|
secret_key: One key or a sequence to rotate (first signs, all verify);
|
|
50
51
|
each at least 32 bytes. When ``None``, the cookie is not signed.
|
|
52
|
+
session_id: Mint a random id per :meth:`set_cookie` and inject it into
|
|
53
|
+
the validator as ``session_id``. Requires ``secret_key`` and a
|
|
54
|
+
validator declaring that parameter; changing it invalidates
|
|
55
|
+
existing cookies.
|
|
51
56
|
ttl: Cookie lifetime in seconds (default 24 h); also enforced
|
|
52
57
|
server-side when the cookie is signed.
|
|
53
58
|
secure: Set the ``Secure`` flag (default ``True``); disable only in local dev.
|
|
@@ -64,6 +69,7 @@ class APIKeyCookieAuth(ValidatedAuthSource):
|
|
|
64
69
|
validator: Callable[..., Any],
|
|
65
70
|
*,
|
|
66
71
|
secret_key: str | Sequence[str] | None = None,
|
|
72
|
+
session_id: bool = False,
|
|
67
73
|
ttl: int = 86400,
|
|
68
74
|
secure: bool = True,
|
|
69
75
|
samesite: SameSite = "lax",
|
|
@@ -76,12 +82,25 @@ class APIKeyCookieAuth(ValidatedAuthSource):
|
|
|
76
82
|
raise ValueError("ttl must be a positive number of seconds")
|
|
77
83
|
self._name = name
|
|
78
84
|
self._secret_keys = _normalize_secret_keys(secret_key)
|
|
85
|
+
if session_id:
|
|
86
|
+
if not self._secret_keys:
|
|
87
|
+
raise ValueError(
|
|
88
|
+
"session_id requires secret_key: without a signature the "
|
|
89
|
+
"client could forge or swap the session id"
|
|
90
|
+
)
|
|
91
|
+
if not _accepts_kwarg(validator, "session_id"):
|
|
92
|
+
raise ValueError(
|
|
93
|
+
"session_id requires a validator declaring a 'session_id' "
|
|
94
|
+
"parameter: the minted id is injected on every call"
|
|
95
|
+
)
|
|
96
|
+
self._session_id = session_id
|
|
79
97
|
# itsdangerous verifies against every key in the list but signs with
|
|
80
98
|
# the last one — reverse so the first configured key is the signer.
|
|
99
|
+
# The salt also separates the two payload layouts.
|
|
81
100
|
self._signer = (
|
|
82
101
|
TimestampSigner(
|
|
83
102
|
list(reversed(self._secret_keys)),
|
|
84
|
-
salt=f"{_SALT_PREFIX}{name}",
|
|
103
|
+
salt=f"{_SALT_PREFIX}{name}{'.sid' if session_id else ''}",
|
|
85
104
|
digest_method=hashlib.sha256,
|
|
86
105
|
)
|
|
87
106
|
if self._secret_keys
|
|
@@ -118,17 +137,53 @@ class APIKeyCookieAuth(ValidatedAuthSource):
|
|
|
118
137
|
except BadSignature:
|
|
119
138
|
raise UnauthorizedError() from None
|
|
120
139
|
|
|
140
|
+
@property
|
|
141
|
+
def name(self) -> str:
|
|
142
|
+
"""Cookie name. Read-only: the signing salt is derived from it."""
|
|
143
|
+
return self._name
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def ttl(self) -> int:
|
|
147
|
+
"""Cookie lifetime in seconds: use it to derive your session's expiry."""
|
|
148
|
+
return self._ttl
|
|
149
|
+
|
|
121
150
|
async def extract(self, request: Request) -> str | None:
|
|
122
151
|
"""Return the raw cookie value, or ``None`` when absent or empty."""
|
|
123
152
|
return request.cookies.get(self._name) or None
|
|
124
153
|
|
|
154
|
+
def session_id_of(self, request: Request) -> str | None:
|
|
155
|
+
"""Return *request*'s session id without running the validator.
|
|
156
|
+
|
|
157
|
+
``None`` when ``session_id`` is off, or the cookie is absent, expired
|
|
158
|
+
or forged.
|
|
159
|
+
"""
|
|
160
|
+
if not self._session_id:
|
|
161
|
+
return None
|
|
162
|
+
cookie_value = request.cookies.get(self._name)
|
|
163
|
+
if not cookie_value:
|
|
164
|
+
return None
|
|
165
|
+
try:
|
|
166
|
+
return self._verify(cookie_value).partition(".")[0]
|
|
167
|
+
except UnauthorizedError:
|
|
168
|
+
return None
|
|
169
|
+
|
|
125
170
|
async def authenticate_scoped(self, credential: str, scopes: list[str]) -> Any:
|
|
126
171
|
"""Verify the cookie, forwarding route-declared scopes to the validator."""
|
|
127
172
|
plain = self._verify(credential)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
173
|
+
if not self._session_id:
|
|
174
|
+
return await self._call_validator(plain, scopes=scopes)
|
|
175
|
+
sid, _, value = plain.partition(".")
|
|
176
|
+
return await self._call_validator(value, scopes=scopes, session_id=sid)
|
|
177
|
+
|
|
178
|
+
def set_cookie(self, response: Response, value: str) -> str | None:
|
|
179
|
+
"""Attach the cookie to *response*, signing it when ``secret_key`` is set.
|
|
180
|
+
|
|
181
|
+
Returns the minted session id: always a ``str`` when ``session_id`` is
|
|
182
|
+
on, always ``None`` when it is off.
|
|
183
|
+
"""
|
|
184
|
+
sid = secrets.token_urlsafe(16) if self._session_id else None
|
|
185
|
+
if sid is not None:
|
|
186
|
+
value = f"{sid}.{value}"
|
|
132
187
|
cookie_value = self._sign(value) if self._signer else value
|
|
133
188
|
response.set_cookie(
|
|
134
189
|
self._name,
|
|
@@ -140,9 +195,16 @@ class APIKeyCookieAuth(ValidatedAuthSource):
|
|
|
140
195
|
domain=self._domain,
|
|
141
196
|
path=self._path,
|
|
142
197
|
)
|
|
198
|
+
return sid
|
|
199
|
+
|
|
200
|
+
def delete_cookie(
|
|
201
|
+
self, response: Response, request: Request | None = None
|
|
202
|
+
) -> str | None:
|
|
203
|
+
"""Clear the session cookie (logout) from this client only.
|
|
143
204
|
|
|
144
|
-
|
|
145
|
-
|
|
205
|
+
Returns *request*'s session id when it verifies (revoke it server-side
|
|
206
|
+
for a hard logout), ``None`` otherwise.
|
|
207
|
+
"""
|
|
146
208
|
response.delete_cookie(
|
|
147
209
|
self._name,
|
|
148
210
|
httponly=True,
|
|
@@ -151,3 +213,4 @@ class APIKeyCookieAuth(ValidatedAuthSource):
|
|
|
151
213
|
domain=self._domain,
|
|
152
214
|
path=self._path,
|
|
153
215
|
)
|
|
216
|
+
return self.session_id_of(request) if request is not None else None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_multiauth-0.3.0 → fastapi_multiauth-0.4.0}/src/fastapi_multiauth/sources/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|