GithubHelp home page GithubHelp logo

python-jose's Introduction

python-jose

A JOSE implementation in Python

PyPI Github Actions CI Status Coverage Status Docs Code style: black

Docs are available on ReadTheDocs.

The JavaScript Object Signing and Encryption (JOSE) technologies - JSON Web Signature (JWS), JSON Web Encryption (JWE), JSON Web Key (JWK), and JSON Web Algorithms (JWA) - collectively can be used to encrypt and/or sign content using a variety of algorithms. While the full set of permutations is extremely large, and might be daunting to some, it is expected that most applications will only use a small set of algorithms to meet their needs.

Installation

$ pip install python-jose[cryptography]

Cryptographic Backends

As of 3.3.0, python-jose implements three different cryptographic backends. The backend must be selected as an extra when installing python-jose. If you do not select a backend, the native-python backend will be installed.

Unless otherwise noted, all backends support all operations.

Due to complexities with setuptools, the native-python backend is always installed, even if you select a different backend on install. We recommend that you remove unnecessary dependencies in production.

  1. cryptography
    • This backend uses pyca/cryptography for all cryptographic operations. This is the recommended backend and is selected over all other backends if any others are present.
    • Installation: pip install python-jose[cryptography]
    • Unused dependencies:
      • rsa
      • ecdsa
      • pyasn1
  2. pycryptodome
    • This backend uses pycryptodome for all cryptographic operations.
    • Installation: pip install python-jose[pycryptodome]
    • Unused dependencies:
      • rsa
  3. native-python

    • This backend uses python-rsa and python-ecdsa for all cryptographic operations. This backend is always installed but any other backend will take precedence if one is installed.
    • Installation: pip install python-jose

    Note

    The native-python backend cannot process certificates.

Usage

>>> from jose import jwt
>>> token = jwt.encode({'key': 'value'}, 'secret', algorithm='HS256')
u'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ2YWx1ZSJ9.FG-8UppwHaFp1LgRYQQeS6EDQF7_6-bMFegNucHjmWg'

>>> jwt.decode(token, 'secret', algorithms=['HS256'])
{u'key': u'value'}

Thanks

This library was originally based heavily on the work of the folks over at PyJWT.

python-jose's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-jose's Issues

Python 3.5 support - Encoding errors - JWK

Hi,

I'm working with your lib and Auth0 authentication provider, but when i try to decode my encoded sig, i have a TypeError raised.

Following python code

keys = r.json()['keys']
key = jwk.construct(keys[0])

message, encoded_sig = jwt_value.rsplit('.', 1)
decoded_sig = base64url_decode(encoded_sig)
d = key.verify(message, decoded_sig)

and my error is:

  File "/home/lchabert/Documents/Developement/python/voxitrunk-env/lib/python3.5/site-packages/jose/utils.py", line 39, in base64url_decode
    input += b'=' * (4 - rem)
TypeError: Can't convert 'bytes' object to str implicitly

I have try to intercept this error on utils.py, and encode the input string. It works, but other encoding errors are raised on 'verify' function too.

Do you know any incompatibility with hashing modules and python 3.5 ?

Thanks,
Regards.

to_pem compatibility issues

With the new backends now in place and trying to get pure python rsa backend implemented, I found out that the RSA backends currently have unified a funny "standard" in that they're outputting PKCS#1 formatted PEM for private keys and PKCS#8 formatted PEM for public keys.

PKCS#1 and PKCS#8 are two standards of serializing keys. PKCS#1 is RSA only and can be identified by -----BEGIN RSA PRIVATE KEY----- or -----BEGIN RSA PUBLIC KEY-----, followed by the key data.

PKCS#8 is generalized. Usually identified by -----BEGIN PRIVATE KEY----- or -----BEGIN PUBLIC KEY-----, it also has a header, which specifies the key type, e.g. RSA, which is then followed by the same key data as PKCS#1.

The problem is that if this gets released, it's going to be cumbersome to maintain. The keys previously didn't have to_pem method, so this isn't related to previous releases.

The library should probably:

  • test both PKCS#1 and PKCS#8 formatted keys as input
  • standardize on output
  • support choosing desired output format

Include release notes

Is there a list of what's changed between releases of python-jose?

I'm having trouble deciding when a new version of python-jose is crucial – eg. because it includes security patches or fixes a bug that could affect my usage – vs when it is just a nice-to-have. Unfortunately redeploying is not always costless.

A change log / release notes would really help with this - or if you already have one, a link to it in the read-me or docs.

