Skip to content

Commit fec9094

Browse files
Merge pull request #376 from supertokens/fix/emailpassword-mt
fix: Add multitenancy features to emailpassword recipe
2 parents 72b54e0 + d294501 commit fec9094

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+500
-192
lines changed

supertokens_python/recipe/dashboard/api/userdetails/user_password_put.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,13 @@ async def handle_user_password_put(
7272
async def reset_password(
7373
form_fields: List[NormalisedFormField],
7474
create_reset_password_token: Callable[
75-
[str, Dict[str, Any]],
75+
[str, str, Dict[str, Any]],
7676
Awaitable[
7777
Union[CreateResetPasswordOkResult, CreateResetPasswordWrongUserIdError]
7878
],
7979
],
8080
reset_password_using_token: Callable[
81-
[str, str, Dict[str, Any]],
81+
[str, str, str, Dict[str, Any]],
8282
Awaitable[
8383
Union[
8484
ResetPasswordUsingTokenOkResult,
@@ -100,15 +100,18 @@ async def reset_password(
100100
password_validation_error
101101
)
102102

103-
password_reset_token = await create_reset_password_token(user_id, user_context)
103+
# TODO: Pass tenant id
104+
password_reset_token = await create_reset_password_token(
105+
"pass-tenant-id", user_id, user_context
106+
)
104107

105108
if isinstance(password_reset_token, CreateResetPasswordWrongUserIdError):
106109
# Techincally it can but its an edge case so we assume that it wont
107110
# UNKNOWN_USER_ID_ERROR
108111
raise Exception("Should never come here")
109112

110113
password_reset_response = await reset_password_using_token(
111-
password_reset_token.token, new_password, user_context
114+
"pass-tenant-id", password_reset_token.token, new_password, user_context
112115
)
113116

114117
if isinstance(

supertokens_python/recipe/emailpassword/api/email_exists.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727

2828
async def handle_email_exists_api(
29+
tenant_id: str,
2930
api_implementation: APIInterface,
3031
api_options: APIOptions,
3132
user_context: Dict[str, Any],
@@ -37,6 +38,6 @@ async def handle_email_exists_api(
3738
raise_bad_input_exception("Please provide the email as a GET param")
3839

3940
response = await api_implementation.email_exists_get(
40-
email, api_options, user_context
41+
email, tenant_id, api_options, user_context
4142
)
4243
return send_200_response(response.to_json(), api_options.response)

supertokens_python/recipe/emailpassword/api/generate_password_reset_token.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929

3030
async def handle_generate_password_reset_token_api(
31+
tenant_id: str,
3132
api_implementation: APIInterface,
3233
api_options: APIOptions,
3334
user_context: Dict[str, Any],
@@ -44,6 +45,6 @@ async def handle_generate_password_reset_token_api(
4445
)
4546

4647
response = await api_implementation.generate_password_reset_token_post(
47-
form_fields, api_options, user_context
48+
form_fields, tenant_id, api_options, user_context
4849
)
4950
return send_200_response(response.to_json(), api_options.response)

supertokens_python/recipe/emailpassword/api/implementation.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,21 @@
5151

5252
class APIImplementation(APIInterface):
5353
async def email_exists_get(
54-
self, email: str, api_options: APIOptions, user_context: Dict[str, Any]
54+
self,
55+
email: str,
56+
tenant_id: str,
57+
api_options: APIOptions,
58+
user_context: Dict[str, Any],
5559
) -> Union[EmailExistsGetOkResult, GeneralErrorResponse]:
5660
user = await api_options.recipe_implementation.get_user_by_email(
57-
email, user_context
61+
email, tenant_id, user_context
5862
)
5963
return EmailExistsGetOkResult(user is not None)
6064

6165
async def generate_password_reset_token_post(
6266
self,
6367
form_fields: List[FormField],
68+
tenant_id: str,
6469
api_options: APIOptions,
6570
user_context: Dict[str, Any],
6671
) -> Union[GeneratePasswordResetTokenPostOkResult, GeneralErrorResponse]:
@@ -72,15 +77,15 @@ async def generate_password_reset_token_post(
7277
email = emailFormField.value
7378

7479
user = await api_options.recipe_implementation.get_user_by_email(
75-
email, user_context
80+
email, tenant_id, user_context
7681
)
7782

7883
if user is None:
7984
return GeneratePasswordResetTokenPostOkResult()
8085

8186
token_result = (
8287
await api_options.recipe_implementation.create_reset_password_token(
83-
user.user_id, user_context
88+
user.user_id, tenant_id, user_context
8489
)
8590
)
8691

@@ -98,6 +103,8 @@ async def generate_password_reset_token_post(
98103
+ token
99104
+ "&rid="
100105
+ api_options.recipe_id
106+
+ "&tenantId="
107+
+ tenant_id
101108
)
102109

103110
log_debug_message("Sending password reset email to %s", email)
@@ -115,6 +122,7 @@ async def password_reset_post(
115122
self,
116123
form_fields: List[FormField],
117124
token: str,
125+
tenant_id: str,
118126
api_options: APIOptions,
119127
user_context: Dict[str, Any],
120128
) -> Union[
@@ -130,7 +138,7 @@ async def password_reset_post(
130138
new_password = new_password_for_field.value
131139

132140
result = await api_options.recipe_implementation.reset_password_using_token(
133-
token, new_password, user_context
141+
token, new_password, tenant_id, user_context
134142
)
135143

136144
if isinstance(result, ResetPasswordUsingTokenInvalidTokenError):
@@ -141,6 +149,7 @@ async def password_reset_post(
141149
async def sign_in_post(
142150
self,
143151
form_fields: List[FormField],
152+
tenant_id: str,
144153
api_options: APIOptions,
145154
user_context: Dict[str, Any],
146155
) -> Union[
@@ -161,7 +170,7 @@ async def sign_in_post(
161170
email = email_form_field.value
162171

163172
result = await api_options.recipe_implementation.sign_in(
164-
email, password, user_context
173+
email, password, tenant_id, user_context
165174
)
166175

167176
if isinstance(result, SignInWrongCredentialsError):
@@ -180,6 +189,7 @@ async def sign_in_post(
180189
async def sign_up_post(
181190
self,
182191
form_fields: List[FormField],
192+
tenant_id: str,
183193
api_options: APIOptions,
184194
user_context: Dict[str, Any],
185195
) -> Union[
@@ -200,7 +210,7 @@ async def sign_up_post(
200210
email = email_form_field.value
201211

202212
result = await api_options.recipe_implementation.sign_up(
203-
email, password, user_context
213+
email, password, tenant_id, user_context
204214
)
205215

206216
if isinstance(result, SignUpEmailAlreadyExistsError):

supertokens_python/recipe/emailpassword/api/password_reset.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929

3030
async def handle_password_reset_api(
31+
tenant_id: str,
3132
api_implementation: APIInterface,
3233
api_options: APIOptions,
3334
user_context: Dict[str, Any],
@@ -51,6 +52,6 @@ async def handle_password_reset_api(
5152
token = body["token"]
5253

5354
response = await api_implementation.password_reset_post(
54-
form_fields, token, api_options, user_context
55+
form_fields, token, tenant_id, api_options, user_context
5556
)
5657
return send_200_response(response.to_json(), api_options.response)

supertokens_python/recipe/emailpassword/api/signin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929

3030
async def handle_sign_in_api(
31+
tenant_id: str,
3132
api_implementation: APIInterface,
3233
api_options: APIOptions,
3334
user_context: Dict[str, Any],
@@ -43,7 +44,7 @@ async def handle_sign_in_api(
4344
)
4445

4546
response = await api_implementation.sign_in_post(
46-
form_fields, api_options, user_context
47+
form_fields, tenant_id, api_options, user_context
4748
)
4849

4950
return send_200_response(response.to_json(), api_options.response)

supertokens_python/recipe/emailpassword/api/signup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535

3636
async def handle_sign_up_api(
37+
tenant_id: str,
3738
api_implementation: APIInterface,
3839
api_options: APIOptions,
3940
user_context: Dict[str, Any],
@@ -49,7 +50,7 @@ async def handle_sign_up_api(
4950
)
5051

5152
response = await api_implementation.sign_up_post(
52-
form_fields, api_options, user_context
53+
form_fields, tenant_id, api_options, user_context
5354
)
5455

5556
if isinstance(response, SignUpPostOkResult):

supertokens_python/recipe/emailpassword/asyncio/__init__.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@
1111
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1212
# License for the specific language governing permissions and limitations
1313
# under the License.
14-
from typing import Any, Dict, Union
14+
from typing import Any, Dict, Union, Optional
1515

1616
from supertokens_python.recipe.emailpassword import EmailPasswordRecipe
1717

1818
from ..types import EmailTemplateVars, User
19+
from ...multitenancy.constants import DEFAULT_TENANT_ID
1920

2021

2122
async def update_email_or_password(
@@ -45,52 +46,65 @@ async def get_user_by_id(
4546

4647

4748
async def get_user_by_email(
48-
email: str, user_context: Union[None, Dict[str, Any]] = None
49+
tenant_id: Optional[str],
50+
email: str,
51+
user_context: Union[None, Dict[str, Any]] = None,
4952
) -> Union[User, None]:
5053
if user_context is None:
5154
user_context = {}
5255
return await EmailPasswordRecipe.get_instance().recipe_implementation.get_user_by_email(
53-
email, user_context
56+
email, tenant_id or DEFAULT_TENANT_ID, user_context
5457
)
5558

5659

5760
async def create_reset_password_token(
58-
user_id: str, user_context: Union[None, Dict[str, Any]] = None
61+
tenant_id: Optional[str],
62+
user_id: str,
63+
user_context: Union[None, Dict[str, Any]] = None,
5964
):
6065
if user_context is None:
6166
user_context = {}
6267
return await EmailPasswordRecipe.get_instance().recipe_implementation.create_reset_password_token(
63-
user_id, user_context
68+
user_id, tenant_id or DEFAULT_TENANT_ID, user_context
6469
)
6570

6671

6772
async def reset_password_using_token(
68-
token: str, new_password: str, user_context: Union[None, Dict[str, Any]] = None
73+
tenant_id: Optional[str],
74+
token: str,
75+
new_password: str,
76+
user_context: Union[None, Dict[str, Any]] = None,
6977
):
7078
if user_context is None:
7179
user_context = {}
7280
return await EmailPasswordRecipe.get_instance().recipe_implementation.reset_password_using_token(
73-
token, new_password, user_context
81+
token, new_password, tenant_id or DEFAULT_TENANT_ID, user_context
7482
)
7583

7684

7785
async def sign_in(
78-
email: str, password: str, user_context: Union[None, Dict[str, Any]] = None
86+
tenant_id: Optional[str],
87+
email: str,
88+
password: str,
89+
user_context: Union[None, Dict[str, Any]] = None,
7990
):
8091
if user_context is None:
8192
user_context = {}
8293
return await EmailPasswordRecipe.get_instance().recipe_implementation.sign_in(
83-
email, password, user_context
94+
email, password, tenant_id or DEFAULT_TENANT_ID, user_context
8495
)
8596

8697

8798
async def sign_up(
88-
email: str, password: str, user_context: Union[None, Dict[str, Any]] = None
99+
tenant_id: Optional[str],
100+
email: str,
101+
password: str,
102+
user_context: Union[None, Dict[str, Any]] = None,
89103
):
90104
if user_context is None:
91105
user_context = {}
92106
return await EmailPasswordRecipe.get_instance().recipe_implementation.sign_up(
93-
email, password, user_context
107+
email, password, tenant_id or DEFAULT_TENANT_ID, user_context
94108
)
95109

96110

supertokens_python/recipe/emailpassword/interfaces.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,33 +97,37 @@ async def get_user_by_id(
9797

9898
@abstractmethod
9999
async def get_user_by_email(
100-
self, email: str, user_context: Dict[str, Any]
100+
self, email: str, tenant_id: str, user_context: Dict[str, Any]
101101
) -> Union[User, None]:
102102
pass
103103

104104
@abstractmethod
105105
async def create_reset_password_token(
106-
self, user_id: str, user_context: Dict[str, Any]
106+
self, user_id: str, tenant_id: str, user_context: Dict[str, Any]
107107
) -> Union[CreateResetPasswordOkResult, CreateResetPasswordWrongUserIdError]:
108108
pass
109109

110110
@abstractmethod
111111
async def reset_password_using_token(
112-
self, token: str, new_password: str, user_context: Dict[str, Any]
112+
self,
113+
token: str,
114+
new_password: str,
115+
tenant_id: str,
116+
user_context: Dict[str, Any],
113117
) -> Union[
114118
ResetPasswordUsingTokenOkResult, ResetPasswordUsingTokenInvalidTokenError
115119
]:
116120
pass
117121

118122
@abstractmethod
119123
async def sign_in(
120-
self, email: str, password: str, user_context: Dict[str, Any]
124+
self, email: str, password: str, tenant_id: str, user_context: Dict[str, Any]
121125
) -> Union[SignInOkResult, SignInWrongCredentialsError]:
122126
pass
123127

124128
@abstractmethod
125129
async def sign_up(
126-
self, email: str, password: str, user_context: Dict[str, Any]
130+
self, email: str, password: str, tenant_id: str, user_context: Dict[str, Any]
127131
) -> Union[SignUpOkResult, SignUpEmailAlreadyExistsError]:
128132
pass
129133

@@ -258,14 +262,19 @@ def __init__(self):
258262

259263
@abstractmethod
260264
async def email_exists_get(
261-
self, email: str, api_options: APIOptions, user_context: Dict[str, Any]
265+
self,
266+
email: str,
267+
tenant_id: str,
268+
api_options: APIOptions,
269+
user_context: Dict[str, Any],
262270
) -> Union[EmailExistsGetOkResult, GeneralErrorResponse]:
263271
pass
264272

265273
@abstractmethod
266274
async def generate_password_reset_token_post(
267275
self,
268276
form_fields: List[FormField],
277+
tenant_id: str,
269278
api_options: APIOptions,
270279
user_context: Dict[str, Any],
271280
) -> Union[GeneratePasswordResetTokenPostOkResult, GeneralErrorResponse]:
@@ -276,6 +285,7 @@ async def password_reset_post(
276285
self,
277286
form_fields: List[FormField],
278287
token: str,
288+
tenant_id: str,
279289
api_options: APIOptions,
280290
user_context: Dict[str, Any],
281291
) -> Union[
@@ -289,6 +299,7 @@ async def password_reset_post(
289299
async def sign_in_post(
290300
self,
291301
form_fields: List[FormField],
302+
tenant_id: str,
292303
api_options: APIOptions,
293304
user_context: Dict[str, Any],
294305
) -> Union[
@@ -300,6 +311,7 @@ async def sign_in_post(
300311
async def sign_up_post(
301312
self,
302313
form_fields: List[FormField],
314+
tenant_id: str,
303315
api_options: APIOptions,
304316
user_context: Dict[str, Any],
305317
) -> Union[

0 commit comments

Comments
 (0)