-
-
Notifications
You must be signed in to change notification settings - Fork 716
Description
I was looking into what PyGitHub does and writing test for it, invoking its JWT methods. Then I attempted decoding that JWT with jwt.decode(..., issuer=123)
since there was 'iss': 123
in the object. The validator treats anything non-str
as iterables and crashes:
def _validate_iss(self, payload: dict[str, Any], issuer: Any) -> None:
if issuer is None:
return
if "iss" not in payload:
raise MissingRequiredClaimError("iss")
if isinstance(issuer, str):
if payload["iss"] != issuer:
raise InvalidIssuerError("Invalid issuer")
else:
> if payload["iss"] not in issuer:
E TypeError: argument of type 'int' is not iterable
issuer = 123
payload = {'exp': 1739881471, 'iat': 1739881111, 'iss': 123}
self = <jwt.api_jwt.PyJWT object at 0x7f3101bc93a0>
When I attempted jwt.decode(..., issuer='123')
it hit another code branch and crashed in the equality check:
def _validate_iss(self, payload: dict[str, Any], issuer: Any) -> None:
if issuer is None:
return
if "iss" not in payload:
raise MissingRequiredClaimError("iss")
if isinstance(issuer, str):
if payload["iss"] != issuer:
> raise InvalidIssuerError("Invalid issuer")
E jwt.exceptions.InvalidIssuerError: Invalid issuer
issuer = '123'
payload = {'exp': 1739881584, 'iat': 1739881224, 'iss': 123}
self = <jwt.api_jwt.PyJWT object at 0x7ff5d86cd2e0>
I understand why this is happening and I'm not the one creating the payload with iss
being of int
type. I believe that the root cause is that PyGitHub creates it with an integer and the bug is that PyJWT allows it, not validating the input.
I checked the spec @ https://datatracker.ietf.org/doc/html/rfc7519#section-4.1 and it says this is supposed to be a string:
4.1.1. "iss" (Issuer) Claim
The "iss" (issuer) claim identifies the principal that issued the
JWT. The processing of this claim is generally application specific.
The "iss" value is a case-sensitive string containing a StringOrURI
value. Use of this claim is OPTIONAL.
(emphasis mine)
So here we are — PyJWT allows putting arbitrary values into payload on encoding but expects them to be spec-compliant on decoding.
I think, there are two things necessary to maintain consistency here — input validation with jwt.encode()
checking that the values provided are of legal types, and maybe better type checking and error messages in jwt.decode()
reporting illegal data types.