diff options
author | Ajitomi, Daisuke <ajitomi@gmail.com> | 2021-08-09 04:09:55 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-08 15:09:55 -0400 |
commit | 6ce51f391b52efa5cfc850ec337200da721c5d5a (patch) | |
tree | 0c5d027947d596040c3248a5ca03a3ba99371c5d | |
parent | 885a730e4e9e39f6027e377b0f6785b317a1f013 (diff) | |
download | pyjwt-6ce51f391b52efa5cfc850ec337200da721c5d5a.tar.gz |
Make typ optional (#644)
* Make typ optional.
* Update doc.
* Update CHANGELOG.
* Refine parameter order of for backward compatibility.
* Remove comment.
* Add Optional to typ.
* Keep order of JWT header parameter (typ, alg).
* Make typ optional with headers argument.
* Make typ optional with headers argument.
* Remove unused log.
-rw-r--r-- | CHANGELOG.rst | 1 | ||||
-rw-r--r-- | jwt/api_jws.py | 2 | ||||
-rw-r--r-- | tests/test_api_jws.py | 59 | ||||
-rw-r--r-- | tests/test_api_jwt.py | 27 |
4 files changed, 89 insertions, 0 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b049e9e..f122fe7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,7 @@ Fixed - Prefer `headers["alg"]` to `algorithm` in `jwt.encode()`. `#673 <https://github.com/jpadilla/pyjwt/pull/673>`__ - Fix aud validation to support {'aud': null} case. `#670 <https://github.com/jpadilla/pyjwt/pull/670>`__ +- Make `typ` optional in JWT to be compliant with RFC7519. `#644 <https://github.com/jpadilla/pyjwt/pull/644>`__ Added ~~~~~ diff --git a/jwt/api_jws.py b/jwt/api_jws.py index 6cefb2c..3a16294 100644 --- a/jwt/api_jws.py +++ b/jwt/api_jws.py @@ -99,6 +99,8 @@ class PyJWS: if headers: self._validate_headers(headers) header.update(headers) + if not header["typ"]: + del header["typ"] json_header = json.dumps( header, separators=(",", ":"), cls=json_encoder diff --git a/tests/test_api_jws.py b/tests/test_api_jws.py index fbeda02..07d1511 100644 --- a/tests/test_api_jws.py +++ b/tests/test_api_jws.py @@ -650,6 +650,65 @@ class TestJWS: assert "testheader" in header_obj assert header_obj["testheader"] == headers["testheader"] + def test_encode_with_typ(self, jws): + payload = """ + { + "iss": "https://scim.example.com", + "iat": 1458496404, + "jti": "4d3559ec67504aaba65d40b0363faad8", + "aud": [ + "https://scim.example.com/Feeds/98d52461fa5bbc879593b7754", + "https://scim.example.com/Feeds/5d7604516b1d08641d7676ee7" + ], + "events": { + "urn:ietf:params:scim:event:create": { + "ref": + "https://scim.example.com/Users/44f6142df96bd6ab61e7521d9", + "attributes": ["id", "name", "userName", "password", "emails"] + } + } + } + """ + token = jws.encode( + payload.encode("utf-8"), "secret", headers={"typ": "secevent+jwt"} + ) + + header = token[0 : token.index(".")].encode() + header = base64url_decode(header) + header_obj = json.loads(header) + + assert "typ" in header_obj + assert header_obj["typ"] == "secevent+jwt" + + def test_encode_with_typ_empty_string(self, jws, payload): + token = jws.encode(payload, "secret", headers={"typ": ""}) + + header = token[0 : token.index(".")].encode() + header = base64url_decode(header) + header_obj = json.loads(header) + + assert "typ" not in header_obj + + def test_encode_with_typ_none(self, jws, payload): + token = jws.encode(payload, "secret", headers={"typ": None}) + + header = token[0 : token.index(".")].encode() + header = base64url_decode(header) + header_obj = json.loads(header) + + assert "typ" not in header_obj + + def test_encode_with_typ_without_keywords(self, jws, payload): + headers = {"foo": "bar"} + token = jws.encode(payload, "secret", "HS256", headers, None) + + header = token[0 : token.index(".")].encode() + header = base64url_decode(header) + header_obj = json.loads(header) + + assert "foo" in header_obj + assert header_obj["foo"] == "bar" + def test_encode_fails_on_invalid_kid_types(self, jws, payload): with pytest.raises(InvalidTokenError) as exc: jws.encode(payload, "secret", headers={"kid": 123}) diff --git a/tests/test_api_jwt.py b/tests/test_api_jwt.py index 1faa05f..a6230b3 100644 --- a/tests/test_api_jwt.py +++ b/tests/test_api_jwt.py @@ -16,6 +16,7 @@ from jwt.exceptions import ( InvalidIssuerError, MissingRequiredClaimError, ) +from jwt.utils import base64url_decode from .utils import crypto_required, key_path, utc_timestamp @@ -167,6 +168,32 @@ class TestJWT: lambda: jwt.encode(t, "secret", algorithms=["HS256"]), ) + def test_encode_with_typ(self, jwt): + payload = { + "iss": "https://scim.example.com", + "iat": 1458496404, + "jti": "4d3559ec67504aaba65d40b0363faad8", + "aud": [ + "https://scim.example.com/Feeds/98d52461fa5bbc879593b7754", + "https://scim.example.com/Feeds/5d7604516b1d08641d7676ee7", + ], + "events": { + "urn:ietf:params:scim:event:create": { + "ref": "https://scim.example.com/Users/44f6142df96bd6ab61e7521d9", + "attributes": ["id", "name", "userName", "password", "emails"], + } + }, + } + token = jwt.encode( + payload, "secret", algorithm="HS256", headers={"typ": "secevent+jwt"} + ) + header = token[0 : token.index(".")].encode() + header = base64url_decode(header) + header_obj = json.loads(header) + + assert "typ" in header_obj + assert header_obj["typ"] == "secevent+jwt" + def test_decode_raises_exception_if_exp_is_not_int(self, jwt): # >>> jwt.encode({'exp': 'not-an-int'}, 'secret') example_jwt = ( |