Skip to content

Commit 083a6dd

Browse files
committed
fix: Improve code based on suggestions and failed existing tests
1 parent ea3915c commit 083a6dd

35 files changed

+320
-402
lines changed

supertokens_python/constants.py

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,9 @@
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-
SUPPORTED_CDI_VERSIONS = [
15-
"2.9",
16-
"2.10",
17-
"2.11",
18-
"2.12",
19-
"2.13",
20-
"2.14",
21-
"2.15",
22-
"2.16",
23-
"2.17",
24-
"2.18",
25-
"2.19",
26-
]
14+
from __future__ import annotations
15+
16+
SUPPORTED_CDI_VERSIONS = ["2.21"]
2717
VERSION = "0.12.4"
2818
TELEMETRY = "/telemetry"
2919
USER_COUNT = "/users/count"
@@ -38,3 +28,4 @@
3828
API_VERSION = "/apiversion"
3929
API_VERSION_HEADER = "cdi-version"
4030
DASHBOARD_VERSION = "0.4"
31+
HUNDRED_YEARS_IN_MS = 3153600000000

supertokens_python/recipe/session/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828

2929
InputErrorHandlers = utils.InputErrorHandlers
3030
InputOverrideConfig = utils.InputOverrideConfig
31-
JWTConfig = utils.JWTConfig
3231
SessionContainer = interfaces.SessionContainer
3332
exceptions = ex
3433

@@ -48,8 +47,9 @@ def init(
4847
] = None,
4948
error_handlers: Union[InputErrorHandlers, None] = None,
5049
override: Union[InputOverrideConfig, None] = None,
51-
jwt: Union[JWTConfig, None] = None,
5250
invalid_claim_status_code: Union[int, None] = None,
51+
use_dynamic_access_token_signing_key: Union[bool, None] = None,
52+
expose_access_token_to_frontend_in_cookie_based_auth: Union[bool, None] = None,
5353
) -> Callable[[AppInfo], RecipeModule]:
5454
return SessionRecipe.init(
5555
cookie_domain,
@@ -60,6 +60,7 @@ def init(
6060
get_token_transfer_method,
6161
error_handlers,
6262
override,
63-
jwt,
6463
invalid_claim_status_code,
64+
use_dynamic_access_token_signing_key,
65+
expose_access_token_to_frontend_in_cookie_based_auth,
6566
)

supertokens_python/recipe/session/access_token.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,11 @@ def get_info_from_access_token(
7575
if payload is None:
7676
raise PyJWKClientError("No key found")
7777

78-
elif jwt_info.version > 3:
78+
elif jwt_info.version >= 3:
7979
for client in jwk_clients:
80-
matching_key = client.get_matching_key_from_jwt(jwt_info.raw_token_string)
80+
matching_key = client.get_matching_key_from_jwt(
81+
jwt_info.raw_token_string
82+
)
8183
payload = jwt.decode( # type: ignore
8284
jwt_info.raw_token_string,
8385
matching_key,
@@ -97,9 +99,7 @@ def get_info_from_access_token(
9799
user_data = payload.get("userData")
98100
else:
99101
user_id = sanitize_string(payload.get("sub"))
100-
expiry_time = sanitize_number(
101-
payload.get("exp", 0) * 1000
102-
) # FIXME: Is using 0 as default okay?
102+
expiry_time = sanitize_number(payload.get("exp", 0) * 1000)
103103
time_created = sanitize_number(payload.get("iat", 0) * 1000)
104104
user_data = payload
105105

@@ -113,7 +113,9 @@ def get_info_from_access_token(
113113
if anti_csrf_token is None and do_anti_csrf_check:
114114
raise Exception("Access token does not contain the anti-csrf token")
115115

116-
assert isinstance(expiry_time, int)
116+
assert isinstance(
117+
expiry_time, (int, float)
118+
) # FIXME: Use only int once core is updated
117119

118120
if expiry_time < get_timestamp_ms():
119121
raise Exception("Access token expired")
@@ -139,8 +141,12 @@ def validate_access_token_structure(payload: Dict[str, Any], version: int) -> No
139141
if version >= 3:
140142
if (
141143
not isinstance(payload.get("sub"), str)
142-
or not isinstance(payload.get("exp"), int)
143-
or not isinstance(payload.get("iat"), int)
144+
or not isinstance(
145+
payload.get("exp"), (int, float)
146+
) # TODO: Leave only int once core is updated
147+
or not isinstance(
148+
payload.get("iat"), (int, float)
149+
) # TODO: Leave only int once core is updated
144150
or not isinstance(payload.get("sessionHandle"), str)
145151
or not isinstance(payload.get("refreshTokenHash1"), str)
146152
):

supertokens_python/recipe/session/api/implementation.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
from typing import Any, Dict
3232

33-
from supertokens_python.recipe.session.session_request_functions import (
33+
from ..session_request_functions import (
3434
get_session_from_request,
3535
refresh_session_in_request,
3636
)
@@ -88,5 +88,8 @@ async def verify_session(
8888
api_options.request,
8989
api_options.config,
9090
api_options.recipe_implementation,
91+
session_required=session_required,
92+
anti_csrf_check=anti_csrf_check,
93+
override_global_claim_validators=override_global_claim_validators,
9194
user_context=user_context,
9295
)

supertokens_python/recipe/session/asyncio/__init__.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from typing import Any, Dict, List, Union, TypeVar, Callable, Optional
1515

1616
from supertokens_python.exceptions import SuperTokensError
17-
from supertokens_python.framework.request import BaseRequest
1817
from supertokens_python.recipe.openid.interfaces import (
1918
GetOpenIdDiscoveryConfigurationResult,
2019
)
@@ -38,8 +37,10 @@
3837
RefreshSessionUnauthorizedResult,
3938
RefreshSessionTokenTheftErrorResult,
4039
)
41-
from supertokens_python.recipe.session.recipe import SessionRecipe
42-
from supertokens_python.recipe.session.session_request_functions import (
40+
from supertokens_python.recipe.session.recipe import (
41+
SessionRecipe,
42+
)
43+
from ..session_request_functions import (
4344
get_session_from_request,
4445
create_new_session_in_request,
4546
refresh_session_in_request,
@@ -278,7 +279,7 @@ async def remove_claim(
278279

279280

280281
async def get_session(
281-
request: BaseRequest,
282+
request: Any,
282283
session_required: Optional[bool] = None,
283284
anti_csrf_check: Optional[bool] = None,
284285
check_database: Optional[bool] = None,

supertokens_python/recipe/session/constants.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,12 @@
3535

3636
JWKCacheMaxAgeInMs = 60 * 1000
3737
JWKRequestCooldownInMs = 500 * 1000
38+
protected_props = [
39+
"sub",
40+
"iat",
41+
"exp",
42+
"sessionHandle",
43+
"parentRefreshTokenHash1",
44+
"refreshTokenHash1",
45+
"antiCsrfToken",
46+
]

supertokens_python/recipe/session/cookie_and_header.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
available_token_transfer_methods,
3333
)
3434
from ...logger import log_debug_message
35-
from .utils import HUNDRED_YEARS_IN_MS
35+
from supertokens_python.constants import HUNDRED_YEARS_IN_MS
3636

3737
if TYPE_CHECKING:
3838
from supertokens_python.framework.request import BaseRequest

supertokens_python/recipe/session/interfaces.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,12 @@ def __init__(
8484

8585

8686
class ReqResInfo:
87-
def __init__(self, request: BaseRequest, transfer_method: TokenTransferMethod):
87+
def __init__(
88+
self,
89+
request: Optional[BaseRequest] = None,
90+
transfer_method: Optional[TokenTransferMethod] = None,
91+
):
92+
# TODO: See if making args optional will cause any issues
8893
self.request = request
8994
self.transfer_method = transfer_method
9095

supertokens_python/recipe/session/jwks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def get_matching_key_from_jwt(self, token: str) -> str:
8080
assert self.jwk_set is not None
8181

8282
try:
83-
return str(self.jwk_set[kid].key) # type: ignore
83+
return self.jwk_set[kid].key # type: ignore
8484
except KeyError:
8585
if not self.is_cooling_down():
8686
# One more attempt to fetch the latest keys

supertokens_python/recipe/session/jwt.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
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 base64 import b64decode
1514
from json import dumps, loads
1615
from typing import Any, Dict, Optional
1716

@@ -68,7 +67,7 @@ def parse_jwt_without_signature_verification(jwt: str) -> ParsedJWTInfo:
6867
header, payload, signature = splitted_input
6968
# checking the header
7069
if header not in _allowed_headers:
71-
parsed_header = loads(b64decode(header.encode()))
70+
parsed_header = loads(utf_base64decode(header))
7271
header_version = parsed_header.get("version")
7372

7473
# We have to ensure version is a string, otherwise Number.parseInt can have unexpected results

supertokens_python/recipe/session/recipe.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,20 @@
1919
from supertokens_python.framework.response import BaseResponse
2020
from typing_extensions import Literal
2121

22-
from supertokens_python.utils import default_user_context
22+
from supertokens_python.utils import (
23+
default_user_context,
24+
)
2325

24-
from .api import handle_refresh_api, handle_signout_api
25-
from .cookie_and_header import get_cors_allowed_headers
26+
from .cookie_and_header import (
27+
get_cors_allowed_headers,
28+
)
2629
from .exceptions import (
2730
SuperTokensSessionError,
2831
TokenTheftError,
2932
UnauthorisedError,
3033
InvalidClaimsError,
3134
)
35+
from ... import AppInfo
3236
from ...types import MaybeAwaitable
3337

3438
if TYPE_CHECKING:
@@ -42,7 +46,6 @@
4246
from supertokens_python.recipe.openid.recipe import OpenIdRecipe
4347
from supertokens_python.recipe_module import APIHandled, RecipeModule
4448

45-
from .api.implementation import APIImplementation
4649
from .constants import SESSION_REFRESH, SIGNOUT
4750
from .interfaces import (
4851
APIInterface,
@@ -59,7 +62,6 @@
5962
InputErrorHandlers,
6063
InputOverrideConfig,
6164
TokenTransferMethod,
62-
JWTConfig,
6365
validate_and_normalise_user_input,
6466
)
6567

@@ -72,8 +74,6 @@ def __init__(
7274
self,
7375
recipe_id: str,
7476
app_info: AppInfo,
75-
use_dynamic_access_token_signing_key: Union[bool, None] = None,
76-
expose_access_token_to_frontend_in_cookie_based_auth: Union[bool, None] = None,
7777
cookie_domain: Union[str, None] = None,
7878
cookie_secure: Union[bool, None] = None,
7979
cookie_same_site: Union[Literal["lax", "none", "strict"], None] = None,
@@ -90,8 +90,9 @@ def __init__(
9090
] = None,
9191
error_handlers: Union[InputErrorHandlers, None] = None,
9292
override: Union[InputOverrideConfig, None] = None,
93-
jwt: Union[JWTConfig, None] = None,
9493
invalid_claim_status_code: Union[int, None] = None,
94+
use_dynamic_access_token_signing_key: Union[bool, None] = None,
95+
expose_access_token_to_frontend_in_cookie_based_auth: Union[bool, None] = None,
9596
):
9697
super().__init__(recipe_id, app_info)
9798
self.openid_recipe = OpenIdRecipe(
@@ -103,8 +104,6 @@ def __init__(
103104
)
104105
self.config = validate_and_normalise_user_input(
105106
app_info,
106-
use_dynamic_access_token_signing_key,
107-
expose_access_token_to_frontend_in_cookie_based_auth,
108107
cookie_domain,
109108
cookie_secure,
110109
cookie_same_site,
@@ -113,8 +112,9 @@ def __init__(
113112
get_token_transfer_method,
114113
error_handlers,
115114
override,
116-
jwt,
117115
invalid_claim_status_code,
116+
use_dynamic_access_token_signing_key,
117+
expose_access_token_to_frontend_in_cookie_based_auth,
118118
)
119119
log_debug_message("session init: anti_csrf: %s", self.config.anti_csrf)
120120
if self.config.cookie_domain is not None:
@@ -145,6 +145,9 @@ def __init__(
145145
if self.config.override.functions is None
146146
else self.config.override.functions(recipe_implementation)
147147
)
148+
149+
from .api.implementation import APIImplementation
150+
148151
api_implementation = APIImplementation()
149152
self.api_implementation: APIInterface = (
150153
api_implementation
@@ -188,6 +191,9 @@ async def handle_api_request(
188191
method: str,
189192
response: BaseResponse,
190193
) -> Union[BaseResponse, None]:
194+
# TODO: See if this import can be done globally without triggering cyclic import issues
195+
from .api import handle_refresh_api, handle_signout_api
196+
191197
if request_id == SESSION_REFRESH:
192198
return await handle_refresh_api(
193199
self.api_implementation,
@@ -266,7 +272,6 @@ def init(
266272
] = None,
267273
error_handlers: Union[InputErrorHandlers, None] = None,
268274
override: Union[InputOverrideConfig, None] = None,
269-
jwt: Union[JWTConfig, None] = None,
270275
invalid_claim_status_code: Union[int, None] = None,
271276
use_dynamic_access_token_signing_key: Union[bool, None] = None,
272277
expose_access_token_to_frontend_in_cookie_based_auth: Union[bool, None] = None,
@@ -276,8 +281,6 @@ def func(app_info: AppInfo):
276281
SessionRecipe.__instance = SessionRecipe(
277282
SessionRecipe.recipe_id,
278283
app_info,
279-
use_dynamic_access_token_signing_key,
280-
expose_access_token_to_frontend_in_cookie_based_auth,
281284
cookie_domain,
282285
cookie_secure,
283286
cookie_same_site,
@@ -286,8 +289,9 @@ def func(app_info: AppInfo):
286289
get_token_transfer_method,
287290
error_handlers,
288291
override,
289-
jwt,
290292
invalid_claim_status_code,
293+
use_dynamic_access_token_signing_key,
294+
expose_access_token_to_frontend_in_cookie_based_auth,
291295
)
292296
return SessionRecipe.__instance
293297
raise_general_exception(

0 commit comments

Comments
 (0)