usso 0.24.19__py3-none-any.whl → 0.25.1__py3-none-any.whl

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.
usso/async_session.py CHANGED
@@ -2,7 +2,6 @@ from contextlib import asynccontextmanager
2
2
  from datetime import datetime, timedelta
3
3
 
4
4
  import aiohttp
5
- from fastapi import params
6
5
  import jwt
7
6
 
8
7
 
usso/core.py CHANGED
@@ -1,11 +1,12 @@
1
+ import json
1
2
  import logging
2
3
  import os
3
4
  import uuid
4
5
  from functools import lru_cache
5
- from typing import Optional, Tuple
6
6
 
7
+ import cachetools.func
7
8
  import jwt
8
- from pydantic import BaseModel
9
+ from pydantic import BaseModel, model_validator
9
10
  from singleton import Singleton
10
11
 
11
12
  from . import b64tools
@@ -16,12 +17,20 @@ logger = logging.getLogger("usso")
16
17
 
17
18
  class UserData(BaseModel):
18
19
  user_id: str
20
+ workspace_id: str | None = None
21
+ workspace_ids: list[str] = []
22
+ token_type: str = "access"
23
+
19
24
  email: str | None = None
20
25
  phone: str | None = None
26
+ username: str | None = None
27
+
21
28
  authentication_method: str | None = None
22
29
  is_active: bool = False
30
+
23
31
  jti: str | None = None
24
32
  data: dict | None = None
33
+
25
34
  token: str | None = None
26
35
 
27
36
  @property
@@ -40,74 +49,153 @@ class UserData(BaseModel):
40
49
  return b64tools.b64_encode_uuid_strip(self.uid)
41
50
 
42
51
 
43
- class Usso(metaclass=Singleton):
44
- def __init__(self, jwks_url: str | None = None):
45
- if jwks_url is None:
46
- jwks_url = os.getenv("USSO_JWKS_URL")
47
- self.jwks_url = jwks_url
52
+ def get_authorization_scheme_param(
53
+ authorization_header_value: str | None,
54
+ ) -> tuple[str, str]:
55
+ if not authorization_header_value:
56
+ return "", ""
57
+ scheme, _, param = authorization_header_value.partition(" ")
58
+ return scheme, param
59
+
60
+
61
+ def decode_token(key, token: str, algorithms=["RS256"], **kwargs) -> dict:
62
+ try:
63
+ decoded = jwt.decode(token, key, algorithms=algorithms)
64
+ decoded["token"] = token
65
+ return UserData(**decoded)
66
+ except jwt.exceptions.ExpiredSignatureError:
67
+ if kwargs.get("raise_exception", True):
68
+ raise USSOException(status_code=401, error="expired_signature")
69
+ except jwt.exceptions.InvalidSignatureError:
70
+ if kwargs.get("raise_exception", True):
71
+ raise USSOException(status_code=401, error="invalid_signature")
72
+ except jwt.exceptions.InvalidAlgorithmError:
73
+ if kwargs.get("raise_exception", True):
74
+ raise USSOException(status_code=401, error="invalid_algorithm")
75
+ except jwt.exceptions.InvalidIssuedAtError:
76
+ if kwargs.get("raise_exception", True):
77
+ raise USSOException(status_code=401, error="invalid_issued_at")
78
+ except jwt.exceptions.InvalidTokenError:
79
+ if kwargs.get("raise_exception", True):
80
+ raise USSOException(status_code=401, error="invalid_token")
81
+ except jwt.exceptions.InvalidKeyError:
82
+ if kwargs.get("raise_exception", True):
83
+ raise USSOException(status_code=401, error="invalid_key")
84
+ except USSOException as e:
85
+ if kwargs.get("raise_exception", True):
86
+ raise e
87
+ except Exception as e:
88
+ if kwargs.get("raise_exception", True):
89
+ raise USSOException(status_code=401, error="error", message=str(e))
90
+ logger.error(e)
91
+
92
+
93
+ @lru_cache
94
+ def get_jwk_keys(jwk_url: str) -> jwt.PyJWKClient:
95
+ return jwt.PyJWKClient(jwk_url, headers={"User-Agent": "usso-python"})
96
+
97
+
98
+ def decode_token_jwk(jwk_url: str, token: str, **kwargs) -> UserData | None:
99
+ """Return the user associated with a token value."""
100
+ try:
101
+ jwk_client = get_jwk_keys(jwk_url)
102
+ signing_key = jwk_client.get_signing_key_from_jwt(token)
103
+ return decode_token(signing_key.key, token, **kwargs)
104
+ except USSOException as e:
105
+ if kwargs.get("raise_exception", True):
106
+ raise e
107
+ logger.error(e)
108
+ except Exception as e:
109
+ if kwargs.get("raise_exception", True):
110
+ raise USSOException(
111
+ status_code=401,
112
+ error="error",
113
+ message=str(e),
114
+ )
115
+ logger.error(e)
116
+
117
+
118
+ class JWTConfig(BaseModel):
119
+ jwk_url: str | None = None
120
+ secret: str | None = None
121
+ type: str = "RS256"
122
+ header: dict[str, str] = {"type": "Cookie", "name": "usso_access_token"}
123
+
124
+ def __hash__(self):
125
+ return hash(self.model_dump_json())
48
126
 
49
- @lru_cache
50
- def get_jwks_keys(self):
51
- return jwt.PyJWKClient(
52
- self.jwks_url,
53
- headers={
54
- "User-Agent": "usso-python",
55
- },
56
- )
127
+ @model_validator(mode="before")
128
+ def validate_secret(cls, data: dict):
129
+ if not data.get("jwk_url") and not data.get("secret"):
130
+ raise ValueError("Either jwk_url or secret must be provided")
131
+ return data
57
132
 
58
- def get_authorization_scheme_param(
133
+ @classmethod
134
+ @cachetools.func.ttl_cache(maxsize=128, ttl=10 * 60)
135
+ def get_jwk_keys(cls, jwk_url):
136
+ return get_jwk_keys(jwk_url)
137
+
138
+ @cachetools.func.ttl_cache(maxsize=128, ttl=10 * 60)
139
+ def decode(self, token: str):
140
+ if self.jwk_url:
141
+ return decode_token_jwk(self.jwk_url, token)
142
+ return decode_token(self.secret, token, algorithms=[self.type])
143
+
144
+
145
+ class Usso:
146
+
147
+ def __init__(
59
148
  self,
60
- authorization_header_value: Optional[str],
61
- ) -> Tuple[str, str]:
62
- if not authorization_header_value:
63
- return "", ""
64
- scheme, _, param = authorization_header_value.partition(" ")
65
- return scheme, param
66
-
67
- def decode_token(self, key, token: str, **kwargs) -> dict:
68
- try:
69
- decoded = jwt.decode(token, key, algorithms=["RS256"])
70
- if decoded["token_type"] != "access":
71
- raise USSOException(status_code=401, error="invalid_token_type")
72
- decoded["token"] = token
73
- return UserData(**decoded)
74
- except jwt.exceptions.ExpiredSignatureError:
75
- if kwargs.get("raise_exception", True):
76
- raise USSOException(status_code=401, error="expired_signature")
77
- except jwt.exceptions.InvalidSignatureError:
78
- if kwargs.get("raise_exception", True):
79
- raise USSOException(status_code=401, error="invalid_signature")
80
- except jwt.exceptions.InvalidAlgorithmError:
81
- if kwargs.get("raise_exception", True):
82
- raise USSOException(status_code=401, error="invalid_algorithm")
83
- except jwt.exceptions.InvalidIssuedAtError:
84
- if kwargs.get("raise_exception", True):
85
- raise USSOException(status_code=401, error="invalid_issued_at")
86
- except jwt.exceptions.InvalidTokenError:
87
- if kwargs.get("raise_exception", True):
88
- raise USSOException(status_code=401, error="invalid_token")
89
- except jwt.exceptions.InvalidKeyError:
90
- if kwargs.get("raise_exception", True):
91
- raise USSOException(status_code=401, error="invalid_key")
92
- except USSOException as e:
93
- if kwargs.get("raise_exception", True):
94
- raise e
95
- except Exception as e:
96
- if kwargs.get("raise_exception", True):
97
- raise USSOException(status_code=401, error="error", message=str(e))
98
- logger.error(e)
149
+ *,
150
+ jwt_config: str | dict | JWTConfig | None = None,
151
+ jwt_configs: list[str] | list[dict] | list[JWTConfig] | None = None,
152
+ ):
153
+ if jwt_config is None and jwt_configs is None:
154
+ jwt_config = os.getenv("USSO_JWT_CONFIG")
155
+
156
+ if jwt_config is None and jwt_configs is None:
157
+ jwk_url = os.getenv("USSO_JWK_URL") or os.getenv("USSO_JWKS_URL")
158
+ if not jwk_url:
159
+ self.jwt_configs = [JWTConfig(jwk_url=jwk_url)]
160
+ return
161
+
162
+ raise ValueError(
163
+ "\n".join(
164
+ [
165
+ "Either jwt_config or jwt_configs must be provided",
166
+ "or set the environment variable USSO_JWT_CONFIG or USSO_JWK_URL",
167
+ ]
168
+ )
169
+ )
170
+
171
+ def _get_config(jwt_config):
172
+ if isinstance(jwt_config, str):
173
+ jwt_config = json.loads(jwt_config)
174
+ if isinstance(jwt_config, dict):
175
+ jwt_config = JWTConfig(**jwt_config)
176
+ return jwt_config
177
+
178
+ if isinstance(jwt_config, str | dict | JWTConfig):
179
+ jwt_config = [_get_config(jwt_config)]
180
+ elif isinstance(jwt_config, list):
181
+ jwt_config = [_get_config(j) for j in jwt_config]
182
+
183
+ # self.jwk_url = jwt_config
184
+ self.jwt_configs = jwt_config
99
185
 
