diff --git a/supertokens_python/recipe/dashboard/api/analytics.py b/supertokens_python/recipe/dashboard/api/analytics.py index a04c52411..b467299e2 100644 --- a/supertokens_python/recipe/dashboard/api/analytics.py +++ b/supertokens_python/recipe/dashboard/api/analytics.py @@ -14,7 +14,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Dict, Any from httpx import AsyncClient @@ -35,7 +35,7 @@ async def handle_analytics_post( - _: APIInterface, api_options: APIOptions + _: APIInterface, api_options: APIOptions, _user_context: Dict[str, Any] ) -> AnalyticsResponse: if not Supertokens.get_instance().telemetry: return AnalyticsResponse() diff --git a/supertokens_python/recipe/dashboard/api/api_key_protector.py b/supertokens_python/recipe/dashboard/api/api_key_protector.py index 591c7f139..0ea448881 100644 --- a/supertokens_python/recipe/dashboard/api/api_key_protector.py +++ b/supertokens_python/recipe/dashboard/api/api_key_protector.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING, Callable, Optional, Awaitable +from typing import TYPE_CHECKING, Callable, Optional, Awaitable, Dict, Any from supertokens_python.framework import BaseResponse @@ -25,7 +25,6 @@ from supertokens_python.types import APIResponse from supertokens_python.utils import ( - default_user_context, send_200_response, send_non_200_response_with_message, ) @@ -34,9 +33,11 @@ async def api_key_protector( api_implementation: APIInterface, api_options: APIOptions, - api_function: Callable[[APIInterface, APIOptions], Awaitable[APIResponse]], + api_function: Callable[ + [APIInterface, APIOptions, Dict[str, Any]], Awaitable[APIResponse] + ], + user_context: Dict[str, Any], ) -> Optional[BaseResponse]: - user_context = default_user_context(api_options.request) should_allow_access = await api_options.recipe_implementation.should_allow_access( api_options.request, api_options.config, user_context ) @@ -46,5 +47,5 @@ async def api_key_protector( "Unauthorised access", 401, api_options.response ) - response = await api_function(api_implementation, api_options) + response = await api_function(api_implementation, api_options, user_context) return send_200_response(response.to_json(), api_options.response) diff --git a/supertokens_python/recipe/dashboard/api/dashboard.py b/supertokens_python/recipe/dashboard/api/dashboard.py index 229d9852f..291da8403 100644 --- a/supertokens_python/recipe/dashboard/api/dashboard.py +++ b/supertokens_python/recipe/dashboard/api/dashboard.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, Dict, Any from supertokens_python.framework import BaseResponse @@ -23,16 +23,15 @@ APIInterface, ) -from supertokens_python.utils import default_user_context - async def handle_dashboard_api( - api_implementation: APIInterface, api_options: APIOptions + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ) -> Optional[BaseResponse]: if api_implementation.dashboard_get is None: return None - user_context = default_user_context(api_options.request) html_str = await api_implementation.dashboard_get(api_options, user_context) api_options.response.set_html_content(html_str) diff --git a/supertokens_python/recipe/dashboard/api/search/getTags.py b/supertokens_python/recipe/dashboard/api/search/getTags.py index b22b74693..20598c62a 100644 --- a/supertokens_python/recipe/dashboard/api/search/getTags.py +++ b/supertokens_python/recipe/dashboard/api/search/getTags.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Dict, Any if TYPE_CHECKING: from supertokens_python.recipe.dashboard.interfaces import APIInterface, APIOptions @@ -23,7 +23,9 @@ from supertokens_python.recipe.dashboard.interfaces import SearchTagsOK -async def handle_get_tags(_: APIInterface, __: APIOptions) -> SearchTagsOK: +async def handle_get_tags( + _: APIInterface, __: APIOptions, _user_context: Dict[str, Any] +) -> SearchTagsOK: response = await Querier.get_instance().send_get_request( NormalisedURLPath("/user/search/tags") ) diff --git a/supertokens_python/recipe/dashboard/api/signin.py b/supertokens_python/recipe/dashboard/api/signin.py index f0bc46620..ab5d20f11 100644 --- a/supertokens_python/recipe/dashboard/api/signin.py +++ b/supertokens_python/recipe/dashboard/api/signin.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Dict, Any if TYPE_CHECKING: from supertokens_python.recipe.dashboard.interfaces import APIInterface, APIOptions @@ -24,7 +24,9 @@ from supertokens_python.utils import send_200_response -async def handle_emailpassword_signin_api(_: APIInterface, api_options: APIOptions): +async def handle_emailpassword_signin_api( + _: APIInterface, api_options: APIOptions, _user_context: Dict[str, Any] +): body = await api_options.request.json() if body is None: raise_bad_input_exception("Please send body") diff --git a/supertokens_python/recipe/dashboard/api/signout.py b/supertokens_python/recipe/dashboard/api/signout.py index cafb3cf98..136441f1b 100644 --- a/supertokens_python/recipe/dashboard/api/signout.py +++ b/supertokens_python/recipe/dashboard/api/signout.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Dict, Any if TYPE_CHECKING: from supertokens_python.recipe.dashboard.interfaces import APIInterface, APIOptions @@ -26,7 +26,7 @@ async def handle_emailpassword_signout_api( - _: APIInterface, api_options: APIOptions + _: APIInterface, api_options: APIOptions, _user_context: Dict[str, Any] ) -> SignOutOK: if api_options.config.auth_mode == "api-key": return SignOutOK() diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_delete.py b/supertokens_python/recipe/dashboard/api/userdetails/user_delete.py index 2fcb7b1d3..62a5f4281 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_delete.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_delete.py @@ -1,10 +1,12 @@ +from typing import Any, Dict + from ...interfaces import APIInterface, APIOptions, UserDeleteAPIResponse from supertokens_python.exceptions import raise_bad_input_exception from supertokens_python import Supertokens async def handle_user_delete( - _api_interface: APIInterface, api_options: APIOptions + _api_interface: APIInterface, api_options: APIOptions, _user_context: Dict[str, Any] ) -> UserDeleteAPIResponse: user_id = api_options.request.get_query_param("userId") diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_get.py b/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_get.py index 3b6328aae..c9caa2f23 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_get.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_get.py @@ -8,11 +8,11 @@ FeatureNotEnabledError, ) -from typing import Union +from typing import Union, Dict, Any async def handle_user_email_verify_get( - _api_interface: APIInterface, api_options: APIOptions + _api_interface: APIInterface, api_options: APIOptions, user_context: Dict[str, Any] ) -> Union[UserEmailVerifyGetAPIResponse, FeatureNotEnabledError]: req = api_options.request user_id = req.get_query_param("userId") @@ -25,5 +25,5 @@ async def handle_user_email_verify_get( except Exception: return FeatureNotEnabledError() - is_verified = await is_email_verified(user_id) + is_verified = await is_email_verified(user_id, user_context=user_context) return UserEmailVerifyGetAPIResponse(is_verified) diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_put.py b/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_put.py index f52a70322..f26971a78 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_put.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_put.py @@ -19,7 +19,7 @@ async def handle_user_email_verify_put( - _api_interface: APIInterface, api_options: APIOptions + _api_interface: APIInterface, api_options: APIOptions, user_context: Dict[str, Any] ) -> UserEmailVerifyPutAPIResponse: request_body: Dict[str, Any] = await api_options.request.json() # type: ignore user_id = request_body.get("userId") @@ -36,20 +36,24 @@ async def handle_user_email_verify_put( ) if verified: - token_response = await create_email_verification_token(user_id) + token_response = await create_email_verification_token( + user_id, user_context=user_context + ) if isinstance( token_response, CreateEmailVerificationTokenEmailAlreadyVerifiedError ): return UserEmailVerifyPutAPIResponse() - verify_response = await verify_email_using_token(token_response.token) + verify_response = await verify_email_using_token( + token_response.token, user_context=user_context + ) if isinstance(verify_response, VerifyEmailUsingTokenInvalidTokenError): # This should never happen because we consume the token immediately after creating it raise Exception("Should not come here") else: - await unverify_email(user_id) + await unverify_email(user_id, user_context=user_context) return UserEmailVerifyPutAPIResponse() diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_token_post.py b/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_token_post.py index 4f6bf2dea..84467be07 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_token_post.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_email_verify_token_post.py @@ -28,7 +28,7 @@ async def handle_email_verify_token_post( - _api_interface: APIInterface, api_options: APIOptions + _api_interface: APIInterface, api_options: APIOptions, user_context: Dict[str, Any] ) -> Union[ UserEmailVerifyTokenPostAPIOkResponse, UserEmailVerifyTokenPostAPIEmailAlreadyVerifiedErrorResponse, @@ -42,13 +42,15 @@ async def handle_email_verify_token_post( ) email_response = await EmailVerificationRecipe.get_instance().get_email_for_user_id( - user_id, {} + user_id, user_context ) if not isinstance(email_response, GetEmailForUserIdOkResult): raise Exception("Should not come here") - email_verification_token = await create_email_verification_token(user_id) + email_verification_token = await create_email_verification_token( + user_id, user_context=user_context + ) if isinstance( email_verification_token, CreateEmailVerificationTokenEmailAlreadyVerifiedError diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_get.py b/supertokens_python/recipe/dashboard/api/userdetails/user_get.py index d501f7297..8d224a12e 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_get.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_get.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Union, Dict, Any from supertokens_python.exceptions import raise_bad_input_exception from supertokens_python.recipe.dashboard.utils import get_user_for_recipe_id @@ -16,7 +16,7 @@ async def handle_user_get( - _api_interface: APIInterface, api_options: APIOptions + _api_interface: APIInterface, api_options: APIOptions, _user_context: Dict[str, Any] ) -> Union[ UserGetAPINoUserFoundError, UserGetAPIOkResponse, @@ -51,7 +51,7 @@ async def handle_user_get( return UserGetAPIOkResponse(recipe_id, user) - user_metadata = await get_user_metadata(user_id) + user_metadata = await get_user_metadata(user_id, user_context=_user_context) first_name = user_metadata.metadata.get("first_name", "") last_name = user_metadata.metadata.get("last_name", "") diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_metadata_get.py b/supertokens_python/recipe/dashboard/api/userdetails/user_metadata_get.py index ddd61b1f3..381a67125 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_metadata_get.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_metadata_get.py @@ -7,11 +7,11 @@ from supertokens_python.exceptions import raise_bad_input_exception from supertokens_python.recipe.usermetadata import UserMetadataRecipe from supertokens_python.recipe.usermetadata.asyncio import get_user_metadata -from typing import Union +from typing import Union, Dict, Any async def handle_metadata_get( - _api_interface: APIInterface, api_options: APIOptions + _api_interface: APIInterface, api_options: APIOptions, user_context: Dict[str, Any] ) -> Union[UserMetadataGetAPIOkResponse, FeatureNotEnabledError]: user_id = api_options.request.get_query_param("userId") @@ -23,5 +23,5 @@ async def handle_metadata_get( except Exception: return FeatureNotEnabledError() - metadata_response = await get_user_metadata(user_id) + metadata_response = await get_user_metadata(user_id, user_context=user_context) return UserMetadataGetAPIOkResponse(metadata_response.metadata) diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_metadata_put.py b/supertokens_python/recipe/dashboard/api/userdetails/user_metadata_put.py index 21ffe6614..ab6c834d3 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_metadata_put.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_metadata_put.py @@ -12,7 +12,7 @@ async def handle_metadata_put( - _api_interface: APIInterface, api_options: APIOptions + _api_interface: APIInterface, api_options: APIOptions, user_context: Dict[str, Any] ) -> UserMetadataPutAPIResponse: request_body: Dict[str, Any] = await api_options.request.json() # type: ignore user_id = request_body.get("userId") @@ -50,7 +50,7 @@ async def handle_metadata_put( # # Removing first ensures that the final data is exactly what the user wanted it to be - await clear_user_metadata(user_id) - await update_user_metadata(user_id, parsed_data) + await clear_user_metadata(user_id, user_context) + await update_user_metadata(user_id, parsed_data, user_context) return UserMetadataPutAPIResponse() diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_password_put.py b/supertokens_python/recipe/dashboard/api/userdetails/user_password_put.py index aa7137a3f..9b1be8491 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_password_put.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_password_put.py @@ -37,7 +37,7 @@ async def handle_user_password_put( - _api_interface: APIInterface, api_options: APIOptions + _api_interface: APIInterface, api_options: APIOptions, user_context: Dict[str, Any] ) -> Union[UserPasswordPutAPIResponse, UserPasswordPutAPIInvalidPasswordErrorResponse]: request_body: Dict[str, Any] = await api_options.request.json() # type: ignore user_id = request_body.get("userId") @@ -72,13 +72,13 @@ async def handle_user_password_put( async def reset_password( form_fields: List[NormalisedFormField], create_reset_password_token: Callable[ - [str], + [str, Dict[str, Any]], Awaitable[ Union[CreateResetPasswordOkResult, CreateResetPasswordWrongUserIdError] ], ], reset_password_using_token: Callable[ - [str, str], + [str, str, Dict[str, Any]], Awaitable[ Union[ ResetPasswordUsingTokenOkResult, @@ -100,15 +100,15 @@ async def reset_password( password_validation_error ) - password_reset_token = await create_reset_password_token(user_id) # type: ignore # FIXME + password_reset_token = await create_reset_password_token(user_id, user_context) if isinstance(password_reset_token, CreateResetPasswordWrongUserIdError): # Techincally it can but its an edge case so we assume that it wont - # UNKNOWN_USER_ID_ERROR FIXME + # UNKNOWN_USER_ID_ERROR raise Exception("Should never come here") password_reset_response = await reset_password_using_token( - password_reset_token.token, new_password + password_reset_token.token, new_password, user_context ) if isinstance( diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_put.py b/supertokens_python/recipe/dashboard/api/userdetails/user_put.py index 354c7729a..000028159 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_put.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_put.py @@ -58,7 +58,7 @@ async def update_email_for_recipe_id( - recipe_id: str, user_id: str, email: str + recipe_id: str, user_id: str, email: str, user_context: Dict[str, Any] ) -> Union[ UserPutAPIOkResponse, UserPutAPIInvalidEmailErrorResponse, @@ -81,7 +81,9 @@ async def update_email_for_recipe_id( if validation_error is not None: return UserPutAPIInvalidEmailErrorResponse(validation_error) - email_update_response = await ep_update_email_or_password(user_id, email) + email_update_response = await ep_update_email_or_password( + user_id, email, user_context=user_context + ) if isinstance( email_update_response, UpdateEmailOrPasswordEmailAlreadyExistsError @@ -105,7 +107,9 @@ async def update_email_for_recipe_id( if validation_error is not None: return UserPutAPIInvalidEmailErrorResponse(validation_error) - email_update_response = await tpep_update_email_or_password(user_id, email) + email_update_response = await tpep_update_email_or_password( + user_id, email, user_context=user_context + ) if isinstance( email_update_response, UpdateEmailOrPasswordEmailAlreadyExistsError @@ -133,7 +137,9 @@ async def update_email_for_recipe_id( if validation_error is not None: return UserPutAPIInvalidEmailErrorResponse(validation_error) - update_result = await pless_update_user(user_id, email) + update_result = await pless_update_user( + user_id, email, user_context=user_context + ) if isinstance(update_result, PlessUpdateUserUnknownUserIdError): raise Exception("Should never come here") @@ -160,7 +166,9 @@ async def update_email_for_recipe_id( if validation_error is not None: return UserPutAPIInvalidEmailErrorResponse(validation_error) - update_result = await pless_update_user(user_id, email) + update_result = await pless_update_user( + user_id, email, user_context=user_context + ) if isinstance(update_result, PlessUpdateUserUnknownUserIdError): raise Exception("Should never come here") @@ -175,7 +183,7 @@ async def update_email_for_recipe_id( async def update_phone_for_recipe_id( - recipe_id: str, user_id: str, phone: str + recipe_id: str, user_id: str, phone: str, user_context: Dict[str, Any] ) -> Union[ UserPutAPIOkResponse, UserPutAPIInvalidPhoneErrorResponse, @@ -198,7 +206,9 @@ async def update_phone_for_recipe_id( if validation_error is not None: return UserPutAPIInvalidPhoneErrorResponse(validation_error) - update_result = await pless_update_user(user_id, phone_number=phone) + update_result = await pless_update_user( + user_id, phone_number=phone, user_context=user_context + ) if isinstance(update_result, PlessUpdateUserUnknownUserIdError): raise Exception("Should never come here") @@ -226,7 +236,9 @@ async def update_phone_for_recipe_id( if validation_error is not None: return UserPutAPIInvalidPhoneErrorResponse(validation_error) - update_result = await pless_update_user(user_id, phone_number=phone) + update_result = await pless_update_user( + user_id, phone_number=phone, user_context=user_context + ) if isinstance(update_result, PlessUpdateUserUnknownUserIdError): raise Exception("Should never come here") @@ -241,7 +253,7 @@ async def update_phone_for_recipe_id( async def handle_user_put( - _api_interface: APIInterface, api_options: APIOptions + _api_interface: APIInterface, api_options: APIOptions, user_context: Dict[str, Any] ) -> Union[ UserPutAPIOkResponse, UserPutAPIInvalidEmailErrorResponse, @@ -318,11 +330,11 @@ async def handle_user_put( if last_name != "": metadata_update["last_name"] = last_name - await update_user_metadata(user_id, metadata_update) + await update_user_metadata(user_id, metadata_update, user_context) if email != "": email_update_response = await update_email_for_recipe_id( - user_response.recipe, user_id, email + user_response.recipe, user_id, email, user_context ) if not isinstance(email_update_response, UserPutAPIOkResponse): @@ -330,7 +342,7 @@ async def handle_user_put( if phone != "": phone_update_response = await update_phone_for_recipe_id( - user_response.recipe, user_id, phone + user_response.recipe, user_id, phone, user_context ) if not isinstance(phone_update_response, UserPutAPIOkResponse): 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 115057b16..7d5aa8e9c 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_get.py @@ -1,5 +1,5 @@ import asyncio -from typing import List, Optional +from typing import List, Optional, Dict, Any from supertokens_python.exceptions import raise_bad_input_exception from supertokens_python.recipe.session.asyncio import ( @@ -16,19 +16,21 @@ async def handle_sessions_get( - _api_interface: APIInterface, api_options: APIOptions + _api_interface: APIInterface, api_options: APIOptions, user_context: Dict[str, Any] ) -> UserSessionsGetAPIResponse: user_id = api_options.request.get_query_param("userId") if user_id is None: raise_bad_input_exception("Missing required parameter 'userId'") - session_handles = await get_all_session_handles_for_user(user_id) + session_handles = await get_all_session_handles_for_user(user_id, user_context) sessions: List[Optional[SessionInfo]] = [None for _ in session_handles] async def call_(i: int, session_handle: str): try: - session_response = await get_session_information(session_handle) + session_response = await get_session_information( + session_handle, user_context + ) if session_response is not None: sessions[i] = SessionInfo(session_response) except Exception: diff --git a/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_post.py b/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_post.py index cfab3e800..cad0c2020 100644 --- a/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_post.py +++ b/supertokens_python/recipe/dashboard/api/userdetails/user_sessions_post.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Union +from typing import Any, Dict, List, Optional from supertokens_python.exceptions import raise_bad_input_exception from supertokens_python.recipe.session.asyncio import revoke_multiple_sessions @@ -6,15 +6,15 @@ async def handle_user_sessions_post( - _api_interface: APIInterface, api_options: APIOptions + _api_interface: APIInterface, api_options: APIOptions, _user_context: Dict[str, Any] ) -> UserSessionsPostAPIResponse: - request_body: Dict[str, Any] = await api_options.request.json() # type: ignore - session_handles: Union[List[str], Any] = request_body.get("sessionHandles") + request_body = await api_options.request.json() # type: ignore + session_handles: Optional[List[str]] = request_body.get("sessionHandles") # type: ignore - if session_handles is None or not isinstance(session_handles, list): - return raise_bad_input_exception( + if not isinstance(session_handles, list): + raise_bad_input_exception( "Required parameter 'sessionHandles' is missing or has an invalid type" ) - await revoke_multiple_sessions(session_handles) + await revoke_multiple_sessions(session_handles, _user_context) return UserSessionsPostAPIResponse() diff --git a/supertokens_python/recipe/dashboard/api/users_count_get.py b/supertokens_python/recipe/dashboard/api/users_count_get.py index d8bc7ab90..cb0bb1aa5 100644 --- a/supertokens_python/recipe/dashboard/api/users_count_get.py +++ b/supertokens_python/recipe/dashboard/api/users_count_get.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Dict, Any from supertokens_python.supertokens import Supertokens from supertokens_python.recipe.dashboard.interfaces import UserCountGetAPIResponse @@ -26,7 +26,7 @@ async def handle_users_count_get_api( - _: APIInterface, _api_options: APIOptions + _: APIInterface, _api_options: APIOptions, _user_context: Dict[str, Any] ) -> UserCountGetAPIResponse: count = await Supertokens.get_instance().get_user_count(include_recipe_ids=None) return UserCountGetAPIResponse(count=count) diff --git a/supertokens_python/recipe/dashboard/api/users_get.py b/supertokens_python/recipe/dashboard/api/users_get.py index 72a4ecc0d..1bd8b5670 100644 --- a/supertokens_python/recipe/dashboard/api/users_get.py +++ b/supertokens_python/recipe/dashboard/api/users_get.py @@ -14,7 +14,7 @@ from __future__ import annotations import asyncio -from typing import TYPE_CHECKING, Any, Awaitable, List +from typing import TYPE_CHECKING, Any, Awaitable, List, Dict from supertokens_python.supertokens import Supertokens @@ -34,7 +34,9 @@ async def handle_users_get_api( - api_implementation: APIInterface, api_options: APIOptions + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ) -> APIResponse: _ = api_implementation @@ -74,7 +76,7 @@ async def handle_users_get_api( async def get_user_metadata_and_update_user(user_idx: int) -> None: user = users_response.users[user_idx] - user_metadata = await get_user_metadata(user.user_id) + user_metadata = await get_user_metadata(user.user_id, user_context) first_name = user_metadata.metadata.get("first_name") last_name = user_metadata.metadata.get("last_name") diff --git a/supertokens_python/recipe/dashboard/api/validate_key.py b/supertokens_python/recipe/dashboard/api/validate_key.py index 932a0b76a..12e5758c9 100644 --- a/supertokens_python/recipe/dashboard/api/validate_key.py +++ b/supertokens_python/recipe/dashboard/api/validate_key.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Dict, Any if TYPE_CHECKING: from supertokens_python.recipe.dashboard.interfaces import ( @@ -30,10 +30,14 @@ async def handle_validate_key_api( - _api_implementation: APIInterface, api_options: APIOptions + _api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ): - is_valid_key = validate_api_key(api_options.request, api_options.config) + is_valid_key = validate_api_key( + api_options.request, api_options.config, user_context + ) if is_valid_key: return send_200_response({"status": "OK"}, api_options.response) diff --git a/supertokens_python/recipe/dashboard/recipe.py b/supertokens_python/recipe/dashboard/recipe.py index 77244273d..a53f39a81 100644 --- a/supertokens_python/recipe/dashboard/recipe.py +++ b/supertokens_python/recipe/dashboard/recipe.py @@ -55,6 +55,7 @@ from supertokens_python.types import APIResponse from supertokens_python.exceptions import SuperTokensError, raise_general_exception +from supertokens_python.recipe.multitenancy.recipe import MultitenancyRecipe from .constants import ( DASHBOARD_ANALYTICS_API, @@ -145,17 +146,21 @@ async def handle_api_request( ) # For these APIs we dont need API key validation if request_id == DASHBOARD_API: - return await handle_dashboard_api(self.api_implementation, api_options) + return await handle_dashboard_api( + self.api_implementation, api_options, user_context + ) if request_id == VALIDATE_KEY_API: - return await handle_validate_key_api(self.api_implementation, api_options) + return await handle_validate_key_api( + self.api_implementation, api_options, user_context + ) if request_id == EMAIL_PASSWORD_SIGN_IN: return await handle_emailpassword_signin_api( - self.api_implementation, api_options + self.api_implementation, api_options, user_context ) # Do API key validation for the remaining APIs api_function: Optional[ - Callable[[APIInterface, APIOptions], Awaitable[APIResponse]] + Callable[[APIInterface, APIOptions, Dict[str, Any]], Awaitable[APIResponse]] ] = None if request_id == USERS_LIST_GET_API: api_function = handle_users_get_api @@ -197,7 +202,7 @@ async def handle_api_request( if api_function is not None: return await api_key_protector( - self.api_implementation, api_options, api_function + self.api_implementation, api_options, api_function, user_context ) return None @@ -247,7 +252,7 @@ def reset(): raise_general_exception("calling testing function in non testing env") DashboardRecipe.__instance = None - def return_api_id_if_can_handle_request( + async def return_api_id_if_can_handle_request( self, path: NormalisedURLPath, method: str, user_context: Dict[str, Any] ) -> Union[ApiIdWithTenantId, None]: dashboard_bundle_path = self.app_info.api_base_path.append( @@ -279,6 +284,8 @@ def return_api_id_if_can_handle_request( tenant_id = match_group_1 remaining_path = NormalisedURLPath(match_group_2) + mt_recipe = MultitenancyRecipe.get_instance() + if is_api_path(path, self.app_info.api_base_path) or ( remaining_path is not None and is_api_path( @@ -291,11 +298,20 @@ def return_api_id_if_can_handle_request( if remaining_path is not None: id_ = get_api_if_matched(remaining_path, method) if id_ is not None: - return ApiIdWithTenantId(id_, tenant_id) + final_tenant_id = ( + await mt_recipe.recipe_implementation.get_tenant_id( + DEFAULT_TENANT_ID if tenant_id is None else tenant_id, + user_context, + ) + ) + return ApiIdWithTenantId(id_, final_tenant_id) id_ = get_api_if_matched(path, method) if id_ is not None: - return ApiIdWithTenantId(id_, DEFAULT_TENANT_ID) + final_tenant_id = await mt_recipe.recipe_implementation.get_tenant_id( + DEFAULT_TENANT_ID, user_context + ) + return ApiIdWithTenantId(id_, final_tenant_id) if path.startswith(dashboard_bundle_path): return ApiIdWithTenantId(DASHBOARD_API, DEFAULT_TENANT_ID) diff --git a/supertokens_python/recipe/dashboard/recipe_implementation.py b/supertokens_python/recipe/dashboard/recipe_implementation.py index 9207e8f4d..9d34fb9ca 100644 --- a/supertokens_python/recipe/dashboard/recipe_implementation.py +++ b/supertokens_python/recipe/dashboard/recipe_implementation.py @@ -51,4 +51,4 @@ async def should_allow_access( "status" in session_verification_response and session_verification_response["status"] == "OK" ) - return validate_api_key(request, config) + return validate_api_key(request, config, user_context) diff --git a/supertokens_python/recipe/dashboard/utils.py b/supertokens_python/recipe/dashboard/utils.py index fbc3f79ad..5a9ba5c19 100644 --- a/supertokens_python/recipe/dashboard/utils.py +++ b/supertokens_python/recipe/dashboard/utils.py @@ -397,7 +397,9 @@ def is_recipe_initialised(recipeId: str) -> bool: return isRecipeInitialised -def validate_api_key(req: BaseRequest, config: DashboardConfig) -> bool: +def validate_api_key( + req: BaseRequest, config: DashboardConfig, _user_context: Dict[str, Any] +) -> bool: api_key_header_value = req.get_header("authorization") if not api_key_header_value: return False diff --git a/supertokens_python/recipe/emailpassword/api/email_exists.py b/supertokens_python/recipe/emailpassword/api/email_exists.py index fbf9b0108..eb227c146 100644 --- a/supertokens_python/recipe/emailpassword/api/email_exists.py +++ b/supertokens_python/recipe/emailpassword/api/email_exists.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Dict, Any if TYPE_CHECKING: from supertokens_python.recipe.emailpassword.interfaces import ( @@ -22,18 +22,19 @@ ) from supertokens_python.exceptions import raise_bad_input_exception -from supertokens_python.utils import send_200_response, default_user_context +from supertokens_python.utils import send_200_response async def handle_email_exists_api( - api_implementation: APIInterface, api_options: APIOptions + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ): if api_implementation.disable_email_exists_get: return None email = api_options.request.get_query_param("email") if email is None: raise_bad_input_exception("Please provide the email as a GET param") - user_context = default_user_context(api_options.request) response = await api_implementation.email_exists_get( email, api_options, user_context diff --git a/supertokens_python/recipe/emailpassword/api/generate_password_reset_token.py b/supertokens_python/recipe/emailpassword/api/generate_password_reset_token.py index 98826ee44..ac1fc4b9e 100644 --- a/supertokens_python/recipe/emailpassword/api/generate_password_reset_token.py +++ b/supertokens_python/recipe/emailpassword/api/generate_password_reset_token.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Dict if TYPE_CHECKING: from supertokens_python.recipe.emailpassword.interfaces import ( @@ -22,13 +22,15 @@ ) from supertokens_python.exceptions import raise_bad_input_exception -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response from .utils import validate_form_fields_or_throw_error async def handle_generate_password_reset_token_api( - api_implementation: APIInterface, api_options: APIOptions + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ): if api_implementation.disable_generate_password_reset_token_post: return None @@ -40,7 +42,6 @@ async def handle_generate_password_reset_token_api( api_options.config.reset_password_using_token_feature.form_fields_for_generate_token_form, form_fields_raw, ) - user_context = default_user_context(api_options.request) response = await api_implementation.generate_password_reset_token_post( form_fields, api_options, user_context diff --git a/supertokens_python/recipe/emailpassword/api/password_reset.py b/supertokens_python/recipe/emailpassword/api/password_reset.py index f25012809..b12451f97 100644 --- a/supertokens_python/recipe/emailpassword/api/password_reset.py +++ b/supertokens_python/recipe/emailpassword/api/password_reset.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Dict if TYPE_CHECKING: from supertokens_python.recipe.emailpassword.interfaces import ( @@ -22,13 +22,15 @@ ) from supertokens_python.exceptions import raise_bad_input_exception -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response from .utils import validate_form_fields_or_throw_error async def handle_password_reset_api( - api_implementation: APIInterface, api_options: APIOptions + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ): if api_implementation.disable_generate_password_reset_token_post: return None @@ -47,7 +49,6 @@ async def handle_password_reset_api( raise_bad_input_exception("The password reset token must be a string") token = body["token"] - user_context = default_user_context(api_options.request) response = await api_implementation.password_reset_post( form_fields, token, api_options, user_context diff --git a/supertokens_python/recipe/emailpassword/api/signin.py b/supertokens_python/recipe/emailpassword/api/signin.py index 7a60409d8..9577adea2 100644 --- a/supertokens_python/recipe/emailpassword/api/signin.py +++ b/supertokens_python/recipe/emailpassword/api/signin.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Dict if TYPE_CHECKING: from supertokens_python.recipe.emailpassword.interfaces import ( @@ -22,12 +22,16 @@ ) from supertokens_python.exceptions import raise_bad_input_exception -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response from .utils import validate_form_fields_or_throw_error -async def handle_sign_in_api(api_implementation: APIInterface, api_options: APIOptions): +async def handle_sign_in_api( + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], +): if api_implementation.disable_sign_in_post: return None body = await api_options.request.json() @@ -37,7 +41,6 @@ async def handle_sign_in_api(api_implementation: APIInterface, api_options: APIO form_fields = await validate_form_fields_or_throw_error( api_options.config.sign_in_feature.form_fields, form_fields_raw ) - user_context = default_user_context(api_options.request) response = await api_implementation.sign_in_post( form_fields, api_options, user_context diff --git a/supertokens_python/recipe/emailpassword/api/signup.py b/supertokens_python/recipe/emailpassword/api/signup.py index a4f0e56ef..625da77be 100644 --- a/supertokens_python/recipe/emailpassword/api/signup.py +++ b/supertokens_python/recipe/emailpassword/api/signup.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Dict from supertokens_python.recipe.emailpassword.interfaces import SignUpPostOkResult from supertokens_python.types import GeneralErrorResponse @@ -28,12 +28,16 @@ ) from supertokens_python.exceptions import raise_bad_input_exception -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response from .utils import validate_form_fields_or_throw_error -async def handle_sign_up_api(api_implementation: APIInterface, api_options: APIOptions): +async def handle_sign_up_api( + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], +): if api_implementation.disable_sign_up_post: return None body = await api_options.request.json() @@ -43,7 +47,6 @@ async def handle_sign_up_api(api_implementation: APIInterface, api_options: APIO form_fields = await validate_form_fields_or_throw_error( api_options.config.sign_up_feature.form_fields, form_fields_raw ) - user_context = default_user_context(api_options.request) response = await api_implementation.sign_up_post( form_fields, api_options, user_context diff --git a/supertokens_python/recipe/emailpassword/recipe.py b/supertokens_python/recipe/emailpassword/recipe.py index 42f410fa5..ba7b017de 100644 --- a/supertokens_python/recipe/emailpassword/recipe.py +++ b/supertokens_python/recipe/emailpassword/recipe.py @@ -187,17 +187,25 @@ async def handle_api_request( self.email_delivery, ) if request_id == SIGNUP: - return await handle_sign_up_api(self.api_implementation, api_options) + return await handle_sign_up_api( + self.api_implementation, api_options, user_context + ) if request_id == SIGNIN: - return await handle_sign_in_api(self.api_implementation, api_options) + return await handle_sign_in_api( + self.api_implementation, api_options, user_context + ) if request_id == SIGNUP_EMAIL_EXISTS: - return await handle_email_exists_api(self.api_implementation, api_options) + return await handle_email_exists_api( + self.api_implementation, api_options, user_context + ) if request_id == USER_PASSWORD_RESET_TOKEN: return await handle_generate_password_reset_token_api( - self.api_implementation, api_options + self.api_implementation, api_options, user_context ) if request_id == USER_PASSWORD_RESET: - return await handle_password_reset_api(self.api_implementation, api_options) + return await handle_password_reset_api( + self.api_implementation, api_options, user_context + ) return None diff --git a/supertokens_python/recipe/emailverification/api/email_verify.py b/supertokens_python/recipe/emailverification/api/email_verify.py index 1481db177..5493679c0 100644 --- a/supertokens_python/recipe/emailverification/api/email_verify.py +++ b/supertokens_python/recipe/emailverification/api/email_verify.py @@ -12,7 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. from __future__ import annotations - +from typing import Any, Dict from supertokens_python.exceptions import raise_bad_input_exception from supertokens_python.recipe.emailverification.interfaces import ( @@ -20,7 +20,6 @@ APIOptions, ) from supertokens_python.utils import ( - default_user_context, normalise_http_method, send_200_response, ) @@ -28,9 +27,10 @@ async def handle_email_verify_api( - api_implementation: APIInterface, api_options: APIOptions + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ): - user_context = default_user_context(api_options.request) if normalise_http_method(api_options.request.method()) == "post": if api_implementation.disable_email_verify_post: return None diff --git a/supertokens_python/recipe/emailverification/api/generate_email_verify_token.py b/supertokens_python/recipe/emailverification/api/generate_email_verify_token.py index d201904f8..a27431097 100644 --- a/supertokens_python/recipe/emailverification/api/generate_email_verify_token.py +++ b/supertokens_python/recipe/emailverification/api/generate_email_verify_token.py @@ -12,21 +12,23 @@ # License for the specific language governing permissions and limitations # under the License. from __future__ import annotations +from typing import Any, Dict from supertokens_python.recipe.emailverification.interfaces import ( APIInterface, APIOptions, ) -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response from supertokens_python.recipe.session.asyncio import get_session async def handle_generate_email_verify_token_api( - api_implementation: APIInterface, api_options: APIOptions + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ): if api_implementation.disable_generate_email_verify_token_post: return None - user_context = default_user_context(api_options.request) session = await get_session( api_options.request, override_global_claim_validators=lambda _, __, ___: [], diff --git a/supertokens_python/recipe/emailverification/recipe.py b/supertokens_python/recipe/emailverification/recipe.py index ccfb780c3..947d52762 100644 --- a/supertokens_python/recipe/emailverification/recipe.py +++ b/supertokens_python/recipe/emailverification/recipe.py @@ -183,11 +183,10 @@ async def handle_api_request( ) if request_id == USER_EMAIL_VERIFY_TOKEN: return await handle_generate_email_verify_token_api( - self.api_implementation, api_options + self.api_implementation, api_options, user_context ) return await handle_email_verify_api( - self.api_implementation, - api_options, + self.api_implementation, api_options, user_context ) async def handle_error( diff --git a/supertokens_python/recipe/jwt/api/jwks_get.py b/supertokens_python/recipe/jwt/api/jwks_get.py index 40d996426..1ba325d09 100644 --- a/supertokens_python/recipe/jwt/api/jwks_get.py +++ b/supertokens_python/recipe/jwt/api/jwks_get.py @@ -11,16 +11,21 @@ # 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 Any, Dict from supertokens_python.recipe.jwt.interfaces import APIInterface, APIOptions -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response from ..interfaces import JWKSGetResponse -async def jwks_get(api_implementation: APIInterface, api_options: APIOptions): +async def jwks_get( + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], +): if api_implementation.disable_jwks_get: return None - user_context = default_user_context(api_options.request) result = await api_implementation.jwks_get(api_options, user_context) diff --git a/supertokens_python/recipe/jwt/recipe.py b/supertokens_python/recipe/jwt/recipe.py index d04bb6440..c70bd049b 100644 --- a/supertokens_python/recipe/jwt/recipe.py +++ b/supertokens_python/recipe/jwt/recipe.py @@ -96,7 +96,7 @@ async def handle_api_request( ) if request_id == GET_JWKS_API: - return await jwks_get(self.api_implementation, options) + return await jwks_get(self.api_implementation, options, user_context) return None diff --git a/supertokens_python/recipe/multitenancy/api/login_methods.py b/supertokens_python/recipe/multitenancy/api/login_methods.py index fccd0a5ba..63b20d040 100644 --- a/supertokens_python/recipe/multitenancy/api/login_methods.py +++ b/supertokens_python/recipe/multitenancy/api/login_methods.py @@ -12,17 +12,19 @@ # License for the specific language governing permissions and limitations # under the License. from __future__ import annotations - +from typing import Any, Dict from supertokens_python.recipe.multitenancy.interfaces import ( APIInterface, APIOptions, ) -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response async def handle_login_methods_api( - api_implementation: APIInterface, api_options: APIOptions + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ): if api_implementation.disable_login_methods_get: return None @@ -30,11 +32,6 @@ async def handle_login_methods_api( tenant_id = api_options.request.get_query_param("tenantId") client_type = api_options.request.get_query_param("clientType") - user_context = default_user_context(api_options.request) - - mt_recipe = api_options.recipe_implementation - tenant_id = await mt_recipe.get_tenant_id(tenant_id, user_context) - result = await api_implementation.login_methods_get( tenant_id, client_type, api_options, user_context ) diff --git a/supertokens_python/recipe/multitenancy/interfaces.py b/supertokens_python/recipe/multitenancy/interfaces.py index 10004e76c..81d50a982 100644 --- a/supertokens_python/recipe/multitenancy/interfaces.py +++ b/supertokens_python/recipe/multitenancy/interfaces.py @@ -158,8 +158,8 @@ def __init__(self): @abstractmethod async def get_tenant_id( - self, tenant_id_from_frontend: Optional[str], user_context: Dict[str, Any] - ) -> Optional[str]: + self, tenant_id_from_frontend: str, user_context: Dict[str, Any] + ) -> str: pass @abstractmethod diff --git a/supertokens_python/recipe/multitenancy/recipe.py b/supertokens_python/recipe/multitenancy/recipe.py index 5f9768f5f..01d197fed 100644 --- a/supertokens_python/recipe/multitenancy/recipe.py +++ b/supertokens_python/recipe/multitenancy/recipe.py @@ -138,6 +138,7 @@ async def handle_api_request( return await handle_login_methods_api( self.api_implementation, api_options, + user_context, ) async def handle_error( diff --git a/supertokens_python/recipe/multitenancy/recipe_implementation.py b/supertokens_python/recipe/multitenancy/recipe_implementation.py index c997c6141..022f20e5f 100644 --- a/supertokens_python/recipe/multitenancy/recipe_implementation.py +++ b/supertokens_python/recipe/multitenancy/recipe_implementation.py @@ -125,8 +125,8 @@ def __init__(self, querier: Querier, config: MultitenancyConfig): self.config = config async def get_tenant_id( - self, tenant_id_from_frontend: Optional[str], user_context: Dict[str, Any] - ) -> Optional[str]: + self, tenant_id_from_frontend: str, user_context: Dict[str, Any] + ) -> str: return tenant_id_from_frontend async def create_or_update_tenant( diff --git a/supertokens_python/recipe/openid/api/open_id_discovery_configuration_get.py b/supertokens_python/recipe/openid/api/open_id_discovery_configuration_get.py index ce55c0bd8..c14353f31 100644 --- a/supertokens_python/recipe/openid/api/open_id_discovery_configuration_get.py +++ b/supertokens_python/recipe/openid/api/open_id_discovery_configuration_get.py @@ -11,20 +11,22 @@ # 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 Any, Dict from supertokens_python.recipe.openid.interfaces import APIInterface, APIOptions -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response from ..interfaces import OpenIdDiscoveryConfigurationGetResponse async def open_id_discovery_configuration_get( - api_implementation: APIInterface, api_options: APIOptions + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ): if api_implementation.disable_open_id_discovery_configuration_get: return None - user_context = default_user_context(api_options.request) - result = await api_implementation.open_id_discovery_configuration_get( api_options, user_context ) diff --git a/supertokens_python/recipe/openid/recipe.py b/supertokens_python/recipe/openid/recipe.py index 76b98d102..b3abbc60b 100644 --- a/supertokens_python/recipe/openid/recipe.py +++ b/supertokens_python/recipe/openid/recipe.py @@ -106,7 +106,7 @@ async def handle_api_request( if request_id == GET_DISCOVERY_CONFIG_URL: return await open_id_discovery_configuration_get( - self.api_implementation, options + self.api_implementation, options, user_context ) return await self.jwt_recipe.handle_api_request( request_id, tenant_id, request, path, method, response, user_context diff --git a/supertokens_python/recipe/passwordless/api/consume_code.py b/supertokens_python/recipe/passwordless/api/consume_code.py index 615f38b70..852174063 100644 --- a/supertokens_python/recipe/passwordless/api/consume_code.py +++ b/supertokens_python/recipe/passwordless/api/consume_code.py @@ -11,12 +11,17 @@ # 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 typing import Any, Dict from supertokens_python.exceptions import raise_bad_input_exception from supertokens_python.recipe.passwordless.interfaces import APIInterface, APIOptions -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response -async def consume_code(api_implementation: APIInterface, api_options: APIOptions): +async def consume_code( + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], +): if api_implementation.disable_consume_code_post: return None @@ -49,7 +54,6 @@ async def consume_code(api_implementation: APIInterface, api_options: APIOptions ) pre_auth_session_id = body["preAuthSessionId"] - user_context = default_user_context(api_options.request) result = await api_implementation.consume_code_post( pre_auth_session_id, diff --git a/supertokens_python/recipe/passwordless/api/create_code.py b/supertokens_python/recipe/passwordless/api/create_code.py index 7f8c08309..669a79fee 100644 --- a/supertokens_python/recipe/passwordless/api/create_code.py +++ b/supertokens_python/recipe/passwordless/api/create_code.py @@ -11,7 +11,7 @@ # 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 typing import Union +from typing import Union, Any, Dict import phonenumbers # type: ignore from phonenumbers import format_number, parse # type: ignore @@ -23,10 +23,14 @@ ContactPhoneOnlyConfig, ) from supertokens_python.types import GeneralErrorResponse -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response -async def create_code(api_implementation: APIInterface, api_options: APIOptions): +async def create_code( + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], +): if api_implementation.disable_create_code_post: return None @@ -100,8 +104,6 @@ async def create_code(api_implementation: APIInterface, api_options: APIOptions) except Exception: phone_number = phone_number.strip() - user_context = default_user_context(api_options.request) - result = await api_implementation.create_code_post( email=email, phone_number=phone_number, diff --git a/supertokens_python/recipe/passwordless/api/email_exists.py b/supertokens_python/recipe/passwordless/api/email_exists.py index 4958b4448..5c0e8ef94 100644 --- a/supertokens_python/recipe/passwordless/api/email_exists.py +++ b/supertokens_python/recipe/passwordless/api/email_exists.py @@ -11,12 +11,18 @@ # 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 Any, Dict from supertokens_python.exceptions import raise_bad_input_exception from supertokens_python.recipe.passwordless.interfaces import APIInterface, APIOptions -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response -async def email_exists(api_implementation: APIInterface, api_options: APIOptions): +async def email_exists( + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], +): if api_implementation.disable_email_exists_get: return None @@ -24,7 +30,5 @@ async def email_exists(api_implementation: APIInterface, api_options: APIOptions if email is None: raise_bad_input_exception("Please provide the email as a GET param") - user_context = default_user_context(api_options.request) - result = await api_implementation.email_exists_get(email, api_options, user_context) return send_200_response(result.to_json(), api_options.response) diff --git a/supertokens_python/recipe/passwordless/api/phone_number_exists.py b/supertokens_python/recipe/passwordless/api/phone_number_exists.py index a815b3204..b26a485f8 100644 --- a/supertokens_python/recipe/passwordless/api/phone_number_exists.py +++ b/supertokens_python/recipe/passwordless/api/phone_number_exists.py @@ -11,13 +11,16 @@ # 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 typing import Any, Dict from supertokens_python.exceptions import raise_bad_input_exception from supertokens_python.recipe.passwordless.interfaces import APIInterface, APIOptions -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response async def phone_number_exists( - api_implementation: APIInterface, api_options: APIOptions + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ): if api_implementation.disable_phone_number_exists_get: return None @@ -26,8 +29,6 @@ async def phone_number_exists( if phone_number is None: raise_bad_input_exception("Please provide the phoneNumber as a GET param") - user_context = default_user_context(api_options.request) - result = await api_implementation.phone_number_exists_get( phone_number, api_options, user_context ) diff --git a/supertokens_python/recipe/passwordless/api/resend_code.py b/supertokens_python/recipe/passwordless/api/resend_code.py index 5bf4c6470..9a232ca92 100644 --- a/supertokens_python/recipe/passwordless/api/resend_code.py +++ b/supertokens_python/recipe/passwordless/api/resend_code.py @@ -11,12 +11,17 @@ # 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 typing import Any, Dict from supertokens_python.exceptions import raise_bad_input_exception from supertokens_python.recipe.passwordless.interfaces import APIInterface, APIOptions -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response -async def resend_code(api_implementation: APIInterface, api_options: APIOptions): +async def resend_code( + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], +): if api_implementation.disable_resend_code_post: return None body = await api_options.request.json() @@ -32,7 +37,6 @@ async def resend_code(api_implementation: APIInterface, api_options: APIOptions) pre_auth_session_id = body["preAuthSessionId"] device_id = body["deviceId"] - user_context = default_user_context(api_options.request) result = await api_implementation.resend_code_post( device_id, pre_auth_session_id, api_options, user_context diff --git a/supertokens_python/recipe/passwordless/recipe.py b/supertokens_python/recipe/passwordless/recipe.py index 3997dbedb..fc6620925 100644 --- a/supertokens_python/recipe/passwordless/recipe.py +++ b/supertokens_python/recipe/passwordless/recipe.py @@ -203,14 +203,16 @@ async def handle_api_request( self.sms_delivery, ) if request_id == CONSUME_CODE_API: - return await consume_code(self.api_implementation, options) + return await consume_code(self.api_implementation, options, user_context) if request_id == CREATE_CODE_API: - return await create_code(self.api_implementation, options) + return await create_code(self.api_implementation, options, user_context) if request_id == DOES_EMAIL_EXIST_API: - return await email_exists(self.api_implementation, options) + return await email_exists(self.api_implementation, options, user_context) if request_id == DOES_PHONE_NUMBER_EXIST_API: - return await phone_number_exists(self.api_implementation, options) - return await resend_code(self.api_implementation, options) + return await phone_number_exists( + self.api_implementation, options, user_context + ) + return await resend_code(self.api_implementation, options, user_context) async def handle_error( self, request: BaseRequest, err: SuperTokensError, response: BaseResponse diff --git a/supertokens_python/recipe/session/api/refresh.py b/supertokens_python/recipe/session/api/refresh.py index c45d142a0..ac986d5a6 100644 --- a/supertokens_python/recipe/session/api/refresh.py +++ b/supertokens_python/recipe/session/api/refresh.py @@ -13,21 +13,24 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any, Dict if TYPE_CHECKING: from supertokens_python.recipe.session.interfaces import APIInterface, APIOptions -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response -async def handle_refresh_api(api_implementation: APIInterface, api_options: APIOptions): +async def handle_refresh_api( + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], +): if ( api_implementation.disable_refresh_post or api_implementation.refresh_post is None ): return None - user_context = default_user_context(api_options.request) await api_implementation.refresh_post(api_options, user_context) if api_options.response is None: diff --git a/supertokens_python/recipe/session/api/signout.py b/supertokens_python/recipe/session/api/signout.py index 3769eadac..32a9a1afa 100644 --- a/supertokens_python/recipe/session/api/signout.py +++ b/supertokens_python/recipe/session/api/signout.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any, Dict from supertokens_python.recipe.session.session_request_functions import ( get_session_from_request, @@ -25,18 +25,20 @@ APIOptions, ) -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response -async def handle_signout_api(api_implementation: APIInterface, api_options: APIOptions): +async def handle_signout_api( + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], +): if ( api_implementation.disable_signout_post or api_implementation.signout_post is None ): return None - user_context = default_user_context(api_options.request) - session = await get_session_from_request( api_options.request, api_options.config, diff --git a/supertokens_python/recipe/session/framework/django/asyncio/__init__.py b/supertokens_python/recipe/session/framework/django/asyncio/__init__.py index d071f9a60..d98bf9beb 100644 --- a/supertokens_python/recipe/session/framework/django/asyncio/__init__.py +++ b/supertokens_python/recipe/session/framework/django/asyncio/__init__.py @@ -20,6 +20,7 @@ from supertokens_python.framework.django.django_response import DjangoResponse from supertokens_python.recipe.session import SessionContainer, SessionRecipe from supertokens_python.recipe.session.interfaces import SessionClaimValidator +from supertokens_python.utils import default_user_context from supertokens_python.types import MaybeAwaitable _T = TypeVar("_T", bound=Callable[..., Any]) @@ -37,18 +38,21 @@ def verify_session( ] = None, user_context: Union[None, Dict[str, Any]] = None, ) -> Callable[[_T], _T]: - if user_context is None: - user_context = {} + _ = user_context def session_verify(f: _T) -> _T: from django.http import HttpRequest @wraps(f) async def wrapped_function(request: HttpRequest, *args: Any, **kwargs: Any): + nonlocal user_context from django.http import JsonResponse try: baseRequest = DjangoRequest(request) + if user_context is None: + user_context = default_user_context(baseRequest) + recipe = SessionRecipe.get_instance() session = await recipe.verify_session( baseRequest, diff --git a/supertokens_python/recipe/session/framework/django/syncio/__init__.py b/supertokens_python/recipe/session/framework/django/syncio/__init__.py index c263cae53..13715178a 100644 --- a/supertokens_python/recipe/session/framework/django/syncio/__init__.py +++ b/supertokens_python/recipe/session/framework/django/syncio/__init__.py @@ -21,6 +21,7 @@ from supertokens_python.framework.django.django_response import DjangoResponse from supertokens_python.recipe.session import SessionRecipe, SessionContainer from supertokens_python.recipe.session.interfaces import SessionClaimValidator +from supertokens_python.utils import default_user_context from supertokens_python.types import MaybeAwaitable _T = TypeVar("_T", bound=Callable[..., Any]) @@ -38,18 +39,21 @@ def verify_session( ] = None, user_context: Union[None, Dict[str, Any]] = None, ) -> Callable[[_T], _T]: - if user_context is None: - user_context = {} + _ = user_context def session_verify(f: _T) -> _T: from django.http import HttpRequest @wraps(f) def wrapped_function(request: HttpRequest, *args: Any, **kwargs: Any): + nonlocal user_context from django.http import JsonResponse try: baseRequest = DjangoRequest(request) + if user_context is None: + user_context = default_user_context(baseRequest) + recipe = SessionRecipe.get_instance() session = sync( recipe.verify_session( diff --git a/supertokens_python/recipe/session/framework/fastapi/__init__.py b/supertokens_python/recipe/session/framework/fastapi/__init__.py index 2329f9dfe..c561d87f9 100644 --- a/supertokens_python/recipe/session/framework/fastapi/__init__.py +++ b/supertokens_python/recipe/session/framework/fastapi/__init__.py @@ -18,6 +18,7 @@ from supertokens_python.types import MaybeAwaitable from ...interfaces import SessionContainer, SessionClaimValidator +from supertokens_python.utils import default_user_context def verify_session( @@ -32,12 +33,15 @@ def verify_session( ] = None, user_context: Union[None, Dict[str, Any]] = None, ) -> Callable[..., Coroutine[Any, Any, Union[SessionContainer, None]]]: - if user_context is None: - user_context = {} + _ = user_context from fastapi import Request async def func(request: Request) -> Union[SessionContainer, None]: + nonlocal user_context baseRequest = FastApiRequest(request) + if user_context is None: + user_context = default_user_context(baseRequest) + recipe = SessionRecipe.get_instance() session = await recipe.verify_session( baseRequest, diff --git a/supertokens_python/recipe/session/framework/flask/__init__.py b/supertokens_python/recipe/session/framework/flask/__init__.py index 2b51e0d8e..bc9211d91 100644 --- a/supertokens_python/recipe/session/framework/flask/__init__.py +++ b/supertokens_python/recipe/session/framework/flask/__init__.py @@ -18,6 +18,7 @@ from supertokens_python.framework.flask.flask_request import FlaskRequest from supertokens_python.recipe.session import SessionRecipe, SessionContainer from supertokens_python.recipe.session.interfaces import SessionClaimValidator +from supertokens_python.utils import default_user_context from supertokens_python.types import MaybeAwaitable _T = TypeVar("_T", bound=Callable[..., Any]) @@ -35,15 +36,18 @@ def verify_session( ] = None, user_context: Union[None, Dict[str, Any]] = None, ) -> Callable[[_T], _T]: - if user_context is None: - user_context = {} + _ = user_context def session_verify(f: _T) -> _T: @wraps(f) def wrapped_function(*args: Any, **kwargs: Any): + nonlocal user_context from flask import make_response, request baseRequest = FlaskRequest(request) + if user_context is None: + user_context = default_user_context(baseRequest) + recipe = SessionRecipe.get_instance() session = sync( recipe.verify_session( diff --git a/supertokens_python/recipe/session/interfaces.py b/supertokens_python/recipe/session/interfaces.py index 407799930..e28d031a3 100644 --- a/supertokens_python/recipe/session/interfaces.py +++ b/supertokens_python/recipe/session/interfaces.py @@ -628,7 +628,10 @@ def get_value_from_payload( """Gets the value of the claim stored in the payload""" async def build( - self, user_id: str, tenant_id: str, user_context: Optional[Dict[str, Any]] = None + self, + user_id: str, + tenant_id: str, + user_context: Optional[Dict[str, Any]] = None, ) -> JSONObject: if user_context is None: user_context = {} diff --git a/supertokens_python/recipe/session/recipe.py b/supertokens_python/recipe/session/recipe.py index 02488ff27..3fe805c38 100644 --- a/supertokens_python/recipe/session/recipe.py +++ b/supertokens_python/recipe/session/recipe.py @@ -19,10 +19,6 @@ from supertokens_python.framework.response import BaseResponse from typing_extensions import Literal -from supertokens_python.utils import ( - default_user_context, -) - from .cookie_and_header import ( get_cors_allowed_headers, ) @@ -204,6 +200,7 @@ async def handle_api_request( self.config, self.recipe_implementation, ), + user_context, ) if request_id == SIGNOUT: return await handle_signout_api( @@ -215,6 +212,7 @@ async def handle_api_request( self.config, self.recipe_implementation, ), + user_context, ) return await self.openid_recipe.handle_api_request( request_id, tenant_id, request, path, method, response, user_context @@ -369,5 +367,5 @@ async def verify_session( session_required, check_database, override_global_claim_validators, - user_context=default_user_context(request), + user_context, ) diff --git a/supertokens_python/recipe/thirdparty/api/apple_redirect.py b/supertokens_python/recipe/thirdparty/api/apple_redirect.py index e6733087e..a5fc86f09 100644 --- a/supertokens_python/recipe/thirdparty/api/apple_redirect.py +++ b/supertokens_python/recipe/thirdparty/api/apple_redirect.py @@ -13,24 +13,22 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any, Dict if TYPE_CHECKING: from supertokens_python.recipe.thirdparty.interfaces import APIInterface, APIOptions -from supertokens_python.utils import default_user_context - async def handle_apple_redirect_api( - api_implementation: APIInterface, api_options: APIOptions + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ): if api_implementation.disable_apple_redirect_handler_post: return None body = await api_options.request.form_data() - user_context = default_user_context(api_options.request) - # this will redirect the user... await api_implementation.apple_redirect_handler_post( body, api_options, user_context diff --git a/supertokens_python/recipe/thirdparty/api/authorisation_url.py b/supertokens_python/recipe/thirdparty/api/authorisation_url.py index bd82c5fb5..001c2c194 100644 --- a/supertokens_python/recipe/thirdparty/api/authorisation_url.py +++ b/supertokens_python/recipe/thirdparty/api/authorisation_url.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any, Dict from supertokens_python.recipe.multitenancy.constants import DEFAULT_TENANT_ID from supertokens_python.recipe.multitenancy.recipe import MultitenancyRecipe from supertokens_python.recipe.multitenancy.exceptions import ( @@ -25,11 +25,13 @@ from supertokens_python.recipe.thirdparty.interfaces import APIOptions, APIInterface from supertokens_python.exceptions import raise_bad_input_exception -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response async def handle_authorisation_url_api( - api_implementation: APIInterface, api_options: APIOptions + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ): if api_implementation.disable_authorisation_url_get: return None @@ -49,11 +51,9 @@ async def handle_authorisation_url_api( "Please provide the redirectURIOnProviderDashboard as a GET param" ) - user_context = default_user_context(api_options.request) - mt_recipe = MultitenancyRecipe.get_instance() tenant_id = await mt_recipe.recipe_implementation.get_tenant_id( - tenant_id, user_context + tenant_id if tenant_id is not None else DEFAULT_TENANT_ID, user_context ) provider_response = await api_options.recipe_implementation.get_provider( diff --git a/supertokens_python/recipe/thirdparty/api/signinup.py b/supertokens_python/recipe/thirdparty/api/signinup.py index a48e808f7..86e0d8d0d 100644 --- a/supertokens_python/recipe/thirdparty/api/signinup.py +++ b/supertokens_python/recipe/thirdparty/api/signinup.py @@ -13,7 +13,7 @@ # under the License. from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any, Dict from supertokens_python.recipe.multitenancy.constants import DEFAULT_TENANT_ID from supertokens_python.recipe.multitenancy.exceptions import ( RecipeDisabledForTenantError, @@ -25,11 +25,13 @@ from supertokens_python.recipe.thirdparty.interfaces import APIOptions, APIInterface from supertokens_python.exceptions import raise_bad_input_exception -from supertokens_python.utils import default_user_context, send_200_response +from supertokens_python.utils import send_200_response async def handle_sign_in_up_api( - api_implementation: APIInterface, api_options: APIOptions + api_implementation: APIInterface, + api_options: APIOptions, + user_context: Dict[str, Any], ): if api_implementation.disable_sign_in_up_post: return None @@ -60,8 +62,6 @@ async def handle_sign_in_up_api( "Please provide one of redirectURIInfo or oAuthTokens in the request body" ) - user_context = default_user_context(api_options.request) - mt_recipe = MultitenancyRecipe.get_instance() tenant_id = await mt_recipe.recipe_implementation.get_tenant_id( tenant_id, user_context diff --git a/supertokens_python/recipe/thirdparty/recipe.py b/supertokens_python/recipe/thirdparty/recipe.py index 5d03faae3..f3032d131 100644 --- a/supertokens_python/recipe/thirdparty/recipe.py +++ b/supertokens_python/recipe/thirdparty/recipe.py @@ -139,13 +139,17 @@ async def handle_api_request( ) if request_id == SIGNINUP: - return await handle_sign_in_up_api(self.api_implementation, api_options) + return await handle_sign_in_up_api( + self.api_implementation, api_options, user_context + ) if request_id == AUTHORISATIONURL: return await handle_authorisation_url_api( - self.api_implementation, api_options + self.api_implementation, api_options, user_context ) if request_id == APPLE_REDIRECT_HANDLER: - return await handle_apple_redirect_api(self.api_implementation, api_options) + return await handle_apple_redirect_api( + self.api_implementation, api_options, user_context + ) return None diff --git a/supertokens_python/recipe/thirdpartyemailpassword/recipe.py b/supertokens_python/recipe/thirdpartyemailpassword/recipe.py index 3cb1b8b0a..d2bd333f2 100644 --- a/supertokens_python/recipe/thirdpartyemailpassword/recipe.py +++ b/supertokens_python/recipe/thirdpartyemailpassword/recipe.py @@ -218,7 +218,7 @@ async def handle_api_request( user_context: Dict[str, Any], ): if ( - self.email_password_recipe.return_api_id_if_can_handle_request( + await self.email_password_recipe.return_api_id_if_can_handle_request( path, method, user_context ) is not None @@ -228,7 +228,7 @@ async def handle_api_request( ) if ( self.third_party_recipe is not None - and self.third_party_recipe.return_api_id_if_can_handle_request( + and await self.third_party_recipe.return_api_id_if_can_handle_request( path, method, user_context ) is not None diff --git a/supertokens_python/recipe/thirdpartypasswordless/recipe.py b/supertokens_python/recipe/thirdpartypasswordless/recipe.py index b6828cf58..77912d4a4 100644 --- a/supertokens_python/recipe/thirdpartypasswordless/recipe.py +++ b/supertokens_python/recipe/thirdpartypasswordless/recipe.py @@ -232,7 +232,7 @@ async def handle_api_request( user_context: Dict[str, Any], ): if ( - self.passwordless_recipe.return_api_id_if_can_handle_request( + await self.passwordless_recipe.return_api_id_if_can_handle_request( path, method, user_context ) is not None @@ -242,7 +242,7 @@ async def handle_api_request( ) if ( self.third_party_recipe is not None - and self.third_party_recipe.return_api_id_if_can_handle_request( + and await self.third_party_recipe.return_api_id_if_can_handle_request( path, method, user_context ) is not None diff --git a/supertokens_python/recipe_module.py b/supertokens_python/recipe_module.py index 5113b681d..c69ead42c 100644 --- a/supertokens_python/recipe_module.py +++ b/supertokens_python/recipe_module.py @@ -30,6 +30,8 @@ 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: Optional[str]): @@ -48,11 +50,9 @@ def get_recipe_id(self): def get_app_info(self): return self.app_info - def return_api_id_if_can_handle_request( + async def return_api_id_if_can_handle_request( self, path: NormalisedURLPath, method: str, user_context: Dict[str, Any] ) -> Union[ApiIdWithTenantId, None]: - _ = user_context - from supertokens_python.recipe.multitenancy.constants import DEFAULT_TENANT_ID apis_handled = self.get_apis_handled() @@ -76,17 +76,29 @@ def return_api_id_if_can_handle_request( tenant_id = match_group_1 remaining_path = NormalisedURLPath(match_group_2) + mt_recipe = MultitenancyRecipe.get_instance() + for current_api in apis_handled: if not current_api.disabled and current_api.method == method: if self.app_info.api_base_path.append( current_api.path_without_api_base_path ).equals(path): - return ApiIdWithTenantId(current_api.request_id, DEFAULT_TENANT_ID) + final_tenant_id = ( + await mt_recipe.recipe_implementation.get_tenant_id( + DEFAULT_TENANT_ID, user_context + ) + ) + return ApiIdWithTenantId(current_api.request_id, final_tenant_id) if remaining_path is not None and self.app_info.api_base_path.append( current_api.path_without_api_base_path ).equals(self.app_info.api_base_path.append(remaining_path)): - return ApiIdWithTenantId(current_api.request_id, tenant_id) + final_tenant_id = ( + await mt_recipe.recipe_implementation.get_tenant_id( + tenant_id or DEFAULT_TENANT_ID, user_context + ) + ) + return ApiIdWithTenantId(current_api.request_id, final_tenant_id) return None diff --git a/supertokens_python/supertokens.py b/supertokens_python/supertokens.py index 489bad308..5c051eb1a 100644 --- a/supertokens_python/supertokens.py +++ b/supertokens_python/supertokens.py @@ -501,8 +501,10 @@ async def middleware( # pylint: disable=no-self-use matched_recipe = recipe break if matched_recipe is not None: - api_and_tenant_id = matched_recipe.return_api_id_if_can_handle_request( - path, method, user_context + api_and_tenant_id = ( + await matched_recipe.return_api_id_if_can_handle_request( + path, method, user_context + ) ) else: for recipe in Supertokens.get_instance().recipe_modules: @@ -510,7 +512,7 @@ async def middleware( # pylint: disable=no-self-use "middleware: Checking recipe ID for match: %s", recipe.get_recipe_id(), ) - api_and_tenant_id = recipe.return_api_id_if_can_handle_request( + api_and_tenant_id = await recipe.return_api_id_if_can_handle_request( path, method, user_context ) if api_and_tenant_id is not None: