summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAjitomi, Daisuke <ajitomi@gmail.com>2021-08-09 04:09:55 +0900
committerGitHub <noreply@github.com>2021-08-08 15:09:55 -0400
commit6ce51f391b52efa5cfc850ec337200da721c5d5a (patch)
tree0c5d027947d596040c3248a5ca03a3ba99371c5d
parent885a730e4e9e39f6027e377b0f6785b317a1f013 (diff)
downloadpyjwt-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.rst1
-rw-r--r--jwt/api_jws.py2
-rw-r--r--tests/test_api_jws.py59
-rw-r--r--tests/test_api_jwt.py27
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 = (