100
186
  def user_data_from_token(self, token: str, **kwargs) -> UserData | None:
101
187
  """Return the user associated with a token value."""
102
- try:
103
- jwks_client = self.get_jwks_keys()
104
- signing_key = jwks_client.get_signing_key_from_jwt(token)
105
- return self.decode_token(signing_key.key, token, **kwargs)
106
- except Exception as e:
107
- if kwargs.get("raise_exception", True):
108
- raise USSOException(
109
- status_code=401,
110
- error="error",
111
- message=str(e),
112
- )
113
- logger.error(e)
188
+ exp = None
189
+ for jwk_config in self.jwt_configs:
190
+ try:
191
+ return jwk_config.decode(token)
192
+ except USSOException as e:
193
+ exp = e
194
+
195
+ if kwargs.get("raise_exception", True):
196
+ if exp:
197
+ raise exp
198
+ raise USSOException(
199
+ status_code=401,
200
+ error="unauthorized",
201
+ )
@@ -3,9 +3,10 @@ import logging
3
3
  from fastapi import Request, WebSocket
4
4
  from starlette.status import HTTP_401_UNAUTHORIZED
5
5
 
6
- from usso.core import UserData, Usso
7
6
  from usso.exceptions import USSOException
8
7
 
8
+ from ..core import UserData, Usso
9
+
9
10
  logger = logging.getLogger("usso")
10
11
 
11
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: usso
3
- Version: 0.24.19
3
+ Version: 0.25.1
4
4
  Summary: A plug-and-play client for integrating universal single sign-on (SSO) with Python frameworks, enabling secure and seamless authentication across microservices.
5
5
  Author-email: Mahdi Kiani <mahdikiany@gmail.com>
6
6
  Maintainer-email: Mahdi Kiani <mahdikiany@gmail.com>
@@ -46,6 +46,7 @@ Requires-Dist: pydantic >=2
46
46
  Requires-Dist: requests >=2.26.0
47
47
  Requires-Dist: pyjwt[crypto]
48
48
  Requires-Dist: singleton-package
49
+ Requires-Dist: cachetools
49
50
  Provides-Extra: dev
50
51
  Requires-Dist: check-manifest ; extra == 'dev'
51
52
  Provides-Extra: django
@@ -53,7 +54,6 @@ Requires-Dist: Django >=3.2 ; extra == 'django'
53
54
  Provides-Extra: fastapi
54
55
  Requires-Dist: fastapi >=0.65.0 ; extra == 'fastapi'
55
56
  Requires-Dist: uvicorn[standard] >=0.13.0 ; extra == 'fastapi'
56
- Requires-Dist: cachetools ; extra == 'fastapi'
57
57
  Provides-Extra: test
58
58
  Requires-Dist: coverage ; extra == 'test'
59
59
 
