usso 0.25.4__tar.gz → 0.26.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.
Files changed (27) hide show
  1. {usso-0.25.4/src/usso.egg-info → usso-0.26.1}/PKG-INFO +10 -1
  2. {usso-0.25.4 → usso-0.26.1}/pyproject.toml +2 -2
  3. usso-0.26.1/src/usso/httpx_session.py +87 -0
  4. {usso-0.25.4 → usso-0.26.1}/src/usso/session.py +2 -0
  5. {usso-0.25.4 → usso-0.26.1/src/usso.egg-info}/PKG-INFO +10 -1
  6. {usso-0.25.4 → usso-0.26.1}/src/usso.egg-info/SOURCES.txt +1 -0
  7. {usso-0.25.4 → usso-0.26.1}/src/usso.egg-info/requires.txt +11 -0
  8. {usso-0.25.4 → usso-0.26.1}/LICENSE.txt +0 -0
  9. {usso-0.25.4 → usso-0.26.1}/README.md +0 -0
  10. {usso-0.25.4 → usso-0.26.1}/setup.cfg +0 -0
  11. {usso-0.25.4 → usso-0.26.1}/src/usso/__init__.py +0 -0
  12. {usso-0.25.4 → usso-0.26.1}/src/usso/api.py +0 -0
  13. {usso-0.25.4 → usso-0.26.1}/src/usso/async_api.py +0 -0
  14. {usso-0.25.4 → usso-0.26.1}/src/usso/async_session.py +0 -0
  15. {usso-0.25.4 → usso-0.26.1}/src/usso/b64tools.py +0 -0
  16. {usso-0.25.4 → usso-0.26.1}/src/usso/core.py +0 -0
  17. {usso-0.25.4 → usso-0.26.1}/src/usso/django/__init__.py +0 -0
  18. {usso-0.25.4 → usso-0.26.1}/src/usso/django/middleware.py +0 -0
  19. {usso-0.25.4 → usso-0.26.1}/src/usso/exceptions.py +0 -0
  20. {usso-0.25.4 → usso-0.26.1}/src/usso/fastapi/__init__.py +0 -0
  21. {usso-0.25.4 → usso-0.26.1}/src/usso/fastapi/integration.py +0 -0
  22. {usso-0.25.4 → usso-0.26.1}/src/usso.egg-info/dependency_links.txt +0 -0
  23. {usso-0.25.4 → usso-0.26.1}/src/usso.egg-info/entry_points.txt +0 -0
  24. {usso-0.25.4 → usso-0.26.1}/src/usso.egg-info/top_level.txt +0 -0
  25. {usso-0.25.4 → usso-0.26.1}/tests/test_api.py +0 -0
  26. {usso-0.25.4 → usso-0.26.1}/tests/test_core.py +0 -0
  27. {usso-0.25.4 → usso-0.26.1}/tests/test_simple.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: usso
3
- Version: 0.25.4
3
+ Version: 0.26.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>
@@ -51,10 +51,19 @@ Requires-Dist: fastapi>=0.65.0; extra == "fastapi"
51
51
  Requires-Dist: uvicorn[standard]>=0.13.0; extra == "fastapi"
52
52
  Provides-Extra: django
53
53
  Requires-Dist: Django>=3.2; extra == "django"
54
+ Provides-Extra: httpx
55
+ Requires-Dist: httpx; extra == "httpx"
54
56
  Provides-Extra: dev
55
57
  Requires-Dist: check-manifest; extra == "dev"
56
58
  Provides-Extra: test
57
59
  Requires-Dist: coverage; extra == "test"
60
+ Provides-Extra: all
61
+ Requires-Dist: fastapi; extra == "all"
62
+ Requires-Dist: uvicorn; extra == "all"
63
+ Requires-Dist: django; extra == "all"
64
+ Requires-Dist: httpx; extra == "all"
65
+ Requires-Dist: dev; extra == "all"
66
+ Requires-Dist: test; extra == "all"
58
67
 
59
68
  # USSO-Client
60
69
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "usso"
7
- version = "0.25.4"
7
+ version = "0.26.1"
8
8
  description = "A plug-and-play client for integrating universal single sign-on (SSO) with Python frameworks, enabling secure and seamless authentication across microservices."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -34,7 +34,7 @@ dependencies = [
34
34
  # "singleton_package",
35
35
  "cachetools",
36
36
  ]
37
- optional-dependencies = {"fastapi" = ["fastapi>=0.65.0", "uvicorn[standard]>=0.13.0"],"django" = ["Django>=3.2"],"dev" = ["check-manifest"],"test" = ["coverage"]}
37
+ optional-dependencies = {"fastapi"=["fastapi>=0.65.0", "uvicorn[standard]>=0.13.0"], "django"=["Django>=3.2"], "httpx"=["httpx"], "dev"=["check-manifest"], "test" = ["coverage"], "all"=["fastapi", "uvicorn", "django", "httpx", "dev", "test"]}
38
38
 
39
39
  [project.urls]
40
40
  "Homepage" = "https://github.com/ussoio/usso-python"