Thanks!

Unable to verify ADAL token signature

We're working w/ an app that is using adal.js to authenticate a user within a SPA, then afterwards we are looking to verify that token on the backend.

We are trying to use the the jwt.decode() method but receive a 'Signature Verification Failed' error we can't figure out. Since Azure issues its public keys in RSA format we were trying to use the jwk.RSAKey object to create the public key for decoding.

The keys we are pointed to are posted here:

https://login.windows.net/common/discovery/keys

Here's the flow of our code.

# token sent over from ADAL. We've pasted this string into http://jwt.calebb.net
# and everything appears to decode correctly.
token = "..."

# note there are multiple keys posted at the above URL, we select the right one by 
# looking at the kid attribute in the decoded token.
key_data=<dict from url posted above>

# Prepare the key using the RSA object
from jose.jwk import RSA
key = RSAKey(key_data, algorithm='RS256')

# Try to to use the exportKey() function to feed a PEM formatted
# key into jwt.decode()
jwt.decode(token, k.prepared_key.exportKey(), algorithms='RS256')

This results in a Signature verification failed error. We've also tried using jwk.construct() directly and calling verify but we have the same result.

Any ideas? Maybe we are using exportKey() incorrectly?

Thanks!

Unverified Signature Reports Unsupported Algorithm

https://github.com/mpdavis/python-jose/blob/master/jose/jws.py#L208

When a signature fails to verify in _verify_signture(), it raises a JWSError reporting a verification failure, but then then exception is immediately caught and re-raised as an Invalid Algorithm. This makes verification failures looks like missing algorithms.

Since get_algorithm_object already throws the right exception, it would be better if the outer try/except were just removed.

Use OrderedDict for headers in jwt.decode and jws._encode_header

Hello,

I would implement the "headless JWT" idea I rode in this article https://dev.to/neilmadden/7-best-practices-for-json-web-tokens the section 4 "Consider using "headless" JWTs" .

But the fact python-jose build the headers from dict make this impossible. Indeed, keys don't have an order in a classic dict. Could you consider to use OrderedDict instead, in jws.py l.131 and jwt.py l.114 ?

If this idea interests you, I could make a pull request.

Best,

pyjwt verifies token while python-jose fails

This pyjwt example works;

import jwt

public_key = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAumZZl1U3GFFZyVTRmHLg\nb1II9+fOIqg9CT4gGDyfLglsPMBV3m6G88KhgiStpnY/nmR/yx0PewIBYPJNEC6x\nxdKxDbKkIA7oZz+P+I1qJwYQsyhIfmVd9IwGIebYu1ZNrlJmseu4axi+Q3NbjRs4\nsvXDt/WF4bkmGIvdlt35xta7+Djo+WiGWfFZBaurnDZqtIZ4xl/CJW0rByX1hBHS\nUn/sS4JL8YUnPC8vLDUXlG5sLH/7BTI1VMtpWWqROnY9B/J8fR6oDdaSWP/BaYQQ\nr8g6ye3a95zpaTweTNnom2VMgj9g23qPYrKD9zXL4oXTjjTb0MbUHRLP8FcYI7E5\nSwIDAQAB\n-----END PUBLIC KEY-----\n"
token = "eyJraWQiOiJ3bXF3Q2ttbVFubll1RXJEVGU2MDVOWUdMR0VTSW5iWUVmd3ZBeXJHc053PSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJiMTMzZWQ0ZC02ZmUwLTQ0YjgtYjZiOS00YWY4NmJkMDYzMmQiLCJldmVudF9pZCI6IjcwNGEzODc3LTU0NGMtMTFlOC04YzRjLTZkNDNmZDlhNDg2YiIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1MjU5NTQ3OTEsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC51cy1lYXN0LTEuYW1hem9uYXdzLmNvbVwvdXMtZWFzdC0xX21yazRSeWpZeiIsImV4cCI6MTUyNTk1ODM5MSwiaWF0IjoxNTI1OTU0NzkxLCJqdGkiOiJjN2EzZjE1MC1jM2I3LTQzOWQtOWRiNS1jNzMxNDgzNzc3MjIiLCJjbGllbnRfaWQiOiI2dXBlNm5kdW5ka3Y3ZjVpOWpsbzZhOHAydCIsInVzZXJuYW1lIjoiam9uYXRoYW5rb3NnZWkxMDAwQGdtYWlsLmNvbSJ9.extzT3KMtocdKmuNgpUpOAUe2WgOmEV2TbO4yWS8nnNzugIlYx93od38WKxLR66x1qTJVv-YQ-Yuk0pt2Nh-bWbYbOmYpURNBAVeFoLILxOMcGtboRI8ecBN57KZt6EQZl9_4gJmSqYDC3yXPBWyZ1MpDItaZCEbOEHIg8CEoCgTyeo5H_-AH7jBBSOLJF1rzdqntVkaVeCO91Zc-L13ZNEpaxtNH95IKhn7XWD0vWvmnjYvHH4xe7iuOE-9zg9QTtb4tJvSdfkRYakfuJ-cqHaHOYFUu50n-rVs8H6Rr_fi_vohxC7ksdglhytg7K0COtvLSiJAFoZpuUW8QPF2lA"

