Skip to content

Commit

Permalink
feat: switched abandonded python-jose to pyjwt (#3684)
Browse files Browse the repository at this point in the history
* Replace python-jose with PyJWT

---------

Co-authored-by: hooij804 <niels.vanhooij@kpn.com>
  • Loading branch information
nielsvanhooy and hooij804 authored Aug 22, 2024
1 parent b058d64 commit b7ab355
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 69 deletions.
12 changes: 6 additions & 6 deletions litestar/security/jwt/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from datetime import datetime, timezone
from typing import TYPE_CHECKING, Any

from jose import JWSError, JWTError, jwt
import jwt

from litestar.exceptions import ImproperlyConfiguredException, NotAuthorizedException

Expand Down Expand Up @@ -71,7 +71,7 @@ def __post_init__(self) -> None:
raise ImproperlyConfiguredException("iat must be a current or past time")

@classmethod
def decode(cls, encoded_token: str, secret: str | dict[str, str], algorithm: str) -> Self:
def decode(cls, encoded_token: str, secret: str, algorithm: str) -> Self:
"""Decode a passed in token string and returns a Token instance.
Args:
Expand All @@ -86,7 +86,7 @@ def decode(cls, encoded_token: str, secret: str | dict[str, str], algorithm: str
NotAuthorizedException: If the token is invalid.
"""
try:
payload = jwt.decode(token=encoded_token, key=secret, algorithms=[algorithm], options={"verify_aud": False})
payload = jwt.decode(jwt=encoded_token, key=secret, algorithms=[algorithm], options={"verify_aud": False})
exp = datetime.fromtimestamp(payload.pop("exp"), tz=timezone.utc)
iat = datetime.fromtimestamp(payload.pop("iat"), tz=timezone.utc)
field_names = {f.name for f in dataclasses.fields(Token)}
Expand All @@ -95,7 +95,7 @@ def decode(cls, encoded_token: str, secret: str | dict[str, str], algorithm: str
for key in extra_fields:
extras[key] = payload.pop(key)
return cls(exp=exp, iat=iat, **payload, extras=extras)
except (KeyError, JWTError, ImproperlyConfiguredException) as e:
except (KeyError, jwt.DecodeError, ImproperlyConfiguredException, jwt.exceptions.InvalidAlgorithmError) as e:
raise NotAuthorizedException("Invalid token") from e

def encode(self, secret: str, algorithm: str) -> str:
Expand All @@ -113,7 +113,7 @@ def encode(self, secret: str, algorithm: str) -> str:
"""
try:
return jwt.encode(
claims={k: v for k, v in asdict(self).items() if v is not None}, key=secret, algorithm=algorithm
payload={k: v for k, v in asdict(self).items() if v is not None}, key=secret, algorithm=algorithm
)
except (JWTError, JWSError) as e:
except (jwt.DecodeError, NotImplementedError) as e:
raise ImproperlyConfiguredException("Failed to encode token") from e
60 changes: 14 additions & 46 deletions pdm.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 17 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,19 @@ classifiers = [
"Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = [
"anyio>=3",
"httpx>=0.22",
"exceptiongroup; python_version < \"3.11\"",
"importlib-metadata; python_version < \"3.10\"",
"importlib-resources>=5.12.0; python_version < \"3.9\"",
"msgspec>=0.18.2",
"multidict>=6.0.2",
"polyfactory>=2.6.3",
"pyyaml",
"typing-extensions",
"click",
"rich>=13.0.0",
"rich-click",
"anyio>=3",
"httpx>=0.22",
"exceptiongroup; python_version < \"3.11\"",
"importlib-metadata; python_version < \"3.10\"",
"importlib-resources>=5.12.0; python_version < \"3.9\"",
"msgspec>=0.18.2",
"multidict>=6.0.2",
"polyfactory>=2.6.3",
"pyyaml",
"typing-extensions",
"click",
"rich>=13.0.0",
"rich-click",
]
description = "Litestar - A production-ready, highly performant, extensible ASGI API Framework"
keywords = ["api", "rest", "asgi", "litestar", "starlite"]
Expand Down Expand Up @@ -83,7 +83,10 @@ full = [
"litestar[annotated-types,attrs,brotli,cli,cryptography,jinja,jwt,mako,minijinja,opentelemetry,piccolo,picologging,prometheus,pydantic,redis,sqlalchemy,standard,structlog]",
]
jinja = ["jinja2>=3.1.2"]
jwt = ["python-jose", "cryptography"]
jwt = [
"cryptography",
"pyjwt>=2.9.0",
]
mako = ["mako>=1.2.4"]
minijinja = ["minijinja>=1.0.0"]
opentelemetry = ["opentelemetry-instrumentation-asgi"]
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/test_security/test_jwt/test_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
from typing import Any, Dict, Optional
from uuid import uuid4

import jwt
import pytest
from hypothesis import given
from hypothesis.strategies import datetimes
from jose import jwt

from litestar.exceptions import ImproperlyConfiguredException, NotAuthorizedException
from litestar.security.jwt import Token
Expand Down Expand Up @@ -150,7 +150,7 @@ def test_extra_fields() -> None:
"exp": (datetime.now(timezone.utc) + timedelta(seconds=30)),
}
token_secret = secrets.token_hex()
encoded_token = jwt.encode(claims=raw_token, key=token_secret, algorithm="HS256")
encoded_token = jwt.encode(payload=raw_token, key=token_secret, algorithm="HS256")
token = Token.decode(encoded_token=encoded_token, secret=token_secret, algorithm="HS256")
assert "azp" in token.extras
assert "email" in token.extras
Expand All @@ -161,6 +161,6 @@ def test_extra_fields() -> None:
"exp": (datetime.now(timezone.utc) + timedelta(seconds=30)),
}
token_secret = secrets.token_hex()
encoded_token = jwt.encode(claims=raw_token, key=token_secret, algorithm="HS256")
encoded_token = jwt.encode(payload=raw_token, key=token_secret, algorithm="HS256")
token = Token.decode(encoded_token=encoded_token, secret=token_secret, algorithm="HS256")
assert token.extras == {}

0 comments on commit b7ab355

Please sign in to comment.