fastapi-sso 0.16.0__py3-none-any.whl → 0.17.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 CHANGED
@@ -4,6 +4,8 @@
4
4
  """
5
5
 
6
6
  from .sso.base import OpenID, SSOBase, SSOLoginError
7
+ from .sso.bitbucket import BitbucketSSO
8
+ from .sso.discord import DiscordSSO
7
9
  from .sso.facebook import FacebookSSO
8
10
  from .sso.fitbit import FitbitSSO
9
11
  from .sso.generic import create_provider
@@ -37,4 +39,6 @@ __all__ = [
37
39
  "NotionSSO",
38
40
  "SpotifySSO",
39
41
  "TwitterSSO",
42
+ "BitbucketSSO",
43
+ "DiscordSSO",
40
44
  ]
@@ -0,0 +1,60 @@
1
+ """BitBucket SSO Oauth Helper class"""
2
+
3
+ from typing import TYPE_CHECKING, ClassVar, List, Optional, Union
4
+
5
+ import pydantic
6
+
7
+ from fastapi_sso.sso.base import DiscoveryDocument, OpenID, SSOBase
8
+
9
+ if TYPE_CHECKING:
10
+ import httpx # pragma: no cover
11
+
12
+
13
+ class BitbucketSSO(SSOBase):
14
+ """Class providing login using BitBucket OAuth"""
15
+
16
+ provider = "bitbucket"
17
+ scope: ClassVar = ["account", "email"]
18
+ version = "2.0"
19
+
20
+ def __init__(
21
+ self,
22
+ client_id: str,
23
+ client_secret: str,
24
+ redirect_uri: Optional[Union[pydantic.AnyHttpUrl, str]] = None,
25
+ allow_insecure_http: bool = False,
26
+ scope: Optional[List[str]] = None,
27
+ ):
28
+ super().__init__(
29
+ client_id=client_id,
30
+ client_secret=client_secret,
31
+ redirect_uri=redirect_uri,
32
+ allow_insecure_http=allow_insecure_http,
33
+ scope=scope,
34
+ )
35
+
36
+ async def get_useremail(self, session: Optional["httpx.AsyncClient"] = None) -> dict:
37
+ """Get user email"""
38
+ if session is None:
39
+ raise ValueError("Session is required to make HTTP requests")
40
+
41
+ response = await session.get(f"https://api.bitbucket.org/{self.version}/user/emails")
42
+ return response.json()
43
+
44
+ async def get_discovery_document(self) -> DiscoveryDocument:
45
+ return {
46
+ "authorization_endpoint": "https://bitbucket.org/site/oauth2/authorize",
47
+ "token_endpoint": "https://bitbucket.org/site/oauth2/access_token",
48
+ "userinfo_endpoint": f"https://api.bitbucket.org/{self.version}/user",
49
+ }
50
+
51
+ async def openid_from_response(self, response: dict, session: Optional["httpx.AsyncClient"] = None) -> OpenID:
52
+ email = await self.get_useremail(session=session)
53
+ return OpenID(
54
+ email=email["values"][0]["email"],
55
+ display_name=response.get("display_name"),
56
+ provider=self.provider,
57
+ id=str(response.get("uuid")).strip("{}"),
58
+ first_name=response.get("nickname"),
59
+ picture=response.get("links", {}).get("avatar", {}).get("href"),
60
+ )
@@ -0,0 +1,56 @@
1
+ """Discord SSO Oauth Helper class"""
2
+
3
+ from typing import TYPE_CHECKING, ClassVar, List, Optional, Union
4
+
5
+ import pydantic
6
+
7
+ from fastapi_sso.sso.base import DiscoveryDocument, OpenID, SSOBase
8
+
9
+ if TYPE_CHECKING:
10
+ import httpx # pragma: no cover
11
+
12
+
13
+ class DiscordSSO(SSOBase):
14
+ """Class providing login using Discord OAuth"""
15
+
16
+ provider = "discord"
17
+ scope: ClassVar = ["identify", "email", "openid"]
18
+
19
+ def __init__(
20
+ self,
21
+ client_id: str,
22
+ client_secret: str,
23
+ redirect_uri: Optional[Union[pydantic.AnyHttpUrl, str]] = None,
24
+ allow_insecure_http: bool = False,
25
+ scope: Optional[List[str]] = None,
26
+ ):
27
+ super().__init__(
28
+ client_id=client_id,
29
+ client_secret=client_secret,
30
+ redirect_uri=redirect_uri,
31
+ allow_insecure_http=allow_insecure_http,
32
+ scope=scope,
33
+ )
34
+
35
+ async def get_discovery_document(self) -> DiscoveryDocument:
36
+ return {
37
+ "authorization_endpoint": "https://discord.com/oauth2/authorize",
38
+ "token_endpoint": "https://discord.com/api/oauth2/token",
39
+ "userinfo_endpoint": "https://discord.com/api/users/@me",
40
+ }
41
+
42
+ async def openid_from_response(self, response: dict, session: Optional["httpx.AsyncClient"] = None) -> OpenID:
43
+ user_id = response.get("id")
44
+ avatar = response.get("avatar")
45
+ picture = None
46
+ if user_id and avatar:
47
+ picture = f"https://cdn.discordapp.com/avatars/{user_id}/{avatar}.png"
48
+
49
+ return OpenID(
50
+ email=response.get("email"),
51
+ display_name=response.get("global_name"),
52
+ provider=self.provider,
53
+ id=user_id,
54
+ first_name=response.get("username"),
55
+ picture=picture,
56
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastapi-sso
3
- Version: 0.16.0
3
+ Version: 0.17.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
@@ -143,6 +143,8 @@ I tend to process Pull Requests faster when properly caffeinated 😉.
143
143
  - LinkedIn (by Alessandro Pischedda) - [Cereal84](https://github.com/Cereal84)
144
144
  - Yandex (by Akim Faskhutdinov) – [akimrx](https://github.com/akimrx)
145
145
  - Seznam (by Tomas Koutek) - [TomasKoutek](https://github.com/TomasKoutek)
146
+ - Discord (by Kaelian Baudelet) - [afi-dev](https://github.com/afi-dev)
147
+ - Bitbucket (by Kaelian Baudelet) - [afi-dev](https://github.com/afi-dev)
146
148
 
147
149
  See [Contributing](#contributing) for a guide on how to contribute your own login provider.
148
150
 
@@ -1,8 +1,10 @@
1
- fastapi_sso/__init__.py,sha256=dGVA7UO2jDN2RAk5UlI73k1p8zEXMjUEaP7Kwq3_Gzc,1006
1
+ fastapi_sso/__init__.py,sha256=G7QrtBs8wAPUxIINZuBX59yeeqWpSK-Yx_ky17BOJK8,1120
2
2
  fastapi_sso/pkce.py,sha256=QDqCH5f5EDmIG2MHfcAYbZJaURbl6w5IiuS6SHq89qA,792
3
3
  fastapi_sso/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  fastapi_sso/sso/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  fastapi_sso/sso/base.py,sha256=PuxN9rEWLZ5c1WN751lFrGArVcOGipcpX43gPDbsbn8,21637
6
+ fastapi_sso/sso/bitbucket.py,sha256=QVeZWMBpJioGjc-y9oiCR3L913QMLqkCQyzjCuKWTi8,2115
7
+ fastapi_sso/sso/discord.py,sha256=J4QNiaMjy53PVp6s9VwB2p0puqsSp3_NnQbe4R98-U4,1792
6
8
  fastapi_sso/sso/facebook.py,sha256=JaGCT2v56iRRQlnoZ5OSsB19677gyMU7U5dZTjVE_mc,1368
7
9
  fastapi_sso/sso/fitbit.py,sha256=CIqyyMDzZ0sYbZOtDNEotsoqq0Rvr5x4oP8_yWxfU7M,1301
8
10
  fastapi_sso/sso/generic.py,sha256=VBzKVc2ckpuC4XqzlXQ56eg-xK8roV-uiUc2xsVseOI,2647
@@ -20,7 +22,7 @@ fastapi_sso/sso/spotify.py,sha256=FvX2N91Bi3wgKRwdU1sWo-zA0s3wYJCiCYA05ebXweE,12
20
22
  fastapi_sso/sso/twitter.py,sha256=1kMjFdh-OT1b5bJvY3tWfl-BRBv2hVZ6L_liLAvNML8,1249
21
23
  fastapi_sso/sso/yandex.py,sha256=8jKkh-na62lwsaBW7Pvj6VC6WlR0RMg8KrSNlr2Hj8o,1507
22
24
  fastapi_sso/state.py,sha256=9RKMrFGjeN4Ab-3var81QV-gpcBlnNy152WYbxTUGVY,300
23
- fastapi_sso-0.16.0.dist-info/LICENSE.md,sha256=5NVQtYs6liDtYdWM4VObWmTTKaK0k9C9txx5pLPJSyQ,1093
24
- fastapi_sso-0.16.0.dist-info/METADATA,sha256=VCFezbjou97uivlibCnawLjRwRZ6H_iCiRVNCSW0fl8,7038
25
- fastapi_sso-0.16.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
26
- fastapi_sso-0.16.0.dist-info/RECORD,,
25
+ fastapi_sso-0.17.0.dist-info/LICENSE.md,sha256=5NVQtYs6liDtYdWM4VObWmTTKaK0k9C9txx5pLPJSyQ,1093
26
+ fastapi_sso-0.17.0.dist-info/METADATA,sha256=66CP7JPwlCpBGMFlXhhHjtC-P4wXqXmdR6F64MzfxcM,7184
27
+ fastapi_sso-0.17.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
28
+ fastapi_sso-0.17.0.dist-info/RECORD,,