@@ -0,0 +1,87 @@
1
+ from datetime import datetime, timedelta
2
+
3
+ import httpx
4
+ import jwt
5
+
6
+
7
+ class AsyncUssoSession(httpx.AsyncClient):
8
+ def __init__(
9
+ self,
10
+ sso_refresh_url: str,
11
+ refresh_token: str | None = None,
12
+ api_key: str | None = None,
13
+ user_id: str | None = None,
14
+ ):
15
+ super().__init__()
16
+ self.sso_refresh_url = sso_refresh_url
17
+ self._refresh_token = refresh_token
18
+ self.access_token = None
19
+ self.session = None # This will hold the aiohttp session
20
+ self.api_key = api_key
21
+ self.user_id = user_id
22
+
23
+ @property
24
+ def refresh_token(self):
25
+ if self._refresh_token:
26
+ decoded_token = jwt.decode(
27
+ self._refresh_token, options={"verify_signature": False}
28
+ )
29
+ exp = decoded_token.get(
30
+ "exp", (datetime.now() + timedelta(days=1)).timestamp()
31
+ )
32
+ exp = datetime.fromtimestamp(exp)
33
+ if exp < datetime.now():
34
+ self._refresh_token = None
35
+
36
+ return self._refresh_token
37
+
38
+ async def _refresh_api(self):
39
+ params = {"user_id": self.user_id} if self.user_id else {}
40
+ async with httpx.AsyncClient() as session:
41
+ response = await session.get(
42
+ f"{self.sso_refresh_url}/api",
43
+ headers={"x-api-key": self.api_key},
44
+ params=params,
45
+ )
46
+ response.raise_for_status()
47
+ data: dict = response.json()
48
+ self._refresh_token = data.get("token", {}).get("refresh_token")
49
+
50
+ async def _refresh(self):
51
+ if not self.refresh_token and not self.api_key:
52
+ raise ValueError("Refresh token not provided or invalid.")
53
+
54
+ if self.api_key and not self.refresh_token:
55
+ await self._refresh_api()
56
+
57
+ async with httpx.AsyncClient() as session:
58
+ response = await session.post(
59
+ self.sso_refresh_url, json={"refresh_token": self.refresh_token}
60
+ )
61
+ response.raise_for_status()
62
+ return response.json()
63
+
64
+ async def _ensure_valid_token(self):
65
+ if self.access_token:
66
+ decoded_token = jwt.decode(
67
+ self.access_token, options={"verify_signature": False}
68
+ )
69
+ exp = decoded_token.get("exp")
70
+
71
+ if exp and datetime.fromtimestamp(exp) < datetime.now():
72
+ self.access_token = None # Token expired, need a new one
73
+
74
+ if not self.access_token:
75
+ # Get a new token if none exists or it has expired
76
+ token_data = await self._refresh()
77
+ self.access_token = token_data.get("access_token")
78
+
79
+ async def request(self, method: str, url: str, *args, **kwargs):
80
+ await self._ensure_valid_token()
81
+
82
+ # Add authorization header to each request
83
+ headers = kwargs.pop("headers") or {}
84
+ headers["Authorization"] = f"Bearer {self.access_token}"
85
+
86
+ # Call the parent's request method
87
+ return await super().request(method, url, headers=headers, *args, **kwargs)
@@ -58,6 +58,8 @@ class UssoSession:
58
58
  json={"refresh_token": f"{self.refresh_token}"},
59
59
  )
60
60
  response.raise_for_status()
61
+ self.access_token = response.json().get("access_token")
62
+ self.session.headers.update({"Authorization": f"Bearer {self.access_token}"})
61
63
  return response.json()
62
64
 
63
65
  def get_session(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: usso
3
- Version: 0.25.4
3
+ Version: 0.26.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>
@@ -51,10 +51,19 @@ Requires-Dist: fastapi>=0.65.0; extra == "fastapi"
51
51
  Requires-Dist: uvicorn[standard]>=0.13.0; extra == "fastapi"
52
52
  Provides-Extra: django
53
53
  Requires-Dist: Django>=3.2; extra == "django"
54
+ Provides-Extra: httpx
55
+ Requires-Dist: httpx; extra == "httpx"
54
56
  Provides-Extra: dev
55
57
  Requires-Dist: check-manifest; extra == "dev"
56
58
  Provides-Extra: test
57
59
  Requires-Dist: coverage; extra == "test"
60
+ Provides-Extra: all
61
+ Requires-Dist: fastapi; extra == "all"
62
+ Requires-Dist: uvicorn; extra == "all"
63
+ Requires-Dist: django; extra == "all"
64
+ Requires-Dist: httpx; extra == "all"
65
+ Requires-Dist: dev; extra == "all"
66
+ Requires-Dist: test; extra == "all"
58
67
 
59
68
  # USSO-Client
60
69
 
@@ -8,6 +8,7 @@ src/usso/async_session.py
8
8
  src/usso/b64tools.py
9
9
  src/usso/core.py
10
10
  src/usso/exceptions.py
11
+ src/usso/httpx_session.py
11
12
  src/usso/session.py
12
13
  src/usso.egg-info/PKG-INFO
13
14
  src/usso.egg-info/SOURCES.txt
@@ -3,6 +3,14 @@ requests>=2.26.0
3
3
  pyjwt[crypto]
4
4
  cachetools
5
5
 
6
+ [all]
7
+ fastapi
8
+ uvicorn
9
+ django
10
+ httpx
11
+ dev
12
+ test
13
+
6
14
  [dev]
7
15
  check-manifest
8
16
 
@@ -13,5 +21,8 @@ Django>=3.2
13
21
  fastapi>=0.65.0
14
22
  uvicorn[standard]>=0.13.0
15
23
 
24
+ [httpx]
25
+ httpx
26
+
16
27
  [test]
17
28
  coverage
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
File without changes
File without changes
File without changes
File without changes
File without changes