Skip to content

Commit 2685c31

Browse files
committed
fix: roles and permissions for oauth2
1 parent 632b5dd commit 2685c31

File tree

1 file changed

+108
-2
lines changed

1 file changed

+108
-2
lines changed

supertokens_python/recipe/userroles/recipe.py

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,20 @@
2121
from supertokens_python.framework import BaseRequest, BaseResponse
2222
from supertokens_python.normalised_url_path import NormalisedURLPath
2323
from supertokens_python.querier import Querier
24+
from supertokens_python.recipe.session.asyncio import get_session_information
2425
from supertokens_python.recipe.userroles.recipe_implementation import (
2526
RecipeImplementation,
2627
)
2728
from supertokens_python.recipe.userroles.utils import validate_and_normalise_user_input
2829
from supertokens_python.recipe_module import APIHandled, RecipeModule
2930
from supertokens_python.supertokens import AppInfo
30-
from supertokens_python.types import RecipeUserId
31+
from supertokens_python.types import RecipeUserId, User
3132

3233
from ...post_init_callbacks import PostSTInitCallbacks
3334
from ..session import SessionRecipe
3435
from ..session.claim_base_classes.primitive_array_claim import PrimitiveArrayClaim
3536
from .exceptions import SuperTokensUserRolesError
36-
from .interfaces import GetPermissionsForRoleOkResult
37+
from .interfaces import GetPermissionsForRoleOkResult, UnknownRoleError
3738
from .utils import InputOverrideConfig
3839

3940

@@ -49,6 +50,8 @@ def __init__(
4950
skip_adding_permissions_to_access_token: Optional[bool] = None,
5051
override: Union[InputOverrideConfig, None] = None,
5152
):
53+
from ..oauth2provider.recipe import OAuth2ProviderRecipe
54+
5255
super().__init__(recipe_id, app_info)
5356
self.config = validate_and_normalise_user_input(
5457
self,
@@ -72,6 +75,109 @@ def callback():
7275
PermissionClaim
7376
)
7477

78+
async def token_payload_builder(
79+
user: User,
80+
scopes: List[str],
81+
session_handle: str,
82+
user_context: Dict[str, Any],
83+
) -> Dict[str, Any]:
84+
payload: Dict[str, Any] = {"roles": None, "permissions": None}
85+
86+
session_info = await get_session_information(
87+
session_handle, user_context
88+
)
89+
90+
if session_info is None:
91+
raise Exception("should never come here")
92+
93+
user_roles: List[str] = []
94+
95+
if "roles" in scopes or "permissions" in scopes:
96+
res = await self.recipe_implementation.get_roles_for_user(
97+
tenant_id=session_info.tenant_id,
98+
user_id=user.id,
99+
user_context=user_context,
100+
)
101+
102+
user_roles = res.roles
103+
104+
if "roles" in scopes:
105+
payload["roles"] = user_roles
106+
107+
if "permissions" in scopes:
108+
user_permissions: Set[str] = set()
109+
for role in user_roles:
110+
role_permissions = (
111+
await self.recipe_implementation.get_permissions_for_role(
112+
role=role,
113+
user_context=user_context,
114+
)
115+
)
116+
117+
if isinstance(role_permissions, UnknownRoleError):
118+
raise Exception("Failed to fetch permissions for the role")
119+
120+
for perm in role_permissions.permissions:
121+
user_permissions.add(perm)
122+
123+
payload["permissions"] = list(user_permissions)
124+
125+
return payload
126+
127+
OAuth2ProviderRecipe.get_instance().add_access_token_builder_from_other_recipe(
128+
token_payload_builder
129+
)
130+
OAuth2ProviderRecipe.get_instance().add_id_token_builder_from_other_recipe(
131+
token_payload_builder
132+
)
133+
134+
async def user_info_builder(
135+
user: User,
136+
_access_token_payload: Dict[str, Any],
137+
scopes: List[str],
138+
tenant_id: str,
139+
user_context: Dict[str, Any],
140+
) -> Dict[str, Any]:
141+
user_info: Dict[str, Any] = {"roles": None, "permissions": None}
142+
143+
user_roles = []
144+
145+
if "roles" in scopes or "permissions" in scopes:
146+
res = await self.recipe_implementation.get_roles_for_user(
147+
tenant_id=tenant_id,
148+
user_id=user.id,
149+
user_context=user_context,
150+
)
151+
152+
user_roles = res.roles
153+
154+
if "roles" in scopes:
155+
user_info["roles"] = user_roles
156+
157+
if "permissions" in scopes:
158+
user_permissions: Set[str] = set()
159+
for role in user_roles:
160+
role_permissions = (
161+
await self.recipe_implementation.get_permissions_for_role(
162+
role=role,
163+
user_context=user_context,
164+
)
165+
)
166+
167+
if isinstance(role_permissions, UnknownRoleError):
168+
raise Exception("Failed to fetch permissions for the role")
169+
170+
for perm in role_permissions.permissions:
171+
user_permissions.add(perm)
172+
173+
user_info["permissions"] = list(user_permissions)
174+
175+
return user_info
176+
177+
OAuth2ProviderRecipe.get_instance().add_user_info_builder_from_other_recipe(
178+
user_info_builder
179+
)
180+
75181
PostSTInitCallbacks.add_post_init_callback(callback)
76182

77183
def is_error_from_this_recipe_based_on_instance(self, err: Exception) -> bool:

0 commit comments

Comments
 (0)