Skip to content

Add support for OrderedDict to headers to make possible custom ordering #715

Closed
@kadabusha

Description

@kadabusha

Headers order in jwt.encode() follows values hardcoded in api_jws.py:

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

and can not be changed.
An issue referenced to old #116 - new RFC 8225 has pretty strict requirements for headers - they should be ordered lexicographically (A-Z)

The signature of the PASSporT is created as specified by JWS
   ([RFC7515], Section 5.1, Steps 1 through 6).  PASSporT MUST use the
   JWS Protected Header.  For the JWS Payload and the JWS Protected
   Header, however, the lexicographic ordering and whitespace rules
   described in Sections 4 and 5 of this document, and the JSON
   serialization rules in Section 9 of this document, MUST be followed.

Expected Result

Values for headers should not override the configured ones

{'alg': 'ES256', 'ppt': 'shaken', 'typ': 'passport', 'url': 'example.com'}

Actual Result

No matter what order is used for headers, jwt.encode() always uses hardcoded typ/alg key names on the first places.

{'typ': 'passport', 'alg': 'ES256', 'ppt': 'shaken', 'url': 'example.com'}

Reproduction Steps

$ openssl req -new -x509 -nodes -newkey ec:<(openssl ecparam -name secp384r1) -keyout key.pem -out cert.crt -days 3650 -subj "/C=US/ST=Pennsylvania/L=Philadelphia/O=Example CA/CN=SHAKEN"
$ python
>>> import jwt
>>> from collections import OrderedDict
>>> key = open('domain.key').read()
>>> payload = {'attest': "my test1", 'dest': "3333", 'iat': "423dfd", 'orig': "321", 'origid': "123"}
>>> header = {'alg': 'ES256', 'ppt': 'shaken', 'typ': 'passport', 'url': 'example.com'}
>>> header_ordered = OrderedDict()
>>> header_ordered['alg'] = 'ES256'
>>> header_ordered['ppt'] = 'shaken'
>>> header_ordered['typ'] = 'passport'
>>> header_ordered['url'] = 'example.com'
>>> jwt.get_unverified_header(jwt.encode(payload, key, algorithm="ES256", headers=header))
{'typ': 'passport', 'alg': 'ES256', 'ppt': 'shaken', 'url': 'example.com'}
>>> jwt.get_unverified_header(jwt.encode(payload, key, algorithm="ES256", headers=header_ordered))
{'typ': 'passport', 'alg': 'ES256', 'ppt': 'shaken', 'url': 'example.com'}

System Information

$ python -m jwt.help
{
  "cryptography": {
    "version": "2.9.2"
  },
  "implementation": {
    "name": "CPython",
    "version": "3.8.12"
  },
  "platform": {
    "release": "11.3-RELEASE-p6",
    "system": "FreeBSD"
  },
  "pyjwt": {
    "version": "1.7.1"
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions