From 3807168a0e938fe5fd6f8c63f25cfdca14657d6f Mon Sep 17 00:00:00 2001 From: KShivendu Date: Wed, 2 Aug 2023 15:21:46 +0530 Subject: [PATCH 01/13] feat: Pass tenant id --- .../recipe/dashboard/api/userdetails/user_sessions_get.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py b/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py index 9636f5d84..0e5e6fe08 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py @@ -17,7 +17,7 @@ async def handle_sessions_get( _api_interface: APIInterface, - _tenant_id: str, + tenant_id: str, api_options: APIOptions, user_context: Dict[str, Any], ) -> UserSessionsGetAPIResponse: @@ -26,9 +26,8 @@ async def handle_sessions_get( if user_id is None: raise_bad_input_exception("Missing required parameter 'userId'") - # TODO: Pass tenant id here session_handles = await get_all_session_handles_for_user( - user_id, "pass-tenant-id", user_context + user_id, tenant_id, user_context ) sessions: List[Optional[SessionInfo]] = [None for _ in session_handles] From 81cb3fd641e5afc42d0de33c8b92980153c81b12 Mon Sep 17 00:00:00 2001 From: KShivendu Date: Wed, 2 Aug 2023 15:25:54 +0530 Subject: [PATCH 02/13] refactor: set default value for tenant id --- supertokens_python/recipe/session/asyncio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/supertokens_python/recipe/session/asyncio/__init__.py b/supertokens_python/recipe/session/asyncio/__init__.py index d2b6cfd76..d0d137b61 100644 --- a/supertokens_python/recipe/session/asyncio/__init__.py +++ b/supertokens_python/recipe/session/asyncio/__init__.py @@ -441,7 +441,7 @@ async def revoke_all_sessions_for_user( async def get_all_session_handles_for_user( user_id: str, - tenant_id: Optional[str], + tenant_id: Optional[str] = None, user_context: Union[None, Dict[str, Any]] = None, ) -> List[str]: if user_context is None: From fbcd035a2d4d1a51576e58f2d444fd3b744bb408 Mon Sep 17 00:00:00 2001 From: KShivendu Date: Thu, 3 Aug 2023 14:06:27 +0530 Subject: [PATCH 03/13] fix: Suggested changes --- .../recipe/dashboard/api/userdetails/user_sessions_get.py | 5 +++-- supertokens_python/recipe/session/interfaces.py | 4 ++-- supertokens_python/recipe/session/recipe_implementation.py | 4 ++-- supertokens_python/recipe/session/session_functions.py | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py b/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py index 066648166..cffd8933c 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py @@ -23,9 +23,10 @@ async def handle_sessions_get( if user_id is None: raise_bad_input_exception("Missing required parameter 'userId'") - # TODO: Pass tenant id here + # Not passing tenant_id because we want to get all the sessions + # across all the tenants for this user. session_handles = await get_all_session_handles_for_user( - user_id, "pass-tenant-id", user_context + user_id, None, user_context ) sessions: List[Optional[SessionInfo]] = [None for _ in session_handles] diff --git a/supertokens_python/recipe/session/interfaces.py b/supertokens_python/recipe/session/interfaces.py index 9777c1f5f..bfa83fd2a 100644 --- a/supertokens_python/recipe/session/interfaces.py +++ b/supertokens_python/recipe/session/interfaces.py @@ -219,7 +219,7 @@ async def revoke_all_sessions_for_user( self, user_id: str, tenant_id: str, - revoke_across_all_tenants: Optional[bool], + revoke_across_all_tenants: bool, user_context: Dict[str, Any], ) -> List[str]: pass @@ -229,7 +229,7 @@ async def get_all_session_handles_for_user( self, user_id: str, tenant_id: str, - fetch_across_all_tenants: Optional[bool], + fetch_across_all_tenants: bool, user_context: Dict[str, Any], ) -> List[str]: pass diff --git a/supertokens_python/recipe/session/recipe_implementation.py b/supertokens_python/recipe/session/recipe_implementation.py index b37e631e0..bc39d8785 100644 --- a/supertokens_python/recipe/session/recipe_implementation.py +++ b/supertokens_python/recipe/session/recipe_implementation.py @@ -330,7 +330,7 @@ async def revoke_all_sessions_for_user( self, user_id: str, tenant_id: Optional[str], - revoke_across_all_tenants: Optional[bool], + revoke_across_all_tenants: bool, user_context: Dict[str, Any], ) -> List[str]: return await session_functions.revoke_all_sessions_for_user( @@ -341,7 +341,7 @@ async def get_all_session_handles_for_user( self, user_id: str, tenant_id: Optional[str], - fetch_across_all_tenants: Optional[bool], + fetch_across_all_tenants: bool, user_context: Dict[str, Any], ) -> List[str]: return await session_functions.get_all_session_handles_for_user( diff --git a/supertokens_python/recipe/session/session_functions.py b/supertokens_python/recipe/session/session_functions.py index d3fb1cdca..e424ed09e 100644 --- a/supertokens_python/recipe/session/session_functions.py +++ b/supertokens_python/recipe/session/session_functions.py @@ -392,7 +392,7 @@ async def revoke_all_sessions_for_user( recipe_implementation: RecipeImplementation, user_id: str, tenant_id: Optional[str], - revoke_across_all_tenants: Optional[bool], + revoke_across_all_tenants: bool, ) -> List[str]: if tenant_id is None: tenant_id = DEFAULT_TENANT_ID @@ -408,7 +408,7 @@ async def get_all_session_handles_for_user( recipe_implementation: RecipeImplementation, user_id: str, tenant_id: Optional[str], - fetch_across_all_tenants: Optional[bool], + fetch_across_all_tenants: bool, ) -> List[str]: if tenant_id is None: tenant_id = DEFAULT_TENANT_ID From e7fccfda14f80492d62983de2c9b27ad2e28b28c Mon Sep 17 00:00:00 2001 From: KShivendu Date: Thu, 3 Aug 2023 14:19:27 +0530 Subject: [PATCH 04/13] chores: Improve comments --- .../recipe/dashboard/api/userdetails/user_sessions_get.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py b/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py index cffd8933c..47e4b36cf 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py @@ -23,8 +23,8 @@ async def handle_sessions_get( if user_id is None: raise_bad_input_exception("Missing required parameter 'userId'") - # Not passing tenant_id because we want to get all the sessions - # across all the tenants for this user. + # Passing tenant id as None sets fetch_across_all_tenants to True + # which is what we want here. session_handles = await get_all_session_handles_for_user( user_id, None, user_context ) From c5194050aa4a348f591643e789e982f724bf694c Mon Sep 17 00:00:00 2001 From: KShivendu Date: Mon, 7 Aug 2023 21:41:52 +0530 Subject: [PATCH 05/13] fix: Suggested changes --- .../recipe/emailpassword/asyncio/__init__.py | 8 ++++---- supertokens_python/recipe/emailpassword/interfaces.py | 4 ++-- .../recipe/thirdpartyemailpassword/asyncio/__init__.py | 8 ++++---- .../recipe/thirdpartyemailpassword/interfaces.py | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/supertokens_python/recipe/emailpassword/asyncio/__init__.py b/supertokens_python/recipe/emailpassword/asyncio/__init__.py index f20b83dee..16baa9dc9 100644 --- a/supertokens_python/recipe/emailpassword/asyncio/__init__.py +++ b/supertokens_python/recipe/emailpassword/asyncio/__init__.py @@ -22,8 +22,8 @@ CreateResetPasswordWrongUserIdError, CreateResetPasswordLinkUknownUserIdError, CreateResetPasswordLinkOkResult, - CreateResetPasswordEmailOkResult, - CreateResetPasswordEmailUnknownUserIdError, + SendResetPasswordEmailOkResult, + SendResetPasswordEmailUnknownUserIdError, ) from supertokens_python.recipe.emailpassword.utils import get_password_reset_link from supertokens_python.recipe.emailpassword.types import ( @@ -159,7 +159,7 @@ async def send_reset_password_email( ): link = await create_reset_password_link(user_id, tenant_id, user_context) if isinstance(link, CreateResetPasswordLinkUknownUserIdError): - return CreateResetPasswordEmailUnknownUserIdError() + return SendResetPasswordEmailUnknownUserIdError() user = await get_user_by_id(user_id, user_context) assert user is not None @@ -173,4 +173,4 @@ async def send_reset_password_email( user_context, ) - return CreateResetPasswordEmailOkResult() + return SendResetPasswordEmailOkResult() diff --git a/supertokens_python/recipe/emailpassword/interfaces.py b/supertokens_python/recipe/emailpassword/interfaces.py index 8e291d866..5e1586921 100644 --- a/supertokens_python/recipe/emailpassword/interfaces.py +++ b/supertokens_python/recipe/emailpassword/interfaces.py @@ -66,11 +66,11 @@ class CreateResetPasswordLinkUknownUserIdError: pass -class CreateResetPasswordEmailOkResult: +class SendResetPasswordEmailOkResult: pass -class CreateResetPasswordEmailUnknownUserIdError: +class SendResetPasswordEmailUnknownUserIdError: pass diff --git a/supertokens_python/recipe/thirdpartyemailpassword/asyncio/__init__.py b/supertokens_python/recipe/thirdpartyemailpassword/asyncio/__init__.py index 989aa6770..270b19e42 100644 --- a/supertokens_python/recipe/thirdpartyemailpassword/asyncio/__init__.py +++ b/supertokens_python/recipe/thirdpartyemailpassword/asyncio/__init__.py @@ -25,8 +25,8 @@ CreateResetPasswordWrongUserIdError, CreateResetPasswordLinkUknownUserIdError, CreateResetPasswordLinkOkResult, - CreateResetPasswordEmailUnknownUserIdError, - CreateResetPasswordEmailOkResult, + SendResetPasswordEmailUnknownUserIdError, + SendResetPasswordEmailEmailOkResult, ) from supertokens_python.recipe.emailpassword.utils import get_password_reset_link @@ -215,7 +215,7 @@ async def send_reset_password_email( ): link = await create_reset_password_link(user_id, tenant_id, user_context) if isinstance(link, CreateResetPasswordLinkUknownUserIdError): - return CreateResetPasswordEmailUnknownUserIdError() + return SendResetPasswordEmailUnknownUserIdError() user = await get_user_by_id(user_id, user_context) assert user is not None @@ -229,4 +229,4 @@ async def send_reset_password_email( user_context, ) - return CreateResetPasswordEmailOkResult() + return SendResetPasswordEmailEmailOkResult() diff --git a/supertokens_python/recipe/thirdpartyemailpassword/interfaces.py b/supertokens_python/recipe/thirdpartyemailpassword/interfaces.py index 186b495cd..22cb364ed 100644 --- a/supertokens_python/recipe/thirdpartyemailpassword/interfaces.py +++ b/supertokens_python/recipe/thirdpartyemailpassword/interfaces.py @@ -21,9 +21,9 @@ CreateResetPasswordLinkUknownUserIdError = ( EPInterfaces.CreateResetPasswordLinkUknownUserIdError ) -CreateResetPasswordEmailOkResult = EPInterfaces.CreateResetPasswordEmailOkResult -CreateResetPasswordEmailUnknownUserIdError = ( - EPInterfaces.CreateResetPasswordEmailUnknownUserIdError +SendResetPasswordEmailEmailOkResult = EPInterfaces.SendResetPasswordEmailOkResult +SendResetPasswordEmailUnknownUserIdError = ( + EPInterfaces.SendResetPasswordEmailUnknownUserIdError ) EmailPasswordEmailExistsGetOkResult = EPInterfaces.EmailExistsGetOkResult GeneratePasswordResetTokenPostOkResult = ( From f35c4547d39280317958883798bcf0b7b5692b26 Mon Sep 17 00:00:00 2001 From: KShivendu Date: Tue, 8 Aug 2023 19:08:15 +0530 Subject: [PATCH 06/13] fix: Suggested changes --- .../recipe/emailverification/recipe.py | 2 +- .../asyncio/__init__.py | 23 ----------------- .../syncio/__init__.py | 25 ------------------- 3 files changed, 1 insertion(+), 49 deletions(-) diff --git a/supertokens_python/recipe/emailverification/recipe.py b/supertokens_python/recipe/emailverification/recipe.py index 638e63927..fe6ba0f2e 100644 --- a/supertokens_python/recipe/emailverification/recipe.py +++ b/supertokens_python/recipe/emailverification/recipe.py @@ -230,7 +230,7 @@ def callback(): PostSTInitCallbacks.add_post_init_callback(callback) return EmailVerificationRecipe.__instance - return raise_general_exception( + raise_general_exception( "Emailverification recipe has already been initialised. Please check your code for bugs." ) diff --git a/supertokens_python/recipe/thirdpartyemailpassword/asyncio/__init__.py b/supertokens_python/recipe/thirdpartyemailpassword/asyncio/__init__.py index 34b7d3677..1e09c2273 100644 --- a/supertokens_python/recipe/thirdpartyemailpassword/asyncio/__init__.py +++ b/supertokens_python/recipe/thirdpartyemailpassword/asyncio/__init__.py @@ -63,29 +63,6 @@ async def get_user_by_third_party_info( ) -async def thirdparty_sign_in_up( - third_party_id: str, - third_party_user_id: str, - email: str, - oauth_tokens: Dict[str, Any], - raw_user_info_from_provider: RawUserInfoFromProvider, - tenant_id: Optional[str] = None, - user_context: Optional[Dict[str, Any]] = None, -): - if user_context is None: - user_context = {} - - return await ThirdPartyEmailPasswordRecipe.get_instance().recipe_implementation.thirdparty_sign_in_up( - third_party_id, - third_party_user_id, - email, - oauth_tokens, - raw_user_info_from_provider, - tenant_id or DEFAULT_TENANT_ID, - user_context, - ) - - async def thirdparty_manually_create_or_update_user( third_party_id: str, third_party_user_id: str, diff --git a/supertokens_python/recipe/thirdpartyemailpassword/syncio/__init__.py b/supertokens_python/recipe/thirdpartyemailpassword/syncio/__init__.py index 191797119..4539e6f53 100644 --- a/supertokens_python/recipe/thirdpartyemailpassword/syncio/__init__.py +++ b/supertokens_python/recipe/thirdpartyemailpassword/syncio/__init__.py @@ -49,31 +49,6 @@ def get_user_by_third_party_info( ) -def thirdparty_sign_in_up( - third_party_id: str, - third_party_user_id: str, - email: str, - oauth_tokens: Dict[str, Any], - raw_user_info_from_provider: RawUserInfoFromProvider, - tenant_id: Optional[str] = None, - user_context: Optional[Dict[str, Any]] = None, -): - from supertokens_python.recipe.thirdpartyemailpassword.asyncio import ( - thirdparty_sign_in_up, - ) - - return sync( - thirdparty_sign_in_up( - third_party_id, - third_party_user_id, - email, - oauth_tokens, - raw_user_info_from_provider, - tenant_id, - user_context, - ) - ) - def thirdparty_manually_create_or_update_user( third_party_id: str, From 0993298434f43ade0a73f8116d2c0b9b9a6692ae Mon Sep 17 00:00:00 2001 From: KShivendu Date: Tue, 8 Aug 2023 19:11:16 +0530 Subject: [PATCH 07/13] fix: Linter and format --- .../recipe/thirdpartyemailpassword/asyncio/__init__.py | 1 - .../recipe/thirdpartyemailpassword/syncio/__init__.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/supertokens_python/recipe/thirdpartyemailpassword/asyncio/__init__.py b/supertokens_python/recipe/thirdpartyemailpassword/asyncio/__init__.py index 1e09c2273..3562c25df 100644 --- a/supertokens_python/recipe/thirdpartyemailpassword/asyncio/__init__.py +++ b/supertokens_python/recipe/thirdpartyemailpassword/asyncio/__init__.py @@ -27,7 +27,6 @@ CreateResetPasswordLinkOkResult, CreateResetPasswordEmailUnknownUserIdError, CreateResetPasswordEmailOkResult, - RawUserInfoFromProvider, ) from supertokens_python.recipe.emailpassword.utils import get_password_reset_link diff --git a/supertokens_python/recipe/thirdpartyemailpassword/syncio/__init__.py b/supertokens_python/recipe/thirdpartyemailpassword/syncio/__init__.py index 4539e6f53..53f099364 100644 --- a/supertokens_python/recipe/thirdpartyemailpassword/syncio/__init__.py +++ b/supertokens_python/recipe/thirdpartyemailpassword/syncio/__init__.py @@ -19,7 +19,6 @@ from ..interfaces import ( EmailPasswordSignInOkResult, EmailPasswordSignInWrongCredentialsError, - RawUserInfoFromProvider, ) from ..types import EmailTemplateVars, User @@ -49,7 +48,6 @@ def get_user_by_third_party_info( ) - def thirdparty_manually_create_or_update_user( third_party_id: str, third_party_user_id: str, From eec077a3efc29af6fc597abb5d418cf1a466b411 Mon Sep 17 00:00:00 2001 From: KShivendu Date: Tue, 8 Aug 2023 22:04:37 +0530 Subject: [PATCH 08/13] fix: Pass tenant id in functions used by dashboard APIs --- .../recipe/dashboard/api/userdetails/user_sessions_get.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py b/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py index 9636f5d84..0e5e6fe08 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py @@ -17,7 +17,7 @@ async def handle_sessions_get( _api_interface: APIInterface, - _tenant_id: str, + tenant_id: str, api_options: APIOptions, user_context: Dict[str, Any], ) -> UserSessionsGetAPIResponse: @@ -26,9 +26,8 @@ async def handle_sessions_get( if user_id is None: raise_bad_input_exception("Missing required parameter 'userId'") - # TODO: Pass tenant id here session_handles = await get_all_session_handles_for_user( - user_id, "pass-tenant-id", user_context + user_id, tenant_id, user_context ) sessions: List[Optional[SessionInfo]] = [None for _ in session_handles] From 5b8a38496c7b152c11a210f344ece50a383d67c9 Mon Sep 17 00:00:00 2001 From: KShivendu Date: Tue, 8 Aug 2023 22:45:08 +0530 Subject: [PATCH 09/13] fix: Make consistent with other SDKs --- .../always_initialised_recipes.py | 21 ------------------- .../recipe/multitenancy/__init__.py | 4 ---- .../recipe/session/session_class.py | 5 +++-- supertokens_python/recipe_module.py | 3 +-- supertokens_python/supertokens.py | 15 ++++++------- 5 files changed, 12 insertions(+), 36 deletions(-) delete mode 100644 supertokens_python/always_initialised_recipes.py diff --git a/supertokens_python/always_initialised_recipes.py b/supertokens_python/always_initialised_recipes.py deleted file mode 100644 index e7fd86845..000000000 --- a/supertokens_python/always_initialised_recipes.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. -# -# This software is licensed under the Apache License, Version 2.0 (the -# "License") as published by the Apache Software Foundation. -# -# You may not use this file except in compliance with the License. You may -# obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -from __future__ import annotations -from typing import Callable, Optional, TYPE_CHECKING - -if TYPE_CHECKING: - from supertokens_python.recipe_module import RecipeModule - from supertokens_python import AppInfo - -DEFAULT_MULTITENANCY_RECIPE: Optional[Callable[[AppInfo], RecipeModule]] = None diff --git a/supertokens_python/recipe/multitenancy/__init__.py b/supertokens_python/recipe/multitenancy/__init__.py index d57fb7bd0..3085e793c 100644 --- a/supertokens_python/recipe/multitenancy/__init__.py +++ b/supertokens_python/recipe/multitenancy/__init__.py @@ -14,7 +14,6 @@ from __future__ import annotations from typing import TYPE_CHECKING, Callable, Union -from supertokens_python import always_initialised_recipes from . import exceptions as ex from . import recipe @@ -42,6 +41,3 @@ def init( error_handlers, override, ) - - -always_initialised_recipes.DEFAULT_MULTITENANCY_RECIPE = init() diff --git a/supertokens_python/recipe/session/session_class.py b/supertokens_python/recipe/session/session_class.py index 2bad06285..e904f14c4 100644 --- a/supertokens_python/recipe/session/session_class.py +++ b/supertokens_python/recipe/session/session_class.py @@ -223,8 +223,9 @@ async def fetch_and_set_claim( if user_context is None: user_context = {} - # TODO: Pass tenant id - update = await claim.build(self.get_user_id(), "pass-tenant-id", user_context) + update = await claim.build( + self.get_user_id(), self.get_tenant_id(), user_context + ) return await self.merge_into_access_token_payload(update, user_context) async def set_claim_value( diff --git a/supertokens_python/recipe_module.py b/supertokens_python/recipe_module.py index 787f92d73..4ff46728a 100644 --- a/supertokens_python/recipe_module.py +++ b/supertokens_python/recipe_module.py @@ -30,8 +30,6 @@ from .exceptions import SuperTokensError from .normalised_url_path import NormalisedURLPath -from supertokens_python.recipe.multitenancy.recipe import MultitenancyRecipe - class ApiIdWithTenantId: def __init__(self, api_id: str, tenant_id: str): @@ -54,6 +52,7 @@ async def return_api_id_if_can_handle_request( self, path: NormalisedURLPath, method: str, user_context: Dict[str, Any] ) -> Union[ApiIdWithTenantId, None]: from supertokens_python.recipe.multitenancy.constants import DEFAULT_TENANT_ID + from supertokens_python.recipe.multitenancy.recipe import MultitenancyRecipe apis_handled = self.get_apis_handled() diff --git a/supertokens_python/supertokens.py b/supertokens_python/supertokens.py index a77bb40e2..8c2701d8c 100644 --- a/supertokens_python/supertokens.py +++ b/supertokens_python/supertokens.py @@ -189,20 +189,21 @@ def __init__( "Please provide at least one recipe to the supertokens.init function call" ) - multitenancy_found = [False] + from supertokens_python.recipe.multitenancy.recipe import MultitenancyRecipe + + multitenancy_found = False def make_recipe(recipe: Callable[[AppInfo], RecipeModule]) -> RecipeModule: + nonlocal multitenancy_found recipe_module = recipe(self.app_info) - if recipe_module.get_recipe_id() == "multitenancy": - multitenancy_found[0] = True + if recipe_module.get_recipe_id() == MultitenancyRecipe.recipe_id: + multitenancy_found = True return recipe_module self.recipe_modules: List[RecipeModule] = list(map(make_recipe, recipe_list)) - if callable(DEFAULT_MULTITENANCY_RECIPE) and not multitenancy_found[0]: - recipe = DEFAULT_MULTITENANCY_RECIPE( # pylint: disable=not-callable - self.app_info - ) + if not multitenancy_found: + recipe = MultitenancyRecipe.init()(self.app_info) self.recipe_modules.append(recipe) self.telemetry = ( From 5f8a58b8b9d2a4ae4f485d0846e7fa413333196d Mon Sep 17 00:00:00 2001 From: KShivendu Date: Tue, 8 Aug 2023 22:46:00 +0530 Subject: [PATCH 10/13] fix: Remove unused import --- supertokens_python/supertokens.py | 1 - 1 file changed, 1 deletion(-) diff --git a/supertokens_python/supertokens.py b/supertokens_python/supertokens.py index 8c2701d8c..14400fe92 100644 --- a/supertokens_python/supertokens.py +++ b/supertokens_python/supertokens.py @@ -46,7 +46,6 @@ send_non_200_response_with_message, ) -from .always_initialised_recipes import DEFAULT_MULTITENANCY_RECIPE from supertokens_python.recipe.multitenancy.constants import DEFAULT_TENANT_ID if TYPE_CHECKING: From e28aca30def3872ac485d31c8a5505a3c36c2e55 Mon Sep 17 00:00:00 2001 From: KShivendu Date: Wed, 9 Aug 2023 18:10:15 +0530 Subject: [PATCH 11/13] test: fix failing tests --- .../recipe/thirdparty/api/implementation.py | 1 + supertokens_python/recipe/userroles/recipe.py | 4 ++-- tests/Django/test_django.py | 17 ++++++++--------- tests/Flask/test_flask.py | 19 +++++++++---------- .../claims/test_create_new_session.py | 2 +- tests/sessions/claims/test_get_claim_value.py | 2 ++ .../claims/test_primitive_array_claim.py | 2 +- tests/sessions/claims/test_primitive_claim.py | 2 +- tests/sessions/claims/test_set_claim_value.py | 6 +++--- ...test_validate_claims_for_session_handle.py | 2 +- tests/sessions/claims/utils.py | 4 ++-- tests/thirdparty/test_thirdparty.py | 17 ++++++++--------- 12 files changed, 39 insertions(+), 39 deletions(-) diff --git a/supertokens_python/recipe/thirdparty/api/implementation.py b/supertokens_python/recipe/thirdparty/api/implementation.py index eef9c6ce2..ad20bf4cd 100644 --- a/supertokens_python/recipe/thirdparty/api/implementation.py +++ b/supertokens_python/recipe/thirdparty/api/implementation.py @@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. from __future__ import annotations +from supertokens_python.utils import utf_base64decode from base64 import b64decode import json diff --git a/supertokens_python/recipe/userroles/recipe.py b/supertokens_python/recipe/userroles/recipe.py index 32502ee17..f4bae1d7f 100644 --- a/supertokens_python/recipe/userroles/recipe.py +++ b/supertokens_python/recipe/userroles/recipe.py @@ -152,7 +152,7 @@ async def fetch_value( recipe = UserRolesRecipe.get_instance() user_roles = await recipe.recipe_implementation.get_roles_for_user( - tenant_id, user_id, user_context + user_id, tenant_id, user_context ) user_permissions: Set[str] = set() @@ -186,7 +186,7 @@ async def fetch_value( ) -> List[str]: recipe = UserRolesRecipe.get_instance() res = await recipe.recipe_implementation.get_roles_for_user( - tenant_id, user_id, user_context + user_id, tenant_id, user_context ) return res.roles diff --git a/tests/Django/test_django.py b/tests/Django/test_django.py index 372e72269..9297429cc 100644 --- a/tests/Django/test_django.py +++ b/tests/Django/test_django.py @@ -16,6 +16,7 @@ from urllib.parse import urlencode from datetime import datetime from inspect import isawaitable +from base64 import b64encode from typing import Any, Dict, Union from django.http import HttpRequest, HttpResponse, JsonResponse @@ -455,10 +456,10 @@ async def test_thirdparty_parsing_works(self): start_st() - data = { - "state": "afc596274293e1587315c", - "code": "c7685e261f98e4b3b94e34b3a69ff9cf4.0.rvxt.eE8rO__6hGoqaX1B7ODPmA", - } + state = b64encode(json.dumps({"redirectURI": "http://localhost:3000/redirect" }).encode()).decode() + code = "testing" + + data = { "state": state, "code": code} request = self.factory.post( "/auth/callback/apple", @@ -470,11 +471,9 @@ async def test_thirdparty_parsing_works(self): raise Exception("Should never come here") response = await temp - self.assertEqual(response.status_code, 200) - self.assertEqual( - response.content, - b'', - ) + self.assertEqual(response.status_code, 303) + self.assertEqual(response.content, b'') + self.assertEqual(response.headers['location'], f"http://localhost:3000/redirect?state={state.replace('=', '%3D')}&code={code}") @pytest.mark.asyncio async def test_search_with_multiple_emails(self): diff --git a/tests/Flask/test_flask.py b/tests/Flask/test_flask.py index 3770d7d60..330f5a105 100644 --- a/tests/Flask/test_flask.py +++ b/tests/Flask/test_flask.py @@ -14,6 +14,7 @@ import json from typing import Any, Dict, Union +from base64 import b64encode import pytest from _pytest.fixtures import fixture @@ -477,17 +478,15 @@ def test_thirdparty_parsing_works(driver_config_app: Any): start_st() test_client = driver_config_app.test_client() - data = { - "state": "afc596274293e1587315c", - "code": "c7685e261f98e4b3b94e34b3a69ff9cf4.0.rvxt.eE8rO__6hGoqaX1B7ODPmA", - } - response = test_client.post("/auth/callback/apple", data=data) + state = b64encode(json.dumps({"redirectURI": "http://localhost:3000/redirect" }).encode()).decode() + code = "testing" - assert response.status_code == 200 - assert ( - response.data - == b'' - ) + data = { "state": state, "code": code} + res = test_client.post("/auth/callback/apple", data=data) + + assert res.status_code == 303 + assert res.data == b'' + assert res.headers["location"] == f"http://localhost:3000/redirect?state={state.replace('=', '%3D')}&code={code}" from flask.wrappers import Response diff --git a/tests/sessions/claims/test_create_new_session.py b/tests/sessions/claims/test_create_new_session.py index bd0fb4703..bf4164f78 100644 --- a/tests/sessions/claims/test_create_new_session.py +++ b/tests/sessions/claims/test_create_new_session.py @@ -69,6 +69,6 @@ async def test_should_merge_claims_and_passed_access_token_payload_obj(timestamp s = await create_new_session(dummy_req, "someId") payload = s.get_access_token_payload() - assert len(payload) == 10 + assert len(payload) == 11 assert payload["st-true"] == {"v": True, "t": timestamp} assert payload["user-custom-claim"] == "foo" diff --git a/tests/sessions/claims/test_get_claim_value.py b/tests/sessions/claims/test_get_claim_value.py index 1825fac14..26560e860 100644 --- a/tests/sessions/claims/test_get_claim_value.py +++ b/tests/sessions/claims/test_get_claim_value.py @@ -45,7 +45,9 @@ async def test_should_get_the_right_value_using_session_handle(): assert isinstance(res, GetClaimValueOkResult) assert res.value is True +import pytest +@pytest.mark.skip async def test_should_work_for_non_existing_handle(): new_st_init = { **st_init_common_args, diff --git a/tests/sessions/claims/test_primitive_array_claim.py b/tests/sessions/claims/test_primitive_array_claim.py index 63c0859f2..ac1469b56 100644 --- a/tests/sessions/claims/test_primitive_array_claim.py +++ b/tests/sessions/claims/test_primitive_array_claim.py @@ -81,7 +81,7 @@ async def test_primitive_claim_fetch_value_params_correct(): user_id, ctx = "user_id", {} await claim.build(user_id, DEFAULT_TENANT_ID, ctx) assert sync_fetch_value.call_count == 1 - assert (user_id, ctx) == sync_fetch_value.call_args_list[0][ + assert (user_id, DEFAULT_TENANT_ID, ctx) == sync_fetch_value.call_args_list[0][ 0 ] # extra [0] refers to call params diff --git a/tests/sessions/claims/test_primitive_claim.py b/tests/sessions/claims/test_primitive_claim.py index 30f672dc7..2ee8d98ba 100644 --- a/tests/sessions/claims/test_primitive_claim.py +++ b/tests/sessions/claims/test_primitive_claim.py @@ -48,7 +48,7 @@ async def test_primitive_claim_fetch_value_params_correct(): user_id, ctx = "user_id", {} await claim.build(user_id, DEFAULT_TENANT_ID, ctx) assert sync_fetch_value.call_count == 1 - assert (user_id, ctx) == sync_fetch_value.call_args_list[0][ + assert (user_id, DEFAULT_TENANT_ID, ctx) == sync_fetch_value.call_args_list[0][ 0 ] # extra [0] refers to call params diff --git a/tests/sessions/claims/test_set_claim_value.py b/tests/sessions/claims/test_set_claim_value.py index b8b78e734..6242c5568 100644 --- a/tests/sessions/claims/test_set_claim_value.py +++ b/tests/sessions/claims/test_set_claim_value.py @@ -60,14 +60,14 @@ async def test_should_overwrite_claim_value(timestamp: int): s = await create_new_session(dummy_req, "someId") payload = s.get_access_token_payload() - assert len(payload) == 9 + assert len(payload) == 10 assert payload["st-true"] == {"t": timestamp, "v": True} await s.set_claim_value(TrueClaim, False) # Payload should be updated now: payload = s.get_access_token_payload() - assert len(payload) == 9 + assert len(payload) == 10 assert payload["st-true"] == {"t": timestamp, "v": False} @@ -79,7 +79,7 @@ async def test_should_overwrite_claim_value_using_session_handle(timestamp: int) s = await create_new_session(dummy_req, "someId") payload = s.get_access_token_payload() - assert len(payload) == 9 + assert len(payload) == 10 assert payload["st-true"] == {"t": timestamp, "v": True} await set_claim_value(s.get_handle(), TrueClaim, False) diff --git a/tests/sessions/claims/test_validate_claims_for_session_handle.py b/tests/sessions/claims/test_validate_claims_for_session_handle.py index 4fcc89912..d4b2b45fc 100644 --- a/tests/sessions/claims/test_validate_claims_for_session_handle.py +++ b/tests/sessions/claims/test_validate_claims_for_session_handle.py @@ -59,6 +59,6 @@ async def test_should_work_for_not_existing_handle(): start_st() res = await validate_claims_for_session_handle( - "non_existing_handle", lambda _, __, ___: [] + "non-existing-handle", lambda _, __, ___: [] ) assert isinstance(res, SessionDoesNotExistError) diff --git a/tests/sessions/claims/utils.py b/tests/sessions/claims/utils.py index 881a4b020..fd6ae7d65 100644 --- a/tests/sessions/claims/utils.py +++ b/tests/sessions/claims/utils.py @@ -8,8 +8,8 @@ from supertokens_python.recipe.session.interfaces import RecipeInterface from tests.utils import st_init_common_args -TrueClaim = BooleanClaim("st-true", fetch_value=lambda _, __: True) # type: ignore -NoneClaim = BooleanClaim("st-none", fetch_value=lambda _, __: None) # type: ignore +TrueClaim = BooleanClaim("st-true", fetch_value=lambda _, __, ___: True) # type: ignore +NoneClaim = BooleanClaim("st-none", fetch_value=lambda _, __, ___: None) # type: ignore def session_functions_override_with_claim( diff --git a/tests/thirdparty/test_thirdparty.py b/tests/thirdparty/test_thirdparty.py index 212e012ce..7e8584e25 100644 --- a/tests/thirdparty/test_thirdparty.py +++ b/tests/thirdparty/test_thirdparty.py @@ -1,4 +1,5 @@ import respx +import json from pytest import fixture, mark from fastapi import FastAPI @@ -7,6 +8,7 @@ from supertokens_python.recipe import session, thirdparty from supertokens_python import init +from base64 import b64encode from tests.utils import ( setup_function, @@ -65,15 +67,12 @@ async def test_thirdpary_parsing_works(fastapi_client: TestClient): init(**st_init_args) # type: ignore start_st() - data = { - "state": "afc596274293e1587315c", - "code": "c7685e261f98e4b3b94e34b3a69ff9cf4.0.rvxt.eE8rO__6hGoqaX1B7ODPmA", - } + state = b64encode(json.dumps({"redirectURI": "http://localhost:3000/redirect" }).encode()).decode() + code = "testing" + data = { "state": state, "code": code} res = fastapi_client.post("/auth/callback/apple", data=data) - assert res.status_code == 200 - assert ( - res.content - == b'' - ) + assert res.status_code == 303 + assert res.content == b'' + assert res.headers["location"] == f"http://localhost:3000/redirect?state={state.replace('=', '%3D')}&code={code}" From 3acd4e7f309110031b6e94e17e28f564437f96d2 Mon Sep 17 00:00:00 2001 From: KShivendu Date: Thu, 10 Aug 2023 14:06:25 +0530 Subject: [PATCH 12/13] test: Fix last failing tests --- tests/sessions/claims/test_get_claim_value.py | 4 +--- tests/test_session.py | 13 ++++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/sessions/claims/test_get_claim_value.py b/tests/sessions/claims/test_get_claim_value.py index 26560e860..3be48dd10 100644 --- a/tests/sessions/claims/test_get_claim_value.py +++ b/tests/sessions/claims/test_get_claim_value.py @@ -45,9 +45,7 @@ async def test_should_get_the_right_value_using_session_handle(): assert isinstance(res, GetClaimValueOkResult) assert res.value is True -import pytest -@pytest.mark.skip async def test_should_work_for_non_existing_handle(): new_st_init = { **st_init_common_args, @@ -58,5 +56,5 @@ async def test_should_work_for_non_existing_handle(): init(**new_st_init) # type: ignore start_st() - res = await get_claim_value("non_existing_handle", TrueClaim) + res = await get_claim_value("non-existing-handle", TrueClaim) assert isinstance(res, SessionDoesNotExistError) diff --git a/tests/test_session.py b/tests/test_session.py index ff123334e..3530cf2b7 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -202,7 +202,7 @@ async def test_creating_many_sessions_for_one_user_and_looping(): assert len(session_handles) == 7 - for i, handle in enumerate(session_handles): + for handle in session_handles: info = await get_session_information(handle) assert info is not None assert info.user_id == "someUser" @@ -224,19 +224,22 @@ async def test_creating_many_sessions_for_one_user_and_looping(): assert info.custom_claims_in_access_token_payload == {"someKey2": "someValue"} assert info.session_data_in_database == {"foo": "bar"} + regenerated_session_handles: List[str] = [] # Regenerate access token with new access_token_payload - for i, token in enumerate(access_tokens): + for token in access_tokens: result = await regenerate_access_token(token, {"bar": "baz"}) assert result is not None - assert ( - result.session.handle == session_handles[i] - ) # Session handle should remain the same + regenerated_session_handles.append(result.session.handle) # Confirm that update worked: info = await get_session_information(result.session.handle) assert info is not None assert info.custom_claims_in_access_token_payload == {"bar": "baz"} + # Session handle should remain the same session handle should remain the same + # but order isn't guaranteed so we should sort them + assert sorted(regenerated_session_handles) == sorted(session_handles) + # Try updating invalid handles: is_updated = await merge_into_access_token_payload("invalidHandle", {"foo": "bar"}) assert is_updated is False From b6624ab42f0f7dc84db187002dd151bff2d602a0 Mon Sep 17 00:00:00 2001 From: rishabhpoddar Date: Fri, 11 Aug 2023 11:40:41 +0530 Subject: [PATCH 13/13] fixes review comments --- supertokens_python/recipe/session/asyncio/__init__.py | 6 +++--- supertokens_python/recipe/session/interfaces.py | 2 +- supertokens_python/recipe/session/recipe_implementation.py | 2 +- supertokens_python/recipe/session/syncio/__init__.py | 4 ++-- supertokens_python/recipe/session/utils.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/supertokens_python/recipe/session/asyncio/__init__.py b/supertokens_python/recipe/session/asyncio/__init__.py index ed795da42..45a035e40 100644 --- a/supertokens_python/recipe/session/asyncio/__init__.py +++ b/supertokens_python/recipe/session/asyncio/__init__.py @@ -152,8 +152,8 @@ async def validate_claims_for_session_handle( ) global_claim_validators = await resolve( recipe_impl.get_global_claim_validators( - session_info.user_id, session_info.tenant_id, + session_info.user_id, claim_validators_added_by_other_recipes, user_context, ) @@ -188,8 +188,8 @@ async def validate_claims_for_session_handle( async def validate_claims_in_jwt_payload( - user_id: str, tenant_id: str, + user_id: str, jwt_payload: JSONObject, override_global_claim_validators: Optional[ Callable[ @@ -213,8 +213,8 @@ async def validate_claims_in_jwt_payload( ) global_claim_validators = await resolve( recipe_impl.get_global_claim_validators( - user_id, tenant_id, + user_id, claim_validators_added_by_other_recipes, user_context, ) diff --git a/supertokens_python/recipe/session/interfaces.py b/supertokens_python/recipe/session/interfaces.py index 5b2d156da..af51f8e67 100644 --- a/supertokens_python/recipe/session/interfaces.py +++ b/supertokens_python/recipe/session/interfaces.py @@ -154,8 +154,8 @@ async def create_new_session( @abstractmethod def get_global_claim_validators( self, - user_id: str, tenant_id: str, + user_id: str, claim_validators_added_by_other_recipes: List[SessionClaimValidator], user_context: Dict[str, Any], ) -> MaybeAwaitable[List[SessionClaimValidator]]: diff --git a/supertokens_python/recipe/session/recipe_implementation.py b/supertokens_python/recipe/session/recipe_implementation.py index 2a061e9fe..c45751383 100644 --- a/supertokens_python/recipe/session/recipe_implementation.py +++ b/supertokens_python/recipe/session/recipe_implementation.py @@ -437,8 +437,8 @@ async def get_claim_value( def get_global_claim_validators( self, - user_id: str, tenant_id: str, + user_id: str, claim_validators_added_by_other_recipes: List[SessionClaimValidator], user_context: Dict[str, Any], ) -> MaybeAwaitable[List[SessionClaimValidator]]: diff --git a/supertokens_python/recipe/session/syncio/__init__.py b/supertokens_python/recipe/session/syncio/__init__.py index dc4e9d140..0072895a2 100644 --- a/supertokens_python/recipe/session/syncio/__init__.py +++ b/supertokens_python/recipe/session/syncio/__init__.py @@ -385,8 +385,8 @@ def validate_claims_for_session_handle( def validate_claims_in_jwt_payload( - user_id: str, tenant_id: str, + user_id: str, jwt_payload: JSONObject, override_global_claim_validators: Optional[ Callable[ @@ -402,8 +402,8 @@ def validate_claims_in_jwt_payload( return sync( async_validate_claims_in_jwt_payload( - user_id, tenant_id, + user_id, jwt_payload, override_global_claim_validators, user_context, diff --git a/supertokens_python/recipe/session/utils.py b/supertokens_python/recipe/session/utils.py index eab3c39cc..fcfe6a330 100644 --- a/supertokens_python/recipe/session/utils.py +++ b/supertokens_python/recipe/session/utils.py @@ -480,8 +480,8 @@ async def get_required_claim_validators( ) global_claim_validators = await resolve( SessionRecipe.get_instance().recipe_implementation.get_global_claim_validators( - session.get_user_id(), session.get_tenant_id(), + session.get_user_id(), claim_validators_added_by_other_recipes, user_context, )