Skip to content

Commit

Permalink
Make typ optional (#644)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
dajiaji committed Aug 8, 2021
1 parent 885a730 commit 6ce51f3
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Expand Up @@ -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
~~~~~
Expand Down
2 changes: 2 additions & 0 deletions jwt/api_jws.py
Expand Up @@ -99,6 +99,8 @@ def encode(
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
Expand Down
59 changes: 59 additions & 0 deletions tests/test_api_jws.py
Expand Up @@ -650,6 +650,65 @@ def test_encode_headers_parameter_adds_headers(self, jws, payload):
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})
Expand Down
27 changes: 27 additions & 0 deletions tests/test_api_jwt.py
Expand Up @@ -16,6 +16,7 @@
InvalidIssuerError,
MissingRequiredClaimError,
)
from jwt.utils import base64url_decode

from .utils import crypto_required, key_path, utc_timestamp

Expand Down Expand Up @@ -167,6 +168,32 @@ def test_encode_bad_type(self, jwt):
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 = (
Expand Down

0 comments on commit 6ce51f3

Please sign in to comment.