decoded_payload = jwt.decode(token, key=public_key, algorithms=['RS256'])

While the same example with python-jose fails

from jose import jwk
from jose.utils import base64url_decode
token = "eyJraWQiOiJ3bXF3Q2ttbVFubll1RXJEVGU2MDVOWUdMR0VTSW5iWUVmd3ZBeXJHc053PSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJiMTMzZWQ0ZC02ZmUwLTQ0YjgtYjZiOS00YWY4NmJkMDYzMmQiLCJldmVudF9pZCI6IjcwNGEzODc3LTU0NGMtMTFlOC04YzRjLTZkNDNmZDlhNDg2YiIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1MjU5NTQ3OTEsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC51cy1lYXN0LTEuYW1hem9uYXdzLmNvbVwvdXMtZWFzdC0xX21yazRSeWpZeiIsImV4cCI6MTUyNTk1ODM5MSwiaWF0IjoxNTI1OTU0NzkxLCJqdGkiOiJjN2EzZjE1MC1jM2I3LTQzOWQtOWRiNS1jNzMxNDgzNzc3MjIiLCJjbGllbnRfaWQiOiI2dXBlNm5kdW5ka3Y3ZjVpOWpsbzZhOHAydCIsInVzZXJuYW1lIjoiam9uYXRoYW5rb3NnZWkxMDAwQGdtYWlsLmNvbSJ9.extzT3KMtocdKmuNgpUpOAUe2WgOmEV2TbO4yWS8nnNzugIlYx93od38WKxLR66x1qTJVv-YQ-Yuk0pt2Nh-bWbYbOmYpURNBAVeFoLILxOMcGtboRI8ecBN57KZt6EQZl9_4gJmSqYDC3yXPBWyZ1MpDItaZCEbOEHIg8CEoCgTyeo5H_-AH7jBBSOLJF1rzdqntVkaVeCO91Zc-L13ZNEpaxtNH95IKhn7XWD0vWvmnjYvHH4xe7iuOE-9zg9QTtb4tJvSdfkRYakfuJ-cqHaHOYFUu50n-rVs8H6Rr_fi_vohxC7ksdglhytg7K0COtvLSiJAFoZpuUW8QPF2lA"
rsa_key = {"alg":"RS256","e":"AQAB","kid":"wmqwCkmmQnnYuErDTe605NYGLGESInbYEfwvAyrGsNw=","kty":"RSA","n":"umZZl1U3GFFZyVTRmHLgb1II9-fOIqg9CT4gGDyfLglsPMBV3m6G88KhgiStpnY_nmR_yx0PewIBYPJNEC6xxdKxDbKkIA7oZz-P-I1qJwYQsyhIfmVd9IwGIebYu1ZNrlJmseu4axi-Q3NbjRs4svXDt_WF4bkmGIvdlt35xta7-Djo-WiGWfFZBaurnDZqtIZ4xl_CJW0rByX1hBHSUn_sS4JL8YUnPC8vLDUXlG5sLH_7BTI1VMtpWWqROnY9B_J8fR6oDdaSWP_BaYQQr8g6ye3a95zpaTweTNnom2VMgj9g23qPYrKD9zXL4oXTjjTb0MbUHRLP8FcYI7E5Sw","use":"sig"}
key = jwk.construct(rsa_key)
message, encoded_sig = token.rsplit('.', 1)
decoded_sig = base64url_decode(encoded_sig.encode('utf-8'))
key.verify(message, decoded_sig)

That is key.verify returns False

Improve Docs for jwt.decode with JWK

https://github.com/mpdavis/python-jose/blob/master/jose/jwt.py#L70v

