Skip to content

Incorrect type annotation in jwt.encode #396

@Hanaasagi

Description

@Hanaasagi

Similar to #394, but deeper.

In current pyjwt, PyJWT.encode's type annotation is:
https://github.com/jpadilla/pyjwt/blob/master/jwt/api_jwt.py#L48

    def encode(self,
               payload,  # type: Union[Dict, bytes]
               key,  # type: str
               algorithm='HS256',  # type: str
               headers=None,  # type: Optional[Dict]
               json_encoder=None  # type: Optional[Callable]
               ):
        # Check that we get a mapping
        if not isinstance(payload, Mapping):
            raise TypeError('Expecting a mapping object, as JWT only supports '
                            'JSON objects as payloads.')

payload is Union[Dict, bytes], but actually it should be Mapping[str, Any].

And current PyJWS.encode's type annotation also is Union[Dict, bytes].
https://github.com/jpadilla/pyjwt/blob/master/jwt/api_jws.py#L77

    def encode(self,
               payload,  # type: Union[Dict, bytes]
               key,  # type: str
               algorithm='HS256',  # type: str
               headers=None,  # type: Optional[Dict]
               json_encoder=None  # type: Optional[Callable]
               ):
        segments = []

        if algorithm is None:
            algorithm = 'none'

        if algorithm not in self._valid_algs:
            pass

        # Header
        header = {'typ': self.header_typ, 'alg': algorithm}

        if headers:
            self._validate_headers(headers)
            header.update(headers)

        json_header = force_bytes(
            json.dumps(
                header,
                separators=(',', ':'),
                cls=json_encoder
            )
        )

        segments.append(base64url_encode(json_header))
        segments.append(base64url_encode(payload))

But it calls base64url_encode and pass the payload.

base64url_encode is defined in utils.py

def base64url_encode(input):
    return base64.urlsafe_b64encode(input).replace(b'=', b'')

From the doc, we can know that it rejects a dict as argument.

base64.urlsafe_b64encode

Encode bytes-like object s using the URL- and filesystem-safe alphabet, which substitutes - instead of + and _ instead of / in the standard Base64 alphabet, and return the encoded bytes. The result can still contain =.

So the type of payload in PyJWS.encode should be bytes.

PyJWT is the subclass of PyJWS, and encode should be compatable with supertype annotation, because of Liskov substitution principle.

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleIssues without activity for more than 60 days

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions