Skip to content

Commit 520a160

Browse files
committed
feat: Router changes to handle tenant id
1 parent 4e0d6a0 commit 520a160

File tree

23 files changed

+254
-51
lines changed

23 files changed

+254
-51
lines changed

supertokens_python/recipe/dashboard/recipe.py

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
# under the License.
1414
from __future__ import annotations
1515

16+
import re
1617
from os import environ
1718
from typing import TYPE_CHECKING, Awaitable, Callable, List, Optional, Union
1819

1920
from supertokens_python.normalised_url_path import NormalisedURLPath
20-
from supertokens_python.recipe_module import APIHandled, RecipeModule
21+
from supertokens_python.recipe_module import APIHandled, RecipeModule, ApiIdWithTenantId
2122

2223
from .api import (
2324
api_key_protector,
@@ -45,6 +46,7 @@
4546
from .exceptions import SuperTokensDashboardError
4647
from .interfaces import APIInterface, APIOptions
4748
from .recipe_implementation import RecipeImplementation
49+
from ..multitenancy.constants import DEFAULT_TENANT_ID
4850

4951
if TYPE_CHECKING:
5052
from supertokens_python.framework.request import BaseRequest
@@ -126,6 +128,7 @@ def get_apis_handled(self) -> List[APIHandled]:
126128
async def handle_api_request(
127129
self,
128130
request_id: str,
131+
tenant_id: Optional[str],
129132
request: BaseRequest,
130133
path: NormalisedURLPath,
131134
method: str,
@@ -250,10 +253,42 @@ def return_api_id_if_can_handle_request(
250253
NormalisedURLPath(DASHBOARD_API)
251254
)
252255

253-
if is_api_path(path, self.app_info):
254-
return get_api_if_matched(path, method)
256+
base_path_str = self.app_info.api_base_path.get_as_string_dangerous()
257+
path_str = path.get_as_string_dangerous()
258+
regex = rf"^{base_path_str}(?:/([a-zA-Z0-9-]+))?(/.*)$"
259+
260+
match = re.match(regex, path_str)
261+
tenant_id: str = DEFAULT_TENANT_ID
262+
remaining_path: Optional[NormalisedURLPath] = None
263+
264+
if match is not None:
265+
# TODO: Do something better than assert here
266+
assert match.group(1) is not None
267+
assert match.group(2) is not None
268+
269+
tenant_id = match.group(1)
270+
remaining_path = NormalisedURLPath(match.group(2))
271+
272+
if is_api_path(path, self.app_info.api_base_path) or (
273+
remaining_path is not None
274+
and is_api_path(
275+
path,
276+
self.app_info.api_base_path.append(NormalisedURLPath(f"/{tenant_id}")),
277+
)
278+
):
279+
# check remainingPath first as path that contains tenantId might match as well
280+
# since getApiIdIfMatched uses endsWith to match
281+
if remaining_path is not None:
282+
id_ = get_api_if_matched(remaining_path, method)
283+
if id_ is not None:
284+
return ApiIdWithTenantId(id_, tenant_id)
285+
286+
id_ = get_api_if_matched(path, method)
287+
if id_ is not None:
288+
return ApiIdWithTenantId(id_, DEFAULT_TENANT_ID)
255289

256290
if path.startswith(dashboard_bundle_path):
257-
return DASHBOARD_API
291+
return ApiIdWithTenantId(DASHBOARD_API, DEFAULT_TENANT_ID)
258292

293+
# tenantId is not supported for bundlePath, so not matching for it
259294
return None

supertokens_python/recipe/dashboard/utils.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
if TYPE_CHECKING:
1919
from supertokens_python.framework.request import BaseRequest
20-
from ...supertokens import AppInfo
2120

2221
from supertokens_python.recipe.emailpassword import EmailPasswordRecipe
2322
from supertokens_python.recipe.emailpassword.asyncio import (
@@ -195,10 +194,8 @@ def validate_and_normalise_user_input(
195194
)
196195

197196

198-
def is_api_path(path: NormalisedURLPath, app_info: AppInfo) -> bool:
199-
dashboard_recipe_base_path = app_info.api_base_path.append(
200-
NormalisedURLPath(DASHBOARD_API)
201-
)
197+
def is_api_path(path: NormalisedURLPath, base_path: NormalisedURLPath) -> bool:
198+
dashboard_recipe_base_path = base_path.append(NormalisedURLPath(DASHBOARD_API))
202199

203200
if not path.startswith(dashboard_recipe_base_path):
204201
return False

supertokens_python/recipe/emailpassword/recipe.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from __future__ import annotations
1515

1616
from os import environ
17-
from typing import TYPE_CHECKING, Any, Dict, List, Union
17+
from typing import TYPE_CHECKING, Any, Dict, List, Union, Optional
1818

1919
from supertokens_python.ingredients.emaildelivery import EmailDeliveryIngredient
2020
from supertokens_python.ingredients.emaildelivery.types import EmailDeliveryConfig
@@ -170,6 +170,7 @@ def get_apis_handled(self) -> List[APIHandled]:
170170
async def handle_api_request(
171171
self,
172172
request_id: str,
173+
tenant_id: Optional[str],
173174
request: BaseRequest,
174175
path: NormalisedURLPath,
175176
method: str,

supertokens_python/recipe/emailverification/recipe.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ def get_apis_handled(self) -> List[APIHandled]:
165165
async def handle_api_request(
166166
self,
167167
request_id: str,
168+
tenant_id: Optional[str],
168169
request: BaseRequest,
169170
path: NormalisedURLPath,
170171
method: str,

supertokens_python/recipe/jwt/recipe.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from __future__ import annotations
1515

1616
from os import environ
17-
from typing import TYPE_CHECKING, List, Union
17+
from typing import TYPE_CHECKING, List, Union, Optional
1818

1919
from supertokens_python.querier import Querier
2020
from supertokens_python.recipe.jwt.api.implementation import APIImplementation
@@ -80,6 +80,7 @@ def get_apis_handled(self) -> List[APIHandled]:
8080
async def handle_api_request(
8181
self,
8282
request_id: str,
83+
tenant_id: Optional[str],
8384
request: BaseRequest,
8485
path: NormalisedURLPath,
8586
method: str,

supertokens_python/recipe/multitenancy/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
# License for the specific language governing permissions and limitations
1313
# under the License.
1414
LOGIN_METHODS = "/loginmethods"
15-
DEFAULT_TENANT_ID = "defaultTenantId"
15+
DEFAULT_TENANT_ID = "public"

supertokens_python/recipe/multitenancy/recipe.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ def get_apis_handled(self) -> List[APIHandled]:
122122
async def handle_api_request(
123123
self,
124124
request_id: str,
125+
tenant_id: Optional[str],
125126
request: BaseRequest,
126127
path: NormalisedURLPath,
127128
method: str,

supertokens_python/recipe/openid/recipe.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from __future__ import annotations
1515

1616
from os import environ
17-
from typing import TYPE_CHECKING, List, Union
17+
from typing import TYPE_CHECKING, List, Union, Optional
1818

1919
from supertokens_python.querier import Querier
2020
from supertokens_python.recipe.jwt import JWTRecipe
@@ -89,6 +89,7 @@ def get_apis_handled(self) -> List[APIHandled]:
8989
async def handle_api_request(
9090
self,
9191
request_id: str,
92+
tenant_id: Optional[str],
9293
request: BaseRequest,
9394
path: NormalisedURLPath,
9495
method: str,
@@ -107,7 +108,7 @@ async def handle_api_request(
107108
self.api_implementation, options
108109
)
109110
return await self.jwt_recipe.handle_api_request(
110-
request_id, request, path, method, response
111+
request_id, tenant_id, request, path, method, response
111112
)
112113

113114
async def handle_error(

supertokens_python/recipe/passwordless/recipe.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from __future__ import annotations
1515

1616
from os import environ
17-
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, List, Union
17+
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, List, Union, Optional
1818

1919
from supertokens_python.ingredients.emaildelivery import EmailDeliveryIngredient
2020
from supertokens_python.ingredients.emaildelivery.types import EmailDeliveryConfig
@@ -185,6 +185,7 @@ def get_apis_handled(self) -> List[APIHandled]:
185185
async def handle_api_request(
186186
self,
187187
request_id: str,
188+
tenant_id: Optional[str],
188189
request: BaseRequest,
189190
path: NormalisedURLPath,
190191
method: str,

supertokens_python/recipe/session/recipe.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ def get_apis_handled(self) -> List[APIHandled]:
187187
async def handle_api_request(
188188
self,
189189
request_id: str,
190+
tenant_id: Optional[str],
190191
request: BaseRequest,
191192
path: NormalisedURLPath,
192193
method: str,
@@ -215,7 +216,7 @@ async def handle_api_request(
215216
),
216217
)
217218
return await self.openid_recipe.handle_api_request(
218-
request_id, request, path, method, response
219+
request_id, tenant_id, request, path, method, response
219220
)
220221

221222
async def handle_error(

0 commit comments

Comments
 (0)