authlib
authlib copied to clipboard
jwk.dumps() No Longer Inserts Extra Parameters
In 0.14.3 and earlier, the rfc7517/jwk.py dumps()
implementation used to call _add_other_params()
to insert the extra parameters supplied by the caller into the object before returning it. This behaviour supported the statement at the bottom of the documentation here stating that:
You may pass extra parameters into dumps method, available parameters can be found on RFC7517 Section 4.
So with 0.14.3 you could do:
from pathlib import Path
from authlib.jose import jwk
public_key = Path('my_key.pub').read_text(encoding='utf-8')
jwk = jwk.dumps(public_key, kty='RSA', kid='my_id', use='sig', alg='RS256')
and the returned jwk dict would contain the extra kid
, use
and alg
parameters.
In 0.15, the above behaviour no longer works. The returned jwk only contains the n
, e
and kty
fields. The new JWK documentation here no longer mentions the dumps()
function, but it still states that:
You may pass extra parameters into import_key method, available parameters can be found on RFC7517 Section 4.
Testing shows that using the JsonWebKey.import_key()
interface results in the same issue.
To Reproduce
With authlib 0.15:
>>> from pathlib import Path
>>> from authlib.jose import jwk
>>> public_key = Path('my_key.pub').read_text(encoding='utf-8')
>>> jwk = jwk.dumps(public_key, kty='RSA', kid='my_id', use='sig', alg='RS256')
>>> jwk.keys()
dict_keys(['n', 'e', 'kty'])
>>> jwk['kid']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'kid'
>>> jwk['use']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'use'
>>> jwk['alg']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'alg'
>>>
Expected behavior
With authlib 0.14.3:
>>> from pathlib import Path
>>> from authlib.jose import jwk
>>> public_key = Path('my_key.pub').read_text(encoding='utf-8')
>>> jwk = jwk.dumps(public_key, kty='RSA', kid='my_id', use='sig', alg='RS256')
>>> jwk.keys()
>>> dict_keys(['kty', 'n', 'e', 'use', 'alg', 'kid'])
>>> jwk['kid']
'my_id'
>>> jwk['use']
'sig'
>>> jwk['alg']
'RS256'
>>>
Environment:
- OS: MacOS X 10.15.7, FreeBSD 12.1
- Python Version: 3.7, 3.8
- Authlib Version: 0.14.3, 0.15
@sjv0 Use JsonWebKey.import_key
instead.
https://docs.authlib.org/en/v0.15/jose/jwk.html
@sjv0 Use
JsonWebKey.import_key
instead.https://docs.authlib.org/en/v0.15/jose/jwk.html
As mentioned in my bug report, that doesn't work either:
>>> from pathlib import Path
>>> from authlib.jose import JsonWebKey
>>> key_data = Path('my_key.pub').read_text(encoding='utf-8')
>>> key = JsonWebKey.import_key(key_data, {'kty': 'RSA', 'kid': 'my_id', 'use': 'sig', 'alg': 'RS256'})
>>> key.keys()
dict_keys(['n', 'e'])
@sjv0 try
>>> from pathlib import Path
>>> from authlib.jose import JsonWebKey
>>> key_data = Path('my_key.pub').read_text(encoding='utf-8')
>>> key = JsonWebKey.import_key(key_data, {'kty': 'RSA', 'kid': 'my_id', 'use': 'sig', 'alg': 'RS256'})
>>> key.as_dict(is_private=False)
>>> from pathlib import Path
>>> from authlib.jose import JsonWebKey
>>> key_data = Path('my_key.pub').read_text(encoding='utf-8')
>>> key = JsonWebKey.import_key(key_data, {'kty': 'RSA', 'kid': 'my_id', 'use': 'sig', 'alg': 'RS256'})
>>> jwk = key.as_dict(is_private=False)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: as_dict() got an unexpected keyword argument 'is_private'
>>> key.keys()
dict_keys(['n', 'e'])
>>> jwk = key.as_dict()
>>> jwk.keys()
dict_keys(['n', 'e', 'kty'])
Looking at the source code it appears that is_private
is new to 0.15.3. I'm still running 0.15.2 which is the latest package available on FreeBSD:
$ python3.7
Python 3.7.9 (default, Jan 5 2021, 01:21:20)
[Clang 8.0.1 (tags/RELEASE_801/final 366581)] on freebsd12
Type "help", "copyright", "credits" or "license" for more information.
>>> import authlib
>>> authlib.version
'0.15.2'
>>> from pathlib import Path
>>> from authlib.jose import JsonWebKey
>>> key_data = Path('my_key.pub').read_text(encoding='utf-8')
>>> key = JsonWebKey.import_key(key_data, {'kty': 'RSA', 'kid': 'my_id', 'use': 'sig', 'alg': 'RS256'})
>>> import pdb
>>> pdb.run('key.as_dict()')
> <string>(1)<module>()
(Pdb) s
--Call--
> /usr/local/lib/python3.7/site-packages/authlib/jose/rfc7517/models.py(84)as_dict()
-> def as_dict(self, add_kid=False):
(Pdb) l 84,7
84 -> def as_dict(self, add_kid=False):
85 """Represent this key as a dict of the JSON Web Key."""
86 obj = dict(self)
87 obj['kty'] = self.kty
88 if add_kid and 'kid' not in obj:
89 obj['kid'] = self.thumbprint()
90 return obj
91
(Pdb)
Ideally there would be a way to do this that works on all versions of authlib, but there's no stress really because it's very straightforward to just add the extra fields to the dict manually after creating the JWK.
I just wanted to report that it's not as easy to have extra fields included in your JWK as the documentation would suggest.
Thanks!
@sjv0 oh, actually, is_private
is for v1.0, which is not released yet. :(
I'll close this issue, since I won't fix it in v0.15.x.
"use" and "alg" shall be inserted regardless of is_private flag. It is ok to dump them as public info.
Already fixed in 1.1