fastapi-sso 0.10.0__tar.gz → 0.12.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 (21) hide show
  1. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/PKG-INFO +5 -2
  2. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/README.md +2 -0
  3. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/__init__.py +2 -0
  4. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/sso/base.py +20 -0
  5. fastapi_sso-0.12.0/fastapi_sso/sso/line.py +37 -0
  6. fastapi_sso-0.12.0/fastapi_sso/sso/linkedin.py +37 -0
  7. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/sso/spotify.py +0 -1
  8. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/pyproject.toml +12 -3
  9. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/LICENSE.md +0 -0
  10. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/py.typed +0 -0
  11. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/sso/__init__.py +0 -0
  12. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/sso/facebook.py +0 -0
  13. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/sso/fitbit.py +0 -0
  14. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/sso/generic.py +0 -0
  15. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/sso/github.py +0 -0
  16. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/sso/gitlab.py +0 -0
  17. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/sso/google.py +0 -0
  18. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/sso/kakao.py +0 -0
  19. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/sso/microsoft.py +0 -0
  20. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/sso/naver.py +0 -0
  21. {fastapi_sso-0.10.0 → fastapi_sso-0.12.0}/fastapi_sso/sso/notion.py +0 -0
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastapi-sso
3
- Version: 0.10.0
3
+ Version: 0.12.0
4
4
  Summary: FastAPI plugin to enable SSO to most common providers (such as Facebook login, Google login and login via Microsoft Office 365 Account)
5
5
  Home-page: https://tomasvotava.github.io/fastapi-sso/
6
6
  License: MIT
7
- Keywords: fastapi,sso,oauth,google,facebook,spotify
7
+ Keywords: fastapi,sso,oauth,google,facebook,spotify,linkedin
8
8
  Author: Tomas Votava
9
9
  Author-email: info@tomasvotava.eu
10
10
  Requires-Python: >=3.8,<4.0
@@ -19,6 +19,7 @@ Requires-Dist: fastapi (>=0.80)
19
19
  Requires-Dist: httpx (>=0.23.0)
20
20
  Requires-Dist: oauthlib (>=3.1.0)
21
21
  Requires-Dist: pydantic[email] (>=1.8.0)
22
+ Requires-Dist: pylint (>=3.0.3,<4.0.0)
22
23
  Project-URL: Documentation, https://tomasvotava.github.io/fastapi-sso/
23
24
  Project-URL: Repository, https://github.com/tomasvotava/fastapi-sso
24
25
  Description-Content-Type: text/markdown
@@ -82,6 +83,8 @@ I tend to process Pull Requests faster when properly caffeinated 😉.
82
83
  - Kakao (by Jae-Baek Song - [thdwoqor](https://github.com/thdwoqor))
83
84
  - Naver (by 1tang2bang92) - [1tang2bang92](https://github.com/1tang2bang92)
84
85
  - Gitlab (by Alessandro Pischedda) - [Cereal84](https://github.com/Cereal84)
86
+ - Line (by Jimmy Yeh) - [jimmyyyeh](https://github.com/jimmyyyeh)
87
+ - LinkedIn (by Alessandro Pischedda) - [Cereal84](https://github.com/Cereal84)
85
88
 
86
89
  See [Contributing](#contributing) for a guide on how to contribute your own login provider.
87
90
 
@@ -57,6 +57,8 @@ I tend to process Pull Requests faster when properly caffeinated 😉.
57
57
  - Kakao (by Jae-Baek Song - [thdwoqor](https://github.com/thdwoqor))
58
58
  - Naver (by 1tang2bang92) - [1tang2bang92](https://github.com/1tang2bang92)
59
59
  - Gitlab (by Alessandro Pischedda) - [Cereal84](https://github.com/Cereal84)
60
+ - Line (by Jimmy Yeh) - [jimmyyyeh](https://github.com/jimmyyyeh)
61
+ - LinkedIn (by Alessandro Pischedda) - [Cereal84](https://github.com/Cereal84)
60
62
 
61
63
  See [Contributing](#contributing) for a guide on how to contribute your own login provider.
62
64
 
@@ -10,6 +10,8 @@ from .sso.github import GithubSSO
10
10
  from .sso.gitlab import GitlabSSO
11
11
  from .sso.google import GoogleSSO
12
12
  from .sso.kakao import KakaoSSO
13
+ from .sso.line import LineSSO
14
+ from .sso.linkedin import LinkedInSSO
13
15
  from .sso.microsoft import MicrosoftSSO
14
16
  from .sso.naver import NaverSSO
15
17
  from .sso.notion import NotionSSO
@@ -1,5 +1,6 @@
1
1
  """SSO login base dependency
2
2
  """
3
+
3
4
  # pylint: disable=too-few-public-methods
4
5
 
5
6
  import json
@@ -93,6 +94,7 @@ class SSOBase:
93
94
  )
94
95
  self.scope = scope or self.scope
95
96
  self._refresh_token: Optional[str] = None
97
+ self._id_token: Optional[str] = None
96
98
  self._state: Optional[str] = None
97
99
 
98
100
  @property
@@ -153,6 +155,16 @@ class SSOBase:
153
155
  """
154
156
  return self._refresh_token or self.oauth_client.refresh_token
155
157
 
158
+ @property
159
+ def id_token(self) -> Optional[str]:
160
+ """
161
+ Retrieves the id token if returned from provider.
162
+
163
+ Returns:
164
+ Optional[str]: The id token if available.
165
+ """
166
+ return self._id_token
167
+
156
168
  async def openid_from_response(self, response: dict, session: Optional[httpx.AsyncClient] = None) -> OpenID:
157
169
  """
158
170
  Converts a response from the provider's user info endpoint to an OpenID object.
@@ -286,6 +298,7 @@ class SSOBase:
286
298
  def __enter__(self) -> "SSOBase":
287
299
  self._oauth_client = None
288
300
  self._refresh_token = None
301
+ self._id_token = None
289
302
  return self
290
303
 
291
304
  def __exit__(
@@ -296,6 +309,10 @@ class SSOBase:
296
309
  ) -> None:
297
310
  return None
298
311
 
312
+ @property
313
+ def _extra_query_params(self) -> Dict:
314
+ return {}
315
+
299
316
  async def process_login(
300
317
  self,
301
318
  code: str,
@@ -326,6 +343,7 @@ class SSOBase:
326
343
  if self._oauth_client is not None: # pragma: no cover
327
344
  self._oauth_client = None
328
345
  self._refresh_token = None
346
+ self._id_token = None
329
347
  warnings.warn(
330
348
  (
331
349
  "Reusing the SSO object is not safe and caused a security issue in previous versions."
@@ -334,6 +352,7 @@ class SSOBase:
334
352
  ReusedOauthClientWarning,
335
353
  )
336
354
  params = params or {}
355
+ params.update(self._extra_query_params)
337
356
  additional_headers = additional_headers or {}
338
357
  additional_headers.update(self.additional_headers or {})
339
358
 
@@ -364,6 +383,7 @@ class SSOBase:
364
383
  response = await session.post(token_url, headers=headers, content=body, auth=auth)
365
384
  content = response.json()
366
385
  self._refresh_token = content.get("refresh_token")
386
+ self._id_token = content.get("id_token")
367
387
  self.oauth_client.parse_request_body_response(json.dumps(content))
368
388
 
369
389
  uri, headers, _ = self.oauth_client.add_token(await self.userinfo_endpoint)
@@ -0,0 +1,37 @@
1
+ """Line SSO Login Helper
2
+ """
3
+
4
+ from typing import TYPE_CHECKING, Optional
5
+
6
+ from fastapi_sso.sso.base import DiscoveryDocument, OpenID, SSOBase
7
+
8
+ if TYPE_CHECKING:
9
+ import httpx
10
+
11
+
12
+ class LineSSO(SSOBase):
13
+ """Class providing login via Line OAuth"""
14
+
15
+ provider = "line"
16
+ base_url = "https://api.line.me/oauth2/v2.1"
17
+ scope = ["email", "profile", "openid"]
18
+
19
+ async def get_discovery_document(self) -> DiscoveryDocument:
20
+ """Get document containing handy urls"""
21
+ return {
22
+ "authorization_endpoint": "https://access.line.me/oauth2/v2.1/authorize",
23
+ "token_endpoint": f"{self.base_url}/token",
24
+ "userinfo_endpoint": f"{self.base_url}/userinfo",
25
+ }
26
+
27
+ async def openid_from_response(self, response: dict, session: Optional["httpx.AsyncClient"] = None) -> OpenID:
28
+ """Return OpenID from user information provided by Line"""
29
+ return OpenID(
30
+ email=response.get("email"),
31
+ first_name=None,
32
+ last_name=None,
33
+ display_name=response.get("name"),
34
+ provider=self.provider,
35
+ id=response.get("sub"),
36
+ picture=response.get("picture"),
37
+ )
@@ -0,0 +1,37 @@
1
+ """LinkedIn SSO Oauth Helper class"""
2
+
3
+ from typing import TYPE_CHECKING, Dict, Optional
4
+
5
+ from fastapi_sso.sso.base import DiscoveryDocument, OpenID, SSOBase
6
+
7
+ if TYPE_CHECKING:
8
+ import httpx
9
+
10
+
11
+ class LinkedInSSO(SSOBase):
12
+ """Class providing login via LinkedIn SSO"""
13
+
14
+ provider = "linkedin"
15
+ scope = ["openid", "profile", "email"]
16
+ additional_headers = {"accept": "application/json"}
17
+
18
+ @property
19
+ def _extra_query_params(self) -> Dict:
20
+ return {"client_secret": self.client_secret}
21
+
22
+ async def get_discovery_document(self) -> DiscoveryDocument:
23
+ return {
24
+ "authorization_endpoint": "https://www.linkedin.com/oauth/v2/authorization",
25
+ "token_endpoint": "https://www.linkedin.com/oauth/v2/accessToken",
26
+ "userinfo_endpoint": "https://api.linkedin.com/v2/userinfo",
27
+ }
28
+
29
+ async def openid_from_response(self, response: dict, session: Optional["httpx.AsyncClient"] = None) -> OpenID:
30
+ return OpenID(
31
+ email=response.get("email"),
32
+ provider=self.provider,
33
+ id=response["sub"],
34
+ first_name=response["given_name"],
35
+ last_name=response["family_name"],
36
+ picture=response["picture"],
37
+ )
@@ -1,7 +1,6 @@
1
1
  """Spotify SSO Login Helper
2
2
  """
3
3
 
4
-
5
4
  from typing import TYPE_CHECKING, Optional
6
5
 
7
6
  from fastapi_sso.sso.base import DiscoveryDocument, OpenID, SSOBase
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "fastapi-sso"
3
- version = "0.10.0"
3
+ version = "0.12.0"
4
4
  description = "FastAPI plugin to enable SSO to most common providers (such as Facebook login, Google login and login via Microsoft Office 365 Account)"
5
5
  authors = ["Tomas Votava <info@tomasvotava.eu>"]
6
6
  readme = "README.md"
@@ -8,7 +8,15 @@ license = "MIT"
8
8
  repository = "https://github.com/tomasvotava/fastapi-sso"
9
9
  homepage = "https://tomasvotava.github.io/fastapi-sso/"
10
10
  documentation = "https://tomasvotava.github.io/fastapi-sso/"
11
- keywords = ["fastapi", "sso", "oauth", "google", "facebook", "spotify"]
11
+ keywords = [
12
+ "fastapi",
13
+ "sso",
14
+ "oauth",
15
+ "google",
16
+ "facebook",
17
+ "spotify",
18
+ "linkedin",
19
+ ]
12
20
  include = ["fastapi_sso/py.typed"]
13
21
 
14
22
 
@@ -58,7 +66,7 @@ mypy = "^1"
58
66
  poethepoet = ">=0.21.1,<0.25.0"
59
67
  pre-commit = "^3"
60
68
  pylint = ">=2,<4"
61
- pytest = "^7"
69
+ pytest = ">=7,<9"
62
70
  pytest-asyncio = ">=0.21.1,<0.24.0"
63
71
  pytest-cov = "^4"
64
72
  pytest-xdist = "^3"
@@ -71,6 +79,7 @@ httpx = ">=0.23.0"
71
79
  oauthlib = ">=3.1.0"
72
80
  pydantic = { extras = ["email"], version = ">=1.8.0" }
73
81
  python = ">=3.8,<4.0"
82
+ pylint = "^3.0.3"
74
83
 
75
84
  [build-system]
76
85
  requires = ["poetry-core>=1.0.0"]
File without changes