Skip to content

Commit f435736

Browse files
feat: Check if token is a JWT (#623)
1 parent cd021e9 commit f435736

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

supabase_auth/_sync/client.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from ..constants import COOKIE_OPTIONS, DEFAULT_HEADERS, GOTRUE_URL, STORAGE_KEY
1212
from ..exceptions import APIError
13-
from ..helpers import is_http_url, model_dump, model_validate
13+
from ..helpers import is_http_url, is_valid_jwt, model_dump, model_validate
1414
from ..types import (
1515
AuthChangeEvent,
1616
CookieOptions,
@@ -364,6 +364,10 @@ def set_session(self, *, refresh_token: str) -> Session:
364364
APIError
365365
If an error occurs.
366366
"""
367+
368+
if not is_valid_jwt(refresh_token):
369+
ValueError("refresh_token must be a valid JWT authorization token")
370+
367371
response = self.api.refresh_access_token(refresh_token=refresh_token)
368372
self._save_session(session=response)
369373
self._notify_all_subscribers(event=AuthChangeEvent.SIGNED_IN)
@@ -388,6 +392,10 @@ def set_auth(self, *, access_token: str) -> Session:
388392
APIError
389393
If an error occurs.
390394
"""
395+
396+
if not is_valid_jwt(access_token):
397+
ValueError("access_token must be a valid JWT authorization token")
398+
391399
session = Session(
392400
access_token=access_token,
393401
token_type="bearer",

supabase_auth/helpers.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
)
3636

3737
TBaseModel = TypeVar("TBaseModel", bound=BaseModel)
38+
BASE64URL_REGEX = r"^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}$|[a-z0-9_-]{2}$)$"
3839

3940

4041
def model_validate(model: Type[TBaseModel], contents) -> TBaseModel:
@@ -243,3 +244,26 @@ def parse_response_api_version(response: Response):
243244

244245
def is_http_url(url: str) -> bool:
245246
return urlparse(url).scheme in {"https", "http"}
247+
248+
249+
def is_valid_jwt(value: str) -> bool:
250+
"""Checks if value looks like a JWT, does not do any extra parsing."""
251+
if not isinstance(value, str):
252+
return False
253+
254+
# Remove trailing whitespaces if any.
255+
value = value.strip()
256+
257+
# Remove "Bearer " prefix if any.
258+
if value.startswith("Bearer "):
259+
value = value[7:]
260+
261+
# Valid JWT must have 2 dots (Header.Paylod.Signature)
262+
if value.count(".") != 2:
263+
return False
264+
265+
for part in value.split("."):
266+
if not re.search(BASE64URL_REGEX, part, re.IGNORECASE):
267+
return False
268+
269+
return True

0 commit comments

Comments
 (0)