lepture / authlib

The ultimate Python library in building OAuth, OpenID Connect clients and servers. JWS,JWE,JWK,JWA,JWT included.
https://authlib.org/
BSD 3-Clause "New" or "Revised" License
4.49k stars 448 forks source link

Invalid key_op "sign" for public key #511

Closed alexazevedo closed 1 year ago

alexazevedo commented 1 year ago

Describe the bug

After upgrading from 0.15 to 1.1.0, the jwt.encode method started to fail with the following error: ValueError: Invalid key_op "sign" for public key.

I didn't modify the public key and didn't change anything on the code. Just upgraded from 0.15 to 1.1.0 Error Stacks

  File "/usr/app/auth_service/jwt_generator.py", line 14, in create_member_jwt
    return create_signed_jwt(email, {'member_id': member_id}, ttl)
  File "/usr/app/auth_service/jwt_generator.py", line 43, in create_signed_jwt
    print(jwt.encode(header, payload, jwk_dict))
  File "/usr/local/lib/python3.9/site-packages/authlib/jose/rfc7519/jwt.py", line 69, in encode
    return self._jws.serialize_compact(header, text, key)
  File "/usr/local/lib/python3.9/site-packages/authlib/jose/rfc7515/jws.py", line 69, in serialize_compact
    signature = urlsafe_b64encode(algorithm.sign(signing_input, key))
  File "/usr/local/lib/python3.9/site-packages/authlib/jose/rfc7518/jws_algs.py", line 128, in sign
    op_key = key.get_op_key('sign')
  File "/usr/local/lib/python3.9/site-packages/authlib/jose/rfc7517/asymmetric_key.py", line 38, in get_op_key
    self.check_key_op(operation)
  File "/usr/local/lib/python3.9/site-packages/authlib/jose/rfc7517/base_key.py", line 77, in check_key_op
    raise ValueError('Invalid key_op "{}" for public key'.format(operation))
ValueError: Invalid key_op "sign" for public key

To Reproduce

Some details and parameters' values header: {'alg': 'ES256'} payload: {'exp': 1669392257, 'sub': 'user@one.com', 'member_id': 111} jwtdict: ```{'crv': 'P-256', 'x': 'FWbfvNNM1J4vtAs-SDaz91AyAl-3O8kcYw0qXhdKoc', 'y': 'A7BYNAseyKKWWvepmQPs0AMiE8Oid3Idmrx18sPEQlY', 'kty': 'EC', 'kid': 'VEbGrIYk3dupNXMLu_GFB8l2YG5lUKrFybVcGXNaHek'}```

Environment:

lepture commented 1 year ago

This is a security improvement. You are absolutely using jwt.encode wrong, when encode a token, you should use a private key.

lexabug commented 1 year ago

@alexazevedo your jwt_dict represents a public key. When you covert your JWK into a dict (key.as_dict()) you should specify the is_private parameter in order tell which type of the key you need: private or public. By default it as_dict() returns public key representation.