def decode(token, key, algorithms=None, options=None, audience=None,
issuer=None, subject=None, access_token=None):
"""Verifies a JWT string's signature and validates reserved claims.
...
key (str): A key to attempt to verify the payload with.

It should mention that this key can be a string containing a JSON Web Key - because the example only shows a static password in that field, so its not obvious that it can do more.

https://github.com/mpdavis/python-jose/blob/master/jose/jwt.py#L110

Also consider showing an example where a JSON web key is used.

key.py and test.py unused?

Quick look, don't think these files are used. Might be used in local testing, but might not need to be committed.

OpenSSL signatures return a DER format instead of Raw key

Hi,

While attempting to convert from jose to using python cryptography, I came across an issue that may impact your library. It appears that OpenSSL (libssl 1.0.2g+) return an EC signature that's a DER. It appears that it's a Sequence NamedTypes of Integers. You can spot his because the decoded signature is not 64 octets (it can vary between 69-71 or so). Unfortunately, since it's a NamedTypes Sequence, you can't just do quick surgery to extract the two 32octet values. Instead, you'll need to do a length check on the signature and potentially run it through an ASN1 parser. I've already filed a similar "heads up" issue with ecdsa, although I'm not sure where the best fix might be.

It's kinda/sorta a problem here because you can create a valid EC signature using openssl that decrypts just fine but would fail here. (One presumes the opposite may also be true since I don't know if JWT enforces the signature encoding format.)

3.0.0: Package rsa and pyasn1 required despite not using default rsa backend

When trying to build with an alternative backend I am still required to pull in "rsa" and "pyasn1". Is it expected behaviour that they are always required even though I don't want to use the default backend?

I would have thought that if I have defined "python-jose[pycrypto]==3.0.0" (for example) in my requirements.txt file that I would not need to pull in packages required for the default backend, only "pycrypto". I'm wondering because I want to be sure I'm not accidentally using the wrong backend.

Support for RFC-8037 and RFC-7539

I'd love to see support for RFC-8037 (JWS/JWT specifically with Ed25519 via PyNaCl) and RFC-7539 (JWE using ChaCha20/Poly1305 encryption) in here.

  • Regarding RFC-8037, there seems to be a PR #100 available already, that needs merging. So I guess the work's pretty much done if it's deemed acceptable.
  • Regarding RFC-7539 things are a bit more difficult, as not all functions from libsodium (used underneath PyNaCl) are available via the PyNaCl API. Though, if somebody has PyNaCl, they also do have libsodium available. I have recently hacked around in my own code base to make some libsodium functions for the IETF-compliant authenticated encryption available to Python by using ctypes. That may provide a working pathway into enabling RFC-7539 for ChaCha20/Poly1305 encryption.

Hopefully some things will make their way into python-jose to allow for more modern, compact and fast ciphers to be used.

Dependency on google app engine.

Hi, I tried to use this on google app engine. A few of dependency are required, six.py and builtins. Am i going to add the required module manually or i missed out configuration on google app engine? Thanks for the advice.

0.6.0 release broke Python 2.7 compatibility

It seems the latest 0.6.0 release broke compatibility with Python 2.7 due to the from builtins import int in jwk.py. Is there a particular use case that import supports? It seems other parts (e.g. jwt.py) are still using the default int binding from the global namespace.

I'd like to propose the removal of that import or wrapping it with a try/except if it is indeed needed for Python 3.

Can't convert 'bytes' object to str implicitly

???
decoded_sig = base64url_decode(encoded_sig)
Traceback (most recent call last):
File "", line 1, in
File "/home/as/.local/lib/python3.5/site-packages/jose/utils.py", line 39, in base64url_decode
input += b'=' * (4 - rem)
TypeError: Can't convert 'bytes' object to str implicitly

Regression: cryptography library support for x509 certificate

Some dependency related issue came up in my Docker container which makes use of python-jose. It appears that something stopped installing pycrypto. I'm not sure if it used to get installed alongside python-jose due to the contents of the requirements.txt file, which contained pycrypto until this commit: b08a58f#diff-b4ef698db8ca845e5845c4618278f29a

Whichever the reason is why pycrypto isn't requested anymore in my dependency tree, for some reason python-jose is now using the cryptography backend (https://github.com/mpdavis/python-jose/blob/master/jose/backends/cryptography_backend.py), I think it is because I'm installing the service_identity module which pulls in pyopenssl and that in turn pulls in cryptography.

I just noticed that the cryptography module is recommended as the default one: https://github.com/mpdavis/python-jose#custom-backends

Here's the problem:

The pycrypto backend is able to load keys from x509 certificates, which are used by Google's GitKit and also by Firebase. The current code for the cryptography backend is not able to do this and triggers an exception due to a deserialization error JWKError: Could not deserialize key data both for GitKit and for Firebase.

Initial x509 certificates support got added due to this issue #27 (comment)

The modification in the snippet below at key.startswith('-----BEGIN CERTIFICATE-----'): fixes the issue, but I am not able to further deal with this issue due to time constraints, currently I'm solving this issue "manually" issuing a pip install pycrypto in the Dockerfile (other parts of my code depend on pycrypto, so I need to install it anyway).

Please read the blue note at https://cryptography.io/en/latest/hazmat/primitives/asymmetric/serialization/#pem
which leads to this document
https://cryptography.io/en/latest/x509/reference/#cryptography.x509.load_pem_x509_certificate

Please apologize for just stating the problem here. The modified code is the following (in this file https://github.com/mpdavis/python-jose/blob/master/jose/backends/cryptography_backend.py#L196):

class CryptographyRSAKey(Key):
    SHA256 = hashes.SHA256
    SHA384 = hashes.SHA384
    SHA512 = hashes.SHA512

    def __init__(self, key, algorithm, cryptography_backend=default_backend):
        
        if algorithm not in ALGORITHMS.RSA:
            raise JWKError('hash_alg: %s is not a valid hash algorithm' % algorithm)

        self.hash_alg = {
            ALGORITHMS.RS256: self.SHA256,
            ALGORITHMS.RS384: self.SHA384,
            ALGORITHMS.RS512: self.SHA512
        }.get(algorithm)
        self._algorithm = algorithm

        self.cryptography_backend = cryptography_backend

        # if it conforms to RSAPublicKey interface
        if hasattr(key, 'public_bytes') and hasattr(key, 'public_numbers'):
            self.prepared_key = key
            return

        if isinstance(key, dict):
            self.prepared_key = self._process_jwk(key)
            return

        if isinstance(key, six.string_types):
            key = key.encode('utf-8')

        if isinstance(key, six.binary_type):
            if key.startswith('-----BEGIN CERTIFICATE-----'): # <####### FROM HERE
              try:
                  key = x509.load_pem_x509_certificate(key, self.cryptography_backend())
                  self.prepared_key = key.public_key()
              except Exception as e:
                  raise JWKError(e)
            else: # <####### TO HERE
              try:
                  try:
                      key = load_pem_public_key(key, self.cryptography_backend())
                  except ValueError:
                      key = load_pem_private_key(key, password=None, backend=self.cryptography_backend())
                  self.prepared_key = key
              except Exception as e:
                  raise JWKError(e)
            return

        raise JWKError('Unable to parse an RSA_JWK from key: %s' % key)

This is the way it got fixed for pycrypto back then:

if key.startswith(b'-----BEGIN CERTIFICATE-----'):

six requirement

python-jose depends from six < 1.10.0 as specified in setup.py

    'six >=1.9.0, <1.10.0',

This behaviour breaks other packages like html5lib and others and it is difficult keep virtualenv clean
after an upgrade of packages

Question: Why use python-jose over pyjwt?

It would be nice to have a section of the readme dedicated to explaining why one might use this project instead of pyjwt, especially since it says it was based on pyjwt. This seems particularly salient since pyjwt has a larger community of contributors.

My team started using python-jose because it supports using JWKs to validate JWTs. At the time, pyjwt did not support JWKs.
However, since that time, pyjwt has added this feature, and I'm no longer sure which one is the right choice for us.

pip install python-jose fails on Windows 10

pip install python-jose
...
running build_ext
  warning: GMP or MPIR library not found; Not building Crypto.PublicKey._fastmath.
  building 'Crypto.Random.OSRNG.winrandom' extension
  error: Microsoft Visual C++ 9.0 is required. Get it from http://aka.ms/vcpython27

  ----------------------------------------
  Failed building wheel for pycrypto
...
Command "c:\python_virtual_envs\jwt\scripts\python.exe -u -c "import setuptools, tokenize;__file__='c:\\users\\ME\\appdata\\local\\temp\\pip-build-6sf2d9\\pycrypto\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record c:\users\ME\appdata\local\temp\pip-ouryei-record\install-record.txt --single-version-externally-managed --compile --install-headers c:\python_virtual_envs\jwt\include\site\python2.7\pycrypto" failed with error code 1 in c:\users\ME\appdata\local\temp\pip-build-6sf2d9\pycrypto\

base64url_decode TypeError: must be str, not bytes

Example copied from docs:

>>> from jose.utils import base64url_decode
>>> token = "eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZjMxNGJjNzAzNyJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4.s0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0"
>>> message, encoded_sig = token.rsplit('.', 1)
>>> decoded_sig = base64url_decode(encoded_sig)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/vernica/.local/lib/python3.6/site-packages/jose/utils.py", line 88, in base64url_decode
    input += b'=' * (4 - rem)
TypeError: must be str, not bytes

Environment:

  • Python 3.6.2
  • jose 1.4.0

Please switch to pycryptodomex

Guidance from pycryptodome is to use "pycryptodomex" unless you know you're installing to a virtualenv:

http://pycryptodome.readthedocs.io/en/latest/src/introduction.html

I think since this is a library, it would be better to require pycryptodomex and code to that. I'd be happy to do a PR if you agree.

(I noticed this because we have a couple libraries with transitive deps to jose and to pyjwkest (both). But they depend on both pycryptodome and pycryptodomex, which is a pain.)

ImportError

I get this log output when trying to run python-jose on AWS

from jose import jwt
 ImportError: No module named jose

I have already confirmed that python-jose is already installed.
Requirement already satisfied (use --upgrade to upgrade): python-jose==1.3.2 in /opt/python/run/venv/lib/python2.7/site-packages (from -r /opt/python/ondeck/app/requirements.txt (line 14))

Any idea why this might be happening?

JWTError

Hello I've been looking for how to use JWTError but i couldn't find an example anywhere. Did I miss it?

JWS verification succeeds with both public and private keys when signing with the private key using RS256

Here's the code snippet.

(PS: Not my keys)

from base64 import b64decode
from jose import jws

private_key = 'MIICWwIBAAKBgGbhqjBjqCgXkqDCx1BRHDSJb9P4J+OjOPXeeIsVkY9UiBerApfTUCIVMSEOiM3u1b790Uk1e6tAUMmoM3ZUIuWsEylGflZYK7alsxEAyQfTDW/eRgMovQD8mr4TDBWKa5y61z8UDt5+YPY4XSd4y/Xh4FJpHj4yyBJzNhJ8MzrzAgMBAAECgYA+sHdBsRgABg0kxEsrF6F2KeDoaqfzv7uvpfYR2fyuN7YNpfiYhvynJ/6dw/t8cHHyRTtHvr0ypqgTmNhy2+W/AR82SYYe/4nai8aHRuTvGM7/H1GwhlggsziJepZBpemU1Iu0Ue3+ZPEn+egB7PZezxi2QbLoafGoPArTJkB/AQJBAL23VPOzi9HL3NyDVJUIQ0bk2Ev118OkLtqqe/qORjDe+iDPX2k1pe6PYhgLovRZxElbCxENu9sgWQG/sea9KkECQQCK06JQ8XtlGRphmPPWb7z1gmebBr5m7RtYdX27g53OynrKiuZ9lnwY/r3deBJqas9qMCM2G0qANUGHZIKAb9AzAkEApKfpY1oBkCSPnBOf5Xk2auFTmRnWGkb1I3O0BtJUuTXNgYx6EqYtTc/EI3p2A/2lDsWl5Tc2RAjfN1VY4hpsAQJAcJ310ovSedS/XeTiCVZjhxXeThhOZNh7kmrdMDw4zAPdUGkVSVPGH9Cm3P4GkmVLFO0v4ziIWzDYk6ipZN9PmQJARv/EHHKedpVSBps5DvI+umMvtH06GhhoIm8iFDx4W1PTez9CGjvq299NoAqxHMyZVe23Kb0vqkKyPg0pgtRGjQ=='

public_key = 'MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGbhqjBjqCgXkqDCx1BRHDSJb9P4J+OjOPXeeIsVkY9UiBerApfTUCIVMSEOiM3u1b790Uk1e6tAUMmoM3ZUIuWsEylGflZYK7alsxEAyQfTDW/eRgMovQD8mr4TDBWKa5y61z8UDt5+YPY4XSd4y/Xh4FJpHj4yyBJzNhJ8MzrzAgMBAAE='

token = jws.sign({'email': '[email protected]'}, b64decode(private_key), algorithm='RS256')
print token
dec = jws.verify(token, b64decode(private_key), algorithms='RS256')
print dec

Upload source dists to PyPI

It would be nice if you could continue to upload source distributions to PyPI since this makes packaging python-jose for other package managers a bit easier.

Better exception handling

Right now, errors thrown by jws#_load, which are great and verbose and informative, are paved over in jwt#get_unverified_header with a catch-all JWTError with no extra information.

Is this intentional for security? It seems like that _load information would be very helpful for debugging downstream.

issuer check incorrect

https://github.com/mpdavis/python-jose/blob/master/jose/jwt.py#L75
issuer (str or iterable) – Acceptable value(s) for the issuer of the token. If the “iss” claim is included in the claim set, then the issuer must be given and the claim in the token must be among the acceptable values

The logic in the code is different from the description above - it only checks the issuer if one is passed to the api but the description above says the opposite. -ie if there is an issuer in the claims then it must be passed into the api.

https://github.com/mpdavis/python-jose/blob/master/jose/jwt.py#L354

Different servers generate different JWT tokens using the same parameters

I'm using python-jose's JWT implementation to generate JWT tokens for authentication purposes.

We're running our backend in a Docker container on Kubernetes and sometimes, when we have multiple pods, we get different tokens for the same claims, secret and algorithm. I've also had this happen on a single container on my development environment when touching my index.wsgi script.

Pod 1:

>>> jwt.encode({'key': 'value'}, 'secret', algorithm='HS256')
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ2YWx1ZSJ9.FG-8UppwHaFp1LgRYQQeS6EDQF7_6-bMFegNucHjmWg'

Pod 2:

>>> jwt.encode({'key': 'value'}, 'secret', algorithm='HS256')
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJrZXkiOiJ2YWx1ZSJ9.JPIDicqvQ6GAh14yE2yZ3wnZQ0LiLNTTRDtJgLZcn98'

I took a deep dive into the code to see what could be causing this and didn't find anything incriminating. In a nutshell, here's what the code does:

  1. Do a json.dumps of the algorithm header ({'typ': 'JWT', 'alg': 'HS256'}) and encode it as Base64, removing any ='s
  2. Do a json.dumps of the payload ({'key': 'value'}) and encode it as Base64, removing any ='s
  3. Sign encoded_header.encoded_payload using HMAC256 with the secret key and encode it as Base64, again removing any ='s
  4. Concatenate the signature to the previous string, resulting in encoded_header.encoded_payload.encoded_signature

At this point, I have no idea what is causing this. I'm suspecting a bug of some sort in the HMAC or SHA256 implementation of Python, but that seems rather unlikely... Any clues?

Note: we've successfully reproduced the bug using pyjwt.

StackOverflow Question

jwk.construct() does not support reading a private RSA key

Attempting to sign a JWT token with a private RSA key throws:

JWKError: Private key not available in this object

The problem seems to come from RSAKey._process_jwk() in jwk.py:

def _process_jwk(self, jwk_dict):
    if not jwk_dict.get('kty') == 'RSA':
        raise JWKError("Incorrect key type.  Expected: 'RSA', Recieved: %s" % jwk_dict.get('kty'))

    e = base64_to_long(jwk_dict.get('e', 256))
    n = base64_to_long(jwk_dict.get('n'))

    self.prepared_key = RSA.construct((n, e))
    return self.prepared_key

Note that the d, p, q fields in the JWK representation are ignored, but given the description in RSA.py (from pycrypto), these are the very values that are needed to construct a private key.

jws.verify type error

When passing a jwt and key to jws.verify I am getting a type error stating that a bytes like object is required. I can verify the jwt with the key successfully on jwt.io, and am passing byte strings as my arguments.

This:

print(type(jwt))
print(type(key))

jws.verify(jwt, key, algorithms=['HS256'])

Results in this:

<class 'bytes'>
<class 'bytes'>
TypeError, a bytes-like object is required, not 'str'

Old version of pycryptodome

How come an over 2 years old version of pycryptodome is used when there are releases that are less than a month old?

The reason why I discovered this is because this pycryptodome does not work on Heroku:

remote:   File "/app/.heroku/python/lib/python3.6/site-packages/Crypto/Hash/BLAKE2s.py", line 63, in <module>�

remote:     from Crypto.Random import get_random_bytes�

remote: ImportError: cannot import name 'get_random_bytes'�

Not sure if a newer version would fix it but I would assume so.

Import fails on Python 3.4 (and probably earlier versions of Python 3)

Steps to reproduce:

  1. Run a python 3.4 interpreter
  2. import jose.jws
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.4/dist-packages/jose/jws.py", line 8, in <module>
    from jose.jwa import get_algorithm_object
  File "/usr/local/lib/python3.4/dist-packages/jose/jwa.py", line 97
    except Exception, e:
                    ^
SyntaxError: invalid syntax

Add a clear example to readme on how to generate a pair of keys acceptable to python-jose

I took a shot and I failed. Now I will have to spend a while figuring out exactly what Python Jose prefers. A readme would take out the guesswork and make a statement as to the best practice.

ssh-keygen -t rsa -b 2048 -f jwtRS256.key
openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub
cat jwtRS256.key
cat jwtRS256.key.pub

<copy the private key into a python script>

>>> import jose.jwt
>>> PRIVATE_KEY = '<big long thing>'
>>> token = jose.jwt.encode({'a': 'b'}, PRIVATE_KEY, algorithm='RS256')
<snip>
jose.exceptions.JWSError: RSA key format is not supported

Various issues in jwt.decode / jws._get_keys

I've had a couple issues (figuring out how to use jwt.decode) which stem from the jws._get_keys implementation.

  1. key argument must be iterable- raises exception otherwise
  2. string key argument must not contain 'keys' (ie if a PEM base64 segment or HS secret segment contains keys, it'll break)
  3. key can't be the result of calling jwk.construct (usability issue)
  4. attempting json.loads on anything not a string seems weird

Add message about lack of X.509 certificate support in documentation

I get this error when using algorithms='RS256' on google app engine.

Full stack trace

Traceback (most recent call last):
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/devappserver2/python/request_handler.py", line 226, in handle_interactive_request
    exec(compiled_code, self._command_globals)
  File "<string>", line 12, in <module>
  File "lib/jose/jwt.py", line 121, in decode
    payload = jws.verify(token, key, algorithms, verify=verify_signature)
  File "lib/jose/jws.py", line 75, in verify
    _verify_signature(signing_input, header, signature, key, algorithms)
  File "lib/jose/jws.py", line 218, in _verify_signature
    key = jwk.construct(key, alg)
  File "lib/jose/jwk.py", line 65, in construct
    return RSAKey(key_data, algorithm)
  File "lib/jose/jwk.py", line 201, in __init__
    raise JWKError(e)
JWKError: RSA key format is not supported

Odd issue with RFC5270 test

Hi,
I'm currently working on a patch to allow python-jose to use pyelliptic. This is because we use the library in a fairly high-demand environment and would like to use a clib based EC handler.

I have every test but one working. tests.rfc.TestFourThreeThree.test_signature is failing because OpenSSL flags that the point defined is not on curve.

I have a gist that demonstrates the problem: https://gist.github.com/jrconlin/ad8c7f692235b0fd51ddbe20be09c272

(in that test, the "rfc" key is taken from the RFC text, "control" are a pair of points extracted from an openssl public key generated by:

openssl ecparam -name secp521r1 -genkey -noout | openssl ec -pubout)

Oddly, if I take the RFC key values and reformat them as a raw key PEM, openssl ecparam -check says they're ok.

Hoping that I'm just doing something stupid, but if you have a moment, I'd greatly appreciate your input.

crytography library

I ended up here because of PyJWT but I also needed jwk stuff. I noticed PyJWT uses cryptography for some algorithm support. I guess Google App Engine requires PyCrypto as you mention but perhaps python-jose should also support cryptography. For example pycrypto hasn't had a commit in 2 years whereas cryptography repository is active.

Just a thought! I might be interested in pitching in as well.

MemoryError

Hello,

I have MemoryError message then I try to import your lib.

Do you know potential problem places?

I use python 2.7.10 and djangorestframework 3.3.2 and last release of your library.
Result is:

Exception Type: MemoryError
/usr/lib64/python2.7/ctypes/__init__.py in _reset_cache, line 279

Should at_hash claim verification fail when missing from JWT?

It looks like at_hash in JWT payload is optional (see http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken).

However, in python-jose, when both id_token and access_token parameters are specified, decoding a JWT that has no at_hash claim raises an error (at_hash claim missing from token)
https://github.com/mpdavis/python-jose/pull/30/files#diff-b106d01229785c64375df96ca4b3f58cR422

Shouldn't it be acceptable since the spec says it's optional?

Obviously we can disable at_hash verification with the appropriate decode option, but we find it useful to perform claims verification on JWT that have it or not with the same code. Maybe with a allow_missing_at_hash option or something?

Huge thanks for this lib 😻

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.