fastapi-sso 0.10.0__py3-none-any.whl → 0.12.0__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.
- fastapi_sso/__init__.py +2 -0
- fastapi_sso/sso/base.py +20 -0
- fastapi_sso/sso/line.py +37 -0
- fastapi_sso/sso/linkedin.py +37 -0
- fastapi_sso/sso/spotify.py +0 -1
- {fastapi_sso-0.10.0.dist-info → fastapi_sso-0.12.0.dist-info}/METADATA +5 -2
- {fastapi_sso-0.10.0.dist-info → fastapi_sso-0.12.0.dist-info}/RECORD +9 -7
- {fastapi_sso-0.10.0.dist-info → fastapi_sso-0.12.0.dist-info}/LICENSE.md +0 -0
- {fastapi_sso-0.10.0.dist-info → fastapi_sso-0.12.0.dist-info}/WHEEL +0 -0
fastapi_sso/__init__.py
CHANGED
|
@@ -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
|
fastapi_sso/sso/base.py
CHANGED
|
@@ -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)
|
fastapi_sso/sso/line.py
ADDED
|
@@ -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
|
+
)
|
fastapi_sso/sso/spotify.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fastapi-sso
|
|
3
|
-
Version: 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
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
fastapi_sso/__init__.py,sha256=
|
|
1
|
+
fastapi_sso/__init__.py,sha256=aqYfVqDcq3sk8BuPNbcVnSED6ouoHi-1is9oe_Lgl-M,654
|
|
2
2
|
fastapi_sso/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
fastapi_sso/sso/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
fastapi_sso/sso/base.py,sha256=
|
|
4
|
+
fastapi_sso/sso/base.py,sha256=K2UnC8ay20lFeCn5WUx1z-DYzpqFYqDC8RZjpVdamTI,14607
|
|
5
5
|
fastapi_sso/sso/facebook.py,sha256=F1ox1auZ5PlJW2xccAN0oF8HpvTA5tF6cdPdXar_xF0,1327
|
|
6
6
|
fastapi_sso/sso/fitbit.py,sha256=OcCL1Go5jZ6XAarucORErX7Nuk9g9qFCQPamdcEbcFE,1258
|
|
7
7
|
fastapi_sso/sso/generic.py,sha256=pLVK7WuxiQS8XdblkdC5h6he6BcybTdMCrXvfdJlvA8,2625
|
|
@@ -9,11 +9,13 @@ fastapi_sso/sso/github.py,sha256=DM4gDK0QTqf8Iftn0La3V7g7bBZ6KuXUB2QyVUELXro,169
|
|
|
9
9
|
fastapi_sso/sso/gitlab.py,sha256=DzvbTkW0dalDDJVGbbQkr8G5Q3GuMF991-aM_L15v64,1032
|
|
10
10
|
fastapi_sso/sso/google.py,sha256=iyVqh5YG5Xw-Ss4y8xEv1APDvubdI9Vt3ijvPMmStVk,1380
|
|
11
11
|
fastapi_sso/sso/kakao.py,sha256=WvlPMWdYSDM_XHv8wtbvzIzm3xUzxmaEulcf-UaeQSE,864
|
|
12
|
+
fastapi_sso/sso/line.py,sha256=s0nsC11wXvCvddwCWSiv108cvCFUPHkF2FEpdOAVMj4,1190
|
|
13
|
+
fastapi_sso/sso/linkedin.py,sha256=QLehBYsbGUdV4QWluS3ERuxvcf2w1k5kyNhZ4zW8OYM,1236
|
|
12
14
|
fastapi_sso/sso/microsoft.py,sha256=tVxHHGlXTuFCwiLh8pcM7I9aP9ncea5U0ZPp-JEB6hU,1918
|
|
13
15
|
fastapi_sso/sso/naver.py,sha256=mwv7ondZHzaUOXleMiBNkKEHnUywctVUjw0wo83l-II,901
|
|
14
16
|
fastapi_sso/sso/notion.py,sha256=3OU70JpE4mle9DXyZrf4sRpwq1raWcOHjFJrRmsI-EM,1302
|
|
15
|
-
fastapi_sso/sso/spotify.py,sha256=
|
|
16
|
-
fastapi_sso-0.
|
|
17
|
-
fastapi_sso-0.
|
|
18
|
-
fastapi_sso-0.
|
|
19
|
-
fastapi_sso-0.
|
|
17
|
+
fastapi_sso/sso/spotify.py,sha256=GhB-Fg3C4In_kzkEUCiPHi00oa1a2Z-QuhX3MCve8m4,1249
|
|
18
|
+
fastapi_sso-0.12.0.dist-info/LICENSE.md,sha256=5NVQtYs6liDtYdWM4VObWmTTKaK0k9C9txx5pLPJSyQ,1093
|
|
19
|
+
fastapi_sso-0.12.0.dist-info/METADATA,sha256=DbEoACGkvJY2IIKpsHh_ESS1yOGZmVUJE4tdSBq7S2I,4588
|
|
20
|
+
fastapi_sso-0.12.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
21
|
+
fastapi_sso-0.12.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|