@@ -0,0 +1,18 @@
1
+ usso/__init__.py,sha256=NnOS_S1a-JKTOlGe1nw-kCL3m0y82mA2mDraus7BQ2o,120
2
+ usso/api.py,sha256=xlDq2nZNpq3mhAvqIbGEfANHNjJpPquSeULBfS7iMJw,5094
3
+ usso/async_api.py,sha256=rb-Xh5oudmZrPYM_iH_B75b5Z0Fvi1V1uurdcKE51w0,5551
4
+ usso/async_session.py,sha256=nFIrtV3Tp0H-s2ZkMLU9_fVSeVGq1EtY1bGT_XOS5Vw,4336
5
+ usso/b64tools.py,sha256=HGQ0E59vzjrQo2-4jrcY03ebtTaYwTtCZ7KgJaEmxO0,610
6
+ usso/core.py,sha256=vrGpfueuX3CwkBdGj9ze-BPuI61TOlLPsCqHiKOQnFY,6510
7
+ usso/exceptions.py,sha256=hawOAuVbvQtjgRfwp1KFZ4SmV7fh720y5Gom9JVA8W8,504
8
+ usso/session.py,sha256=Lky2O8FGbOMJFOMxxdE0rhpgwWKThGQfr-X9YQsFpLk,2358
9
+ usso/django/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ usso/django/middleware.py,sha256=EEEpHvMQ6QiWw2HY8zQ2Aec0RCATcLWsCKeyiPWJKio,3245
11
+ usso/fastapi/__init__.py,sha256=0EcdOzb4f3yu9nILIdGWnlyUz-0VaVX2az1e3f2BusI,201
12
+ usso/fastapi/integration.py,sha256=LNKd_KStKr5CBj_CUfwkrgtiY5R8nBL61FVBWcIrhQE,1667
13
+ usso-0.25.1.dist-info/LICENSE.txt,sha256=ceC9ZJOV9H6CtQDcYmHOS46NA3dHJ_WD4J9blH513pc,1081
14
+ usso-0.25.1.dist-info/METADATA,sha256=z1rpx_Pqk64o-Bpi6q38jpHDYZDGr9jiYha05I1jxBg,4227
15
+ usso-0.25.1.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
16
+ usso-0.25.1.dist-info/entry_points.txt,sha256=4Zgpm5ELaAWPf0jPGJFz1_X69H7un8ycT3WdGoJ0Vvk,35
17
+ usso-0.25.1.dist-info/top_level.txt,sha256=g9Jf6h1Oyidh0vPiFni7UHInTJjSvu6cUalpLTIvthg,5
18
+ usso-0.25.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.1.0)
2
+ Generator: setuptools (75.2.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,186 +0,0 @@
1
- import json
2
- import logging
3
- import os
4
-
5
- import cachetools.func
6
- import jwt
7
- from fastapi import Request, WebSocket
8
- from pydantic import BaseModel, model_validator
9
- from starlette.status import HTTP_401_UNAUTHORIZED
10
-
11
- from usso.core import UserData
12
- from usso.exceptions import USSOException
13
-
14
- logger = logging.getLogger("usso")
15
-
16
-
17
- class JWTConfig(BaseModel):
18
- jwk_url: str | None = None
19
- secret: str | None = None
20
- type: str = "RS256"
21
- header: dict[str, str] = {"type": "Cookie", "name": "usso_access_token"}
22
-
23
- def __hash__(self):
24
- return hash(self.model_dump_json())
25
-
26
- @model_validator(mode="before")
27
- def validate_secret(cls, data: dict):
28
- if not data.get("jwk_url") and not data.get("secret"):
29
- raise ValueError("Either jwk_url or secret must be provided")
30
- return data
31
-
32
- @classmethod
33
- @cachetools.func.ttl_cache(maxsize=128, ttl=10 * 60)
34
- def get_jwk_keys(cls, jwk_url):
35
- return jwt.PyJWKClient(
36
- jwk_url,
37
- headers={
38
- "User-Agent": "usso-python",
39
- },
40
- )
41
-
42
- @cachetools.func.ttl_cache(maxsize=128, ttl=10 * 60)
43
- def decode(self, token: str):
44
- if self.jwk_url:
45
- jwk_client = self.get_jwk_keys(self.jwk_url)
46
- signing_key = jwk_client.get_signing_key_from_jwt(token)
47
- return jwt.decode(token, signing_key.key, algorithms=[self.type])
48
-
49
- return jwt.decode(token, self.secret, algorithms=[self.type])
50
-
51
-
52
- class Usso:
53
-
54
- def __init__(self, jwt_config: str | dict | JWTConfig | None = None):
55
- if jwt_config is None:
56
- self.jwk_url = os.getenv("USSO_JWK_URL")
57
- return
58
-
59
- if isinstance(jwt_config, str):
60
- jwt_config = json.loads(jwt_config)
61
- if isinstance(jwt_config, dict):
62
- jwt_config = JWTConfig(**jwt_config)
63
-
64
- self.jwk_url = jwt_config
65
- self.jwt_config = jwt_config
66
-
67
- def get_authorization_scheme_param(
68
- self,
69
- authorization_header_value: str | None,
70
- ) -> tuple[str, str]:
71
- if not authorization_header_value:
72
- return "", ""
73
- scheme, _, param = authorization_header_value.partition(" ")
74
- return scheme, param
75
-
76
- def decode_token(self, key, token: str, **kwargs) -> dict:
77
- try:
78
- decoded = jwt.decode(token, key, algorithms=["RS256"])
79
- if decoded["token_type"] != "access":
80
- raise USSOException(status_code=401, error="invalid_token_type")
81
- decoded["token"] = token
82
- return UserData(**decoded)
83
- except jwt.exceptions.ExpiredSignatureError:
84
- if kwargs.get("raise_exception", True):
85
- raise USSOException(status_code=401, error="expired_signature")
86
- except jwt.exceptions.InvalidSignatureError:
87
- if kwargs.get("raise_exception", True):
88
- raise USSOException(status_code=401, error="invalid_signature")
89
- except jwt.exceptions.InvalidAlgorithmError:
90
- if kwargs.get("raise_exception", True):
91
- raise USSOException(status_code=401, error="invalid_algorithm")
92
- except jwt.exceptions.InvalidIssuedAtError:
93
- if kwargs.get("raise_exception", True):
94
- raise USSOException(status_code=401, error="invalid_issued_at")
95
- except jwt.exceptions.InvalidTokenError:
96
- if kwargs.get("raise_exception", True):
97
- raise USSOException(status_code=401, error="invalid_token")
98
- except jwt.exceptions.InvalidKeyError:
99
- if kwargs.get("raise_exception", True):
100
- raise USSOException(status_code=401, error="invalid_key")
101
- except USSOException as e:
102
- if kwargs.get("raise_exception", True):
103
- raise e
104
- except Exception as e:
105
- if kwargs.get("raise_exception", True):
106
- raise USSOException(status_code=401, error="error", message=str(e))
107
- logger.error(e)
108
-
109
- def user_data_from_token(self, token: str, **kwargs) -> UserData | None:
110
- """Return the user associated with a token value."""
111
- try:
112
- decoded = self.jwk_url.decode(token)
113
- if decoded["token_type"] != "access":
114
- raise USSOException(status_code=401, error="invalid_token_type")
115
- decoded["token"] = token
116
- return UserData(**decoded)
117
- except jwt.exceptions.ExpiredSignatureError:
118
- if kwargs.get("raise_exception", True):
119
- raise USSOException(status_code=401, error="expired_signature")
120
- except jwt.exceptions.InvalidSignatureError:
121
- if kwargs.get("raise_exception", True):
122
- raise USSOException(status_code=401, error="invalid_signature")
123
- except jwt.exceptions.InvalidAlgorithmError:
124
- if kwargs.get("raise_exception", True):
125
- raise USSOException(status_code=401, error="invalid_algorithm")
126
- except jwt.exceptions.InvalidIssuedAtError:
127
- if kwargs.get("raise_exception", True):
128
- raise USSOException(status_code=401, error="invalid_issued_at")
129
- except jwt.exceptions.InvalidTokenError:
130
- if kwargs.get("raise_exception", True):
131
- raise USSOException(status_code=401, error="invalid_token")
132
- except jwt.exceptions.InvalidKeyError:
133
- if kwargs.get("raise_exception", True):
134
- raise USSOException(status_code=401, error="invalid_key")
135
- except KeyError as e:
136
- if kwargs.get("raise_exception", True):
137
- raise USSOException(status_code=401, error="key_error", message=str(e))
138
- except USSOException as e:
139
- if kwargs.get("raise_exception", True):
140
- raise e
141
- except Exception as e:
142
- if kwargs.get("raise_exception", True):
143
- raise USSOException(status_code=401, error="error", message=str(e))
144
- logger.error(e)
145
-
146
- async def jwt_access_security(self, request: Request) -> UserData | None:
147
- """Return the user associated with a token value."""
148
- kwargs = {}
149
- authorization = request.headers.get("Authorization")
150
- if authorization:
151
- scheme, credentials = self.get_authorization_scheme_param(authorization)
152
- if scheme.lower() == "bearer":
153
- token = credentials
154
- return self.user_data_from_token(token, **kwargs)
155
-
156
- cookie_token = request.cookies.get("usso_access_token")
157
- if cookie_token:
158
- return self.user_data_from_token(cookie_token, **kwargs)
159
-
160
- if kwargs.get("raise_exception", True):
161
- raise USSOException(
162
- status_code=HTTP_401_UNAUTHORIZED,
163
- error="unauthorized",
164
- )
165
- return None
166
-
167
- async def jwt_access_security_ws(self, websocket: WebSocket) -> UserData | None:
168
- """Return the user associated with a token value."""
169
- kwargs = {}
170
- authorization = websocket.headers.get("Authorization")
171
- if authorization:
172
- scheme, credentials = self.get_authorization_scheme_param(authorization)
173
- if scheme.lower() == "bearer":
174
- token = credentials
175
- return self.user_data_from_token(token, **kwargs)
176
-
177
- cookie_token = websocket.cookies.get("usso_access_token")
178
- if cookie_token:
179
- return self.user_data_from_token(cookie_token, **kwargs)
180
-
181
- if kwargs.get("raise_exception", True):
182
- raise USSOException(
183
- status_code=HTTP_401_UNAUTHORIZED,
184
- error="unauthorized",
185
- )
186
- return None
usso/package_data.dat DELETED
File without changes
@@ -1,20 +0,0 @@
1
- usso/__init__.py,sha256=NnOS_S1a-JKTOlGe1nw-kCL3m0y82mA2mDraus7BQ2o,120
2
- usso/api.py,sha256=xlDq2nZNpq3mhAvqIbGEfANHNjJpPquSeULBfS7iMJw,5094
3
- usso/async_api.py,sha256=rb-Xh5oudmZrPYM_iH_B75b5Z0Fvi1V1uurdcKE51w0,5551
4
- usso/async_session.py,sha256=9i74AAcLYzwRkffvDOG64DBvJd-cQG31656RhhpkRtE,4363
5
- usso/b64tools.py,sha256=HGQ0E59vzjrQo2-4jrcY03ebtTaYwTtCZ7KgJaEmxO0,610
6
- usso/core.py,sha256=cOpETK_gGVsUJT0EeIebOGLEbF8vHVET-_I-8QxOCyE,3977
7
- usso/exceptions.py,sha256=hawOAuVbvQtjgRfwp1KFZ4SmV7fh720y5Gom9JVA8W8,504
8
- usso/package_data.dat,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- usso/session.py,sha256=Lky2O8FGbOMJFOMxxdE0rhpgwWKThGQfr-X9YQsFpLk,2358
10
- usso/django/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- usso/django/middleware.py,sha256=EEEpHvMQ6QiWw2HY8zQ2Aec0RCATcLWsCKeyiPWJKio,3245
12
- usso/fastapi/__init__.py,sha256=0EcdOzb4f3yu9nILIdGWnlyUz-0VaVX2az1e3f2BusI,201
13
- usso/fastapi/auth_middleware.py,sha256=DYrNPy_9FIV1amRuafoJtgGMi8uE0FPmSKBUGP79GNo,7616
14
- usso/fastapi/integration.py,sha256=VAUWaa7ChQ1jTtn8A136VgyG6t2kDo5pGK-3RgmNDVs,1669
15
- usso-0.24.19.dist-info/LICENSE.txt,sha256=ceC9ZJOV9H6CtQDcYmHOS46NA3dHJ_WD4J9blH513pc,1081
16
- usso-0.24.19.dist-info/METADATA,sha256=cszPw64wfliP6WNFYMxLUJIQop7-UZDSvHKVHADRYQE,4249
17
- usso-0.24.19.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
18
- usso-0.24.19.dist-info/entry_points.txt,sha256=4Zgpm5ELaAWPf0jPGJFz1_X69H7un8ycT3WdGoJ0Vvk,35
19
- usso-0.24.19.dist-info/top_level.txt,sha256=g9Jf6h1Oyidh0vPiFni7UHInTJjSvu6cUalpLTIvthg,5
20
- usso-0.24.19.dist-info/RECORD,,