Skip to content

Commit 968c756

Browse files
namsnathmavwolverinesattvikc
authored
update: adds raw user info to thirdparty response (supertokens#558)
- BitBucket - Cleans up primary email logic - Moves `email` key from `from_id_token_payload` to `from_user_info_api` in `raw_user_info_from_provider` - Github - Changes `id` field access to be concrete to be in-line with API Spec - Adds raw user info to output - Makes primary email logic consistent with BitBucket - LinkedIn - Changes `sub` field access to be concrete to be in-line with API Spec - Adds raw user info to output Co-authored-by: Viraj Kanwade <viraj.kanwade@forgeahead.io> Co-authored-by: Sattvik Chakravarthy <sattvik@supertokens.com>
1 parent 251dae1 commit 968c756

File tree

5 files changed

+65
-48
lines changed

5 files changed

+65
-48
lines changed

CHANGELOG.md

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
## [unreleased]
1010

1111
## [0.28.0]
12+
- Adds `raw_user_info_from_provider` to `UserInfo` data in LinkedIn and Github third-party recipes.
13+
- **[Breaking] Bitbucket third-party recipe**
14+
- Moves `email` from `from_id_token_payload` to `from_user_info_api` in `raw_user_info_from_provider`.
15+
- Keeps the API consistent with the Node SDK.
16+
- Migration:
17+
```
18+
- user_info.raw_user_info_from_provider.from_id_token_payload["email"]
19+
+ user_info.raw_user_info_from_provider.from_user_info_api["email"]
20+
```
1221
- Updates timestamps to use UTC instead of GMT as the timezone
1322
1423
## [0.27.0] - 2024-12-30
@@ -280,7 +289,7 @@ async def change_email(req: ChangeEmailBody, session: SessionContainer = Depends
280289
# Update the email
281290
await update_email_or_password(
282291
session.get_recipe_user_id(),
283-
email,
292+
email,
284293
)
285294

286295
# ...
@@ -363,7 +372,7 @@ from supertokens_python.types import RecipeUserId
363372

364373
def functions_override(original_implementation: RecipeInterface):
365374
o_create_new_session = original_implementation.create_new_session
366-
375+
367376
async def n_create_new_session(
368377
user_id: str,
369378
recipe_user_id: RecipeUserId,
@@ -380,7 +389,7 @@ def functions_override(original_implementation: RecipeInterface):
380389
return await o_create_new_session(user_id, recipe_user_id, access_token_payload, session_data_in_database, disable_anti_csrf, tenant_id, user_context)
381390

382391
original_implementation.create_new_session = n_create_new_session
383-
392+
384393
return original_implementation
385394

386395
session.init(override=session.InputOverrideConfig(functions=functions_override))
@@ -398,7 +407,7 @@ from supertokens_python.types import RecipeUserId
398407

399408
def functions_override(original_implementation: RecipeInterface):
400409
o_create_new_session = original_implementation.create_new_session
401-
410+
402411
async def n_create_new_session(
403412
user_id: str,
404413
recipe_user_id: RecipeUserId,
@@ -415,7 +424,7 @@ def functions_override(original_implementation: RecipeInterface):
415424
return await o_create_new_session(user_id, recipe_user_id, access_token_payload, session_data_in_database, disable_anti_csrf, tenant_id, user_context)
416425

417426
original_implementation.create_new_session = n_create_new_session
418-
427+
419428
return original_implementation
420429

421430
session.init(override=session.InputOverrideConfig(functions=functions_override))
@@ -635,7 +644,7 @@ thirdparty.init(
635644
third_party_id="google",
636645
# rest of the config
637646
),
638-
647+
639648
# Add the following line to make this provider available in non-public tenants by default
640649
include_in_non_public_tenants_by_default=True
641650
),
@@ -644,7 +653,7 @@ thirdparty.init(
644653
third_party_id="github",
645654
# rest of the config
646655
),
647-
656+
648657
# Add the following line to make this provider available in non-public tenants by default
649658
include_in_non_public_tenants_by_default=True
650659
),
@@ -736,7 +745,7 @@ for tenant in tenants_res.tenants:
736745

737746
- The way to get user information has changed:
738747
- If you are using `get_users_by_email` from `thirdpartyemailpassword` recipe:
739-
748+
740749
Before:
741750
```python
742751
from supertokens_python.recipe.thirdpartyemailpassword.syncio import get_users_by_email
@@ -748,20 +757,20 @@ for tenant in tenants_res.tenants:
748757
```python
749758
from supertokens_python.recipe.thirdparty.syncio import get_users_by_email as get_users_by_email_third_party
750759
from supertokens_python.recipe.emailpassword.syncio import get_user_by_email as get_user_by_email_emailpassword
751-
760+
752761
third_party_user_info = get_users_by_email_third_party("public", "test@example.com")
753762

754763
email_password_user_info = get_user_by_email_emailpassword("public", "test@example.com")
755764

756765
if email_password_user_info is not None:
757766
print(email_password_user_info)
758-
767+
759768
if len(third_party_user_info) > 0:
760769
print(third_party_user_info)
761770
```
762771

763772
- If you are using `get_user_id` from `thirdpartyemailpassword` recipe:
764-
773+
765774
Before:
766775
```python
767776
from supertokens_python.recipe.thirdpartyemailpassword.syncio import get_user_by_id
@@ -786,9 +795,9 @@ for tenant in tenants_res.tenants:
786795
else:
787796
print(thirdparty_user)
788797
```
789-
798+
790799
- If you are using `get_users_by_email` from `thirdpartypasswordless` recipe:
791-
800+
792801
Before:
793802
```python
794803
from supertokens_python.recipe.thirdpartypasswordless.syncio import get_users_by_email
@@ -800,20 +809,20 @@ for tenant in tenants_res.tenants:
800809
```python
801810
from supertokens_python.recipe.thirdparty.syncio import get_users_by_email as get_users_by_email_third_party
802811
from supertokens_python.recipe.passwordless.syncio import get_user_by_email as get_user_by_email_passwordless
803-
812+
804813
third_party_user_info = get_users_by_email_third_party("public", "test@example.com")
805814

806815
passwordless_user_info = get_user_by_email_passwordless("public", "test@example.com")
807816

808817
if passwordless_user_info is not None:
809818
print(passwordless_user_info)
810-
819+
811820
if len(third_party_user_info) > 0:
812821
print(third_party_user_info)
813822
```
814823

815824
- If you are using `get_user_id` from `thirdpartypasswordless` recipe:
816-
825+
817826
Before:
818827
```python
819828
from supertokens_python.recipe.thirdpartypasswordless.syncio import get_user_by_id
@@ -1025,7 +1034,7 @@ With this update, verify_session will return a 401 error if it detects multiple
10251034
)
10261035
```
10271036

1028-
- In the session recipe, if there is an `UNAUTHORISED` or `TOKEN_THEFT_DETECTED` error, the session tokens are cleared in the response regardless of if you have provided your own `error_handlers` in `session.init`
1037+
- In the session recipe, if there is an `UNAUTHORISED` or `TOKEN_THEFT_DETECTED` error, the session tokens are cleared in the response regardless of if you have provided your own `error_handlers` in `session.init`
10291038

10301039
## [0.17.0] - 2023-11-14
10311040
- Fixes `create_reset_password_link` in the emailpassword recipe wherein we passed the `rid` instead of the token in the link

supertokens_python/recipe/thirdparty/providers/bitbucket.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,13 @@
1414

1515
from __future__ import annotations
1616

17-
from typing import Dict, Any, Optional
18-
1917
from supertokens_python.recipe.thirdparty.provider import (
2018
ProviderConfigForClient,
2119
ProviderInput,
2220
Provider,
2321
)
22+
from typing import Dict, Any, Optional
2423
from .custom import GenericProvider, NewProvider
25-
2624
from .utils import do_get_request
2725
from ..types import RawUserInfoFromProvider, UserInfo, UserInfoEmail
2826

@@ -66,25 +64,22 @@ async def get_user_info(
6664
headers=headers,
6765
)
6866

69-
if raw_user_info_from_provider.from_id_token_payload is None:
70-
# Actually this should never happen but python type
71-
# checker is not agreeing so doing this:
72-
raw_user_info_from_provider.from_id_token_payload = {}
73-
74-
raw_user_info_from_provider.from_id_token_payload["email"] = (
75-
user_info_from_email
76-
)
67+
raw_user_info_from_provider.from_user_info_api["email"] = user_info_from_email
7768

78-
email = None
79-
is_verified = False
69+
# Get the primary email from the Email response
70+
# Create an object if primary email found
71+
primary_email_info: UserInfoEmail | None = None
8072
for email_info in user_info_from_email["values"]:
8173
if email_info["is_primary"]:
82-
email = email_info["email"]
83-
is_verified = email_info["is_confirmed"]
74+
primary_email_info = UserInfoEmail(
75+
email=email_info["email"],
76+
is_verified=email_info["is_confirmed"],
77+
)
78+
break
8479

8580
return UserInfo(
8681
third_party_user_id=raw_user_info_from_provider.from_user_info_api["uuid"],
87-
email=None if email is None else UserInfoEmail(email, is_verified),
82+
email=primary_email_info,
8883
raw_user_info_from_provider=raw_user_info_from_provider,
8984
)
9085

supertokens_python/recipe/thirdparty/providers/github.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222
)
2323
from supertokens_python.recipe.thirdparty.types import UserInfo, UserInfoEmail
2424

25-
from .custom import GenericProvider, NewProvider
2625
from ..provider import Provider, ProviderConfigForClient, ProviderInput
26+
from ..types import RawUserInfoFromProvider
27+
from .custom import GenericProvider, NewProvider
2728

2829

2930
class GithubImpl(GenericProvider):
@@ -45,24 +46,31 @@ async def get_user_info(
4546
"Accept": "application/vnd.github.v3+json",
4647
}
4748

48-
raw_response = {}
49-
50-
email_info: List[Any] = await do_get_request("https://api.github.com/user/emails", headers=headers) # type: ignore
49+
# https://docs.github.com/en/rest/users/emails?apiVersion=2022-11-28
5150
user_info = await do_get_request("https://api.github.com/user", headers=headers)
52-
53-
raw_response["emails"] = email_info
54-
raw_response["user"] = user_info
51+
user_email_info: List[Any] = await do_get_request("https://api.github.com/user/emails", headers=headers) # type: ignore
52+
53+
raw_user_info_from_provider = RawUserInfoFromProvider({}, {})
54+
raw_user_info_from_provider.from_user_info_api = user_info
55+
raw_user_info_from_provider.from_user_info_api["emails"] = user_email_info
56+
57+
# Get the primary email from the Email response
58+
# Create an object if primary email found
59+
primary_email_info: UserInfoEmail | None = None
60+
for email_detail in user_email_info:
61+
if email_detail["primary"]:
62+
primary_email_info = UserInfoEmail(
63+
email=email_detail["email"],
64+
is_verified=email_detail["verified"],
65+
)
66+
break
5567

5668
result = UserInfo(
57-
third_party_user_id=str(user_info.get("id")),
69+
third_party_user_id=str(user_info["id"]),
70+
email=primary_email_info,
71+
raw_user_info_from_provider=raw_user_info_from_provider,
5872
)
5973

60-
for info in email_info:
61-
if info.get("primary"):
62-
result.email = UserInfoEmail(
63-
email=info.get("email"), is_verified=info.get("verified")
64-
)
65-
6674
return result
6775

6876

supertokens_python/recipe/thirdparty/providers/linkedin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,12 @@ async def get_user_info(
6767
raw_user_info_from_provider.from_user_info_api = user_info
6868

6969
return UserInfo(
70-
third_party_user_id=raw_user_info_from_provider.from_user_info_api.get("sub"), # type: ignore
70+
third_party_user_id=raw_user_info_from_provider.from_user_info_api["sub"], # type: ignore
7171
email=UserInfoEmail(
7272
email=raw_user_info_from_provider.from_user_info_api.get("email"), # type: ignore
7373
is_verified=raw_user_info_from_provider.from_user_info_api.get("email_verified"), # type: ignore
7474
),
75+
raw_user_info_from_provider=raw_user_info_from_provider,
7576
)
7677

7778

supertokens_python/recipe/thirdparty/types.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ def to_json(self) -> Dict[str, Any]:
5858

5959

6060
class UserInfoEmail:
61+
"""
62+
Details about the user's - generally primary - email.
63+
"""
64+
6165
def __init__(self, email: str, is_verified: bool):
6266
self.id: str = email
6367
self.is_verified: bool = is_verified

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy