Skip to content

Commit

Permalink
add "typ": "JWT" header by default when creating JWT (#17)
Browse files Browse the repository at this point in the history
* add "typ": "JWT" header by default when creating JWT
  • Loading branch information
guillp authored Jul 24, 2023
1 parent 25c1c13 commit 6fa76b6
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 5 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ jwt = Jwt.sign(claims, private_jwk)
# that's it! we have a signed JWT
assert isinstance(jwt, Jwt) # Jwt are objects
assert jwt.claims == claims # claims can be accessed as a dict
assert jwt.headers == {"alg": "ES256", "kid": "my_key"} # headers too
assert jwt.headers == {"typ": "JWT", "alg": "ES256", "kid": "my_key"} # headers too
assert jwt.sub == "some_sub" # individual claims can be accessed as attributes
assert jwt["claim1"] == "value1" # or as dict items (with "subscription")
assert jwt.alg == "ES256" # alg and kid headers are also accessible as attributes
Expand All @@ -81,7 +81,7 @@ assert jwt.verify_signature(private_jwk.public_jwk())
assert jwt.verify_signature(private_jwk.public_jwk(), alg="ES256")

print(jwt)
# eyJhbGciOiJFUzI1NiIsImtpZCI6Im15a2V5In0.eyJzdWIiOiJzb21lX3N1YiIsImNsYWltMSI6InZhbHVlMSJ9.C1KcDyDT8qXwUqcWzPKkQD7f6xai-gCgaRFMdKPe80Vk7XeYNa8ovuLwvdXgGW4ZZ_lL73QIyncY7tHGXUthag
# eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Im15X2tleSJ9.eyJzdWIiOiJzb21lX3N1YiIsImNsYWltMSI6InZhbHVlMSJ9.3VVLoaMVvdsieKKXqKenR62-7FqzUx4mhHV_AXYkNaaEbuEhdI6ej7PTkxZGtdm8pIQljhajo8NOk7eA-Z1klQ
# This will output the full JWT compact representation. You can inspect it for example at <https://jwt.io>
```

Expand Down
8 changes: 8 additions & 0 deletions jwskate/jwt/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def sign(
claims: Dict[str, Any],
key: Union[Jwk, Dict[str, Any], Any],
alg: Optional[str] = None,
typ: Optional[str] = 'JWT',
extra_headers: Optional[Dict[str, Any]] = None,
) -> SignedJwt:
"""Sign a JSON payload with a private key and return the resulting `SignedJwt`.
Expand All @@ -64,6 +65,7 @@ def sign(
claims: the payload to sign
key: the key to use for signing
alg: the alg to use for signing
typ: typ (token type) header to include. If `None`, do not include this header.
extra_headers: additional headers to include in the Jwt
Returns:
Expand All @@ -78,6 +80,8 @@ def sign(

extra_headers = extra_headers or {}
headers = dict(alg=alg, **extra_headers)
if typ:
headers['typ'] = typ
if key.kid:
headers["kid"] = key.kid

Expand Down Expand Up @@ -122,12 +126,14 @@ def sign_arbitrary(
def unprotected(
cls,
claims: Dict[str, Any],
typ: Optional[str] = 'JWT',
extra_headers: Optional[Dict[str, Any]] = None,
) -> SignedJwt:
"""Generate a JWT that is not signed and not encrypted (with alg=none).
Args:
claims: the claims to set in the token.
typ: typ (token type) header to include. If `None`, do not include this header.
extra_headers: additional headers to insert in the token.
Returns:
Expand All @@ -137,6 +143,8 @@ def unprotected(
from .signed import SignedJwt

headers = dict(extra_headers or {}, alg="none")
if typ:
headers['typ'] = typ

headers_part = BinaPy.serialize_to("json", headers).to("b64u")
claims_part = BinaPy.serialize_to("json", claims).to("b64u")
Expand Down
8 changes: 5 additions & 3 deletions tests/test_jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ def test_signed_jwt() -> None:

def test_unprotected() -> None:
jwt = Jwt.unprotected({"foo": "bar"})
assert jwt == "eyJhbGciOiJub25lIn0.eyJmb28iOiJiYXIifQ."
assert jwt == "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJmb28iOiJiYXIifQ."
assert jwt.alg == 'none'
assert jwt.signature == b''


def test_jwt_signer_and_verifier(issuer: str) -> None:
Expand Down Expand Up @@ -155,10 +157,10 @@ def test_empty_jwt(private_jwk: Jwk) -> None:

assert (
str(jwt)
== "eyJhbGciOiJSUzI1NiIsImtpZCI6IkpXSy1BQkNEIn0.e30.iQ6eyP9QrNDQVfKYwHpIWvnTBb0SXNEItDxMQ0VmsB5CA5FaRYtGvj01VjoUAHEegGvwFI4YI35MDY_-DUR3UIXqxVMOe9Hk2hb9paTjJLpDIa7Ml6LKDh9-4xmAAPjZcra4IYrpDux8ohg0LUzgxHn0xnKDuxKmlh9shCyNWEOfN_i_JX4v8aSD-zDBteftrY9GzHU4Y0mlvlm4FaAwafPXovZilb_dTgTBkiFLmXY0y5ESurhQ4LrQqLzBz45lSONLElil5OQu0ySrrC72CBKp-HjdpCsLyG9F9p_X-1r9mmqlN38zIcgwkbhek04ieX-rumyzvHLO_UzttxDQOg"
== "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkpXSy1BQkNEIn0.e30.c_3ppMzgxnhn4CkLBCNNJ5_zdoS6S9P79cruukiuixMHoHIPF0_nzaj5LBRUXt3O47JiJyUzroi1MXNe_Kod9dqLRM8RJ9t3dbWJRNbPrgnCkqpUhNZ6frrc8jVs9Qu9xmXLDYEa4aSwPSkQTufWN1fC04Vzm8JUMVXM0AFeKjyEyUijEuqeBBFztDbIc2apyXWc5bZW7HEkhDNgKK0pWAVnXLwt4OwGQjd6ZOC5Hgx1wDbiam_abNWaDvR53JSCLM0wMpkYrONY_RPjWRycyeb9K5tHOcGbfRvQqpZGsRG-slf-bqwSOt-8G6Phc_YDv9Lw4NN-vqOxbo2lw-3Crw"
)
assert bytes(jwt) == str(jwt).encode()
assert jwt.signed_part == b"eyJhbGciOiJSUzI1NiIsImtpZCI6IkpXSy1BQkNEIn0.e30"
assert jwt.signed_part == b"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkpXSy1BQkNEIn0.e30"

jwt.validate(key=private_jwk.public_jwk(), check_exp=False)

Expand Down

0 comments on commit 6fa76b6

Please sign in to comment.