Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error TypeError: ECPublicKey.verify() takes 3 positional arguments but 4 were given while using jwt.decode #964

Open
cemysf opened this issue Jul 12, 2024 · 7 comments
Labels
stale Issues without activity for more than 60 days

Comments

@cemysf
Copy link

cemysf commented Jul 12, 2024

Getting this error TypeError: ECPublicKey.verify() takes 3 positional arguments but 4 were given while trying to decode a token with RS256 algorithm.

Expected Result

Decode some token via jwt.decode

Actual Result

... (omitted) ...
File /opt/venv/lib/python3.12/site-packages/jwt/api_jwt.py:210, in PyJWT.decode(self, jwt, key, algorithms, options, verify, detached_payload, audience, issuer, leeway, **kwargs)
    203 if kwargs:
    204     warnings.warn(
    205         "passing additional kwargs to decode() is deprecated "
    206         "and will be removed in pyjwt version 3. "
    207         f"Unsupported kwargs: {tuple(kwargs.keys())}",
    208         RemovedInPyjwt3Warning,
    209     )
--> 210 decoded = self.decode_complete(
    211     jwt,
    212     key,
    213     algorithms,
    214     options,
    215     verify=verify,
    216     detached_payload=detached_payload,
    217     audience=audience,
    218     issuer=issuer,
    219     leeway=leeway,
    220 )
    221 return decoded["payload"]

File /opt/venv/lib/python3.12/site-packages/jwt/api_jwt.py:151, in PyJWT.decode_complete(self, jwt, key, algorithms, options, verify, detached_payload, audience, issuer, leeway, **kwargs)
    146 if options["verify_signature"] and not algorithms:
    147     raise DecodeError(
    148         'It is required that you pass in a value for the "algorithms" argument when calling decode().'
    149     )
--> 151 decoded = api_jws.decode_complete(
    152     jwt,
    153     key=key,
    154     algorithms=algorithms,
    155     options=options,
    156     detached_payload=detached_payload,
    157 )
    159 payload = self._decode_payload(decoded)
    161 merged_options = {**self.options, **options}

File /opt/venv/lib/python3.12/site-packages/jwt/api_jws.py:209, in PyJWS.decode_complete(self, jwt, key, algorithms, options, detached_payload, **kwargs)
    206     signing_input = b".".join([signing_input.rsplit(b".", 1)[0], payload])
    208 if verify_signature:
--> 209     self._verify_signature(signing_input, header, signature, key, algorithms)
    211 return {
    212     "payload": payload,
    213     "header": header,
    214     "signature": signature,
    215 }

File /opt/venv/lib/python3.12/site-packages/jwt/api_jws.py:309, in PyJWS._verify_signature(self, signing_input, header, signature, key, algorithms)
    306     raise InvalidAlgorithmError("Algorithm not supported") from e
    307 prepared_key = alg_obj.prepare_key(key)
--> 309 if not alg_obj.verify(signing_input, prepared_key, signature):
    310     raise InvalidSignatureError("Signature verification failed")

File /opt/venv/lib/python3.12/site-packages/jwt/algorithms.py:483, in RSAAlgorithm.verify(self, msg, key, sig)
    481 def verify(self, msg: bytes, key: RSAPublicKey, sig: bytes) -> bool:
    482     try:
--> 483         key.verify(sig, msg, padding.PKCS1v15(), self.hash_alg())
    484         return True
    485     except InvalidSignature:

TypeError: ECPublicKey.verify() takes 3 positional arguments but 4 were given

Reproduction Steps

import jwt

token = "..."
key = "..."
jwt.decode(
  jwt=token,
  key=key
  algorithms=["RS256",]
)

System Information

$ python -m jwt.help
{
  "cryptography": {
    "version": "42.0.5"
  },
  "implementation": {
    "name": "CPython",
    "version": "3.12.4"
  },
  "platform": {
    "release": "5.15.0-113-generic",
    "system": "Linux"
  },
  "pyjwt": {
    "version": "2.8.0"
  }
}
@RbnRncn
Copy link
Contributor

RbnRncn commented Sep 5, 2024

Exact same problem in 2.9.0.

{
  "cryptography": {
    "version": "43.0.1"
  },
  "implementation": {
    "name": "CPython",
    "version": "3.12.4"
  },
  "platform": {
    "release": "11",
    "system": "Windows"
  },
  "pyjwt": {
    "version": "2.9.0"
  }
}

@pachewise
Copy link
Contributor

pachewise commented Sep 10, 2024

Can you check what type(load_pem_public_key(your_key.encode("utf-8"))is? It seems to be returning an ElliptiveCurvePublicKey.

>>> from cryptography.hazmat.primitives.serialization import load_pem_public_key
>>> your_key = "..."  # unicode string, or you if you already have it as bytes skip the encode() below
>>> type(load_pem_public_key(your_key.encode("utf-8")))

(if load_pem_public_key throws an error for you, try load_ssh_public_key - that is, make sure you are using the loader relevant to how the key is formatted)

@RbnRncn
Copy link
Contributor

RbnRncn commented Sep 11, 2024

Yes, my problem was caused because I was taking the wrong key from the JWKS endpoint of my openid-configuration. I was taking the first one that it is in fact an elliptic curve key ({"kty": "EC"}).

Using a PyJWTClient and the method get_signing_key_from_jwt as it is showed in the example https://pyjwt.readthedocs.io/en/latest/usage.html#oidc-login-flow it took the correct key and decoded without issues.

@pachewise
Copy link
Contributor

I do feel like we should catch these issues where the key passed in is from the wrong algo-family (and, ideally, down to ensuring the same algo was used). I can attempt a PR this week if that's the approach we want to take.

@RbnRncn
Copy link
Contributor

RbnRncn commented Sep 12, 2024

Yes, maybe it should warn you (or throw you) in some way that you are trying to verify with an ECPublicKey when the algorithm you specified is RS256.

But if we are already detecting the key algorithm and we know the algorithm passed by the user, we could catch the error and be more specific.

Only my two cents as an user, I'm by no means an expert in this. I'm glad to help if needed.

@pachewise
Copy link
Contributor

Draft PR, so we have something to look at while proposing a "fix" for this.

pachewise added a commit to pachewise/pyjwt that referenced this issue Sep 12, 2024
Copy link

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days

@github-actions github-actions bot added the stale Issues without activity for more than 60 days label Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale Issues without activity for more than 60 days
Projects
None yet
Development

No branches or pull requests

3 participants