authlib icon indicating copy to clipboard operation
authlib copied to clipboard

jwk.dumps() No Longer Inserts Extra Parameters

Open sjv0 opened this issue 4 years ago • 6 comments

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 avatar Feb 02 '21 00:02 sjv0

@sjv0 Use JsonWebKey.import_key instead.

https://docs.authlib.org/en/v0.15/jose/jwk.html

lepture avatar Feb 02 '21 13:02 lepture

@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 avatar Feb 02 '21 20:02 sjv0

@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)

lepture avatar Feb 03 '21 07:02 lepture

>>> 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 avatar Feb 03 '21 22:02 sjv0

@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.

lepture avatar Feb 04 '21 08:02 lepture

"use" and "alg" shall be inserted regardless of is_private flag. It is ok to dump them as public info.

toxadx avatar Oct 26 '21 11:10 toxadx

Already fixed in 1.1

lepture avatar Dec 06 '22 08:12 lepture