Giter Club home page Giter Club logo

pyjwt's Introduction

PyJWT

image

image

image

image

A Python implementation of RFC 7519. Original implementation was written by @progrium.

Installing

Install with pip:

$ pip install PyJWT

Usage

>>> import jwt
>>> encoded = jwt.encode({"some": "payload"}, "secret", algorithm="HS256")
>>> print(encoded)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg
>>> jwt.decode(encoded, "secret", algorithms=["HS256"])
{'some': 'payload'}

Documentation

View the full docs online at https://pyjwt.readthedocs.io/en/stable/

Tests

You can run tests from the project root after cloning with:

$ tox

pyjwt's People

Contributors

akx avatar alexm92 avatar auvipy avatar chillipino avatar dajiaji avatar daviddavis avatar dependabot[bot] avatar esneider avatar gullpong avatar jdufresne avatar jpadilla avatar julianmaurin avatar lothiraldan avatar mandus avatar maoaiz avatar mark-adams avatar michael-k avatar mike9005 avatar mindw avatar pre-commit-ci[bot] avatar progrium avatar purificant avatar ralphbean avatar sirosen avatar skion avatar sullivanmatt avatar viicos avatar vimalloc avatar wbolster-eiq avatar woodruffw avatar

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

pyjwt's Issues

Missing checks that decoded header and payload are actually json objects

Consider this sample evil JWT string: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.InN0cmluZyBjb250YWluaW5nIG5iZiBhbmQgZXhwIHRvIGZvb2wgdGhlIFwiaW5cIiBvcGVyYXRvciI.OP64cbMBNsV3_2dAgL_VD96-gAvKksoEMpwIL6BAh3M using the secret secret.

The payload in this JWT is not a JSON encoded object (dict in python), but a string containing the substrings "nbf" and "exp". This fools the validation since the in operator works both on strings and dictionaries, resulting in a TypeError instead of a jwt.DecodeError:

Traceback (most recent call last):
  File "tests/test_jwt.py", line 796, in test_check_issuer
    decoded = jwt.decode(token, 'secret', issuer=issuer)
  File "/Users/wbolster/Projects/pyjwt/jwt/__init__.py", line 324, in decode
    verify_expiration, leeway, **kwargs)
  File "/Users/wbolster/Projects/pyjwt/jwt/__init__.py", line 395, in verify_signature
    if payload['nbf'] > (utc_timestamp + leeway):
TypeError: string indices must be integers

The relevant part of the spec (http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#Validating) mandates that a proper check is done:

Verify that the resulting octet sequence is a UTF-8 encoded representation of a completely valid JSON object [...]

...but currently pyjwt doesn't do this.

I'm not sure whether this has serious security implications, but at least it allows an attacker (who already knows the secret) to crash the application instead of simply rejecting the invalid JWT.

Export `load` and `verify_signature` from `.api` in main module

These are useful functions for people who need to inspect properties of the payload before doing verification. Otherwise, there's redundant work to load the payload twice.

Since these functions were in the top-level namespace in the previous release, this was a breaking change in a patch release and so sadface.

tests show Resourcewarning

The tests spit out this warning: ResourceWarning: unclosed file <_io.TextIOWrapper name='tests/testkey_ec.pub' mode='r' encoding='UTF-8'>.

setup.py adds a "tests" module

In setup.py, "tests" is listed as a module, so when you're anywhere:

>>> import tests
>>> tests.__file__
'/usr/local/Cellar/python/2.7.1/lib/python2.7/site-packages/PyJWT-0.1.4-py2.7.egg/tests/__init__.pyc'

Adding support for Ed25519 signatures

Would anyone upstream be interested in adding support for NaCl-style Ed25519 signatures? I have done some preliminary work in here based on PyNaCl. At the moment it includes a fallback (and prohibitively slow) pure-Python implementation as well, but I could easily be persuaded to create a PR without that part and/or based on feedback.

`requests` auth module

Hiya,

Kenneth Reitz's requests library has a system for pluggable authentication & authorization modules. I've made a stab at a JWT module: jwt_auth.py in https://github.com/tgs/python-badgekit-api-client/tree/master/badgekit

At present, it uses python-jws, but could easily be rewritten to use pyjwt instead.

I'm thinking about how make it available to the public - some requests auth modules have their own projects, like https://github.com/requests/requests-ntlm . In this case, it seems a little silly, because the JWT auth is just one file, some unit tests, and a dependency on python-jws. Would you like to include the auth module in your project? I'm happy to clean it up if you want to review the code.

Thanks!
-Thomas

keys cannot be binary?

encode() does some string conversions to the key which cause it to barf if a key contains non-ascii characters. Is there a reason to be treating the key as a string? Normally crypto operations should support the full bit range, and I don't see anything in the JWT spec that would forbid this.

Otherwise, if I want to support, say, 128-bit strength, I need to bloat it out into an ascii string that is longer than 16 bytes (e.g. a hex string of 32 chars).

Decoding RS256 JWT

I am trying to decode a JWT encoded with RS256.

When I run the following:

secret = Crypto.PublicKey.RSA.importKey(PUBLIC_KEY)

I get:

ValueError: RSA key format is not supported

I suspect something might be wrong with the public key format:

PUBLIC_KEY= """-----BEGIN CERTIFICATE-----
MIIDETCCAfmgAwIBAgI....sRPdPR8
-----END CERTIFICATE-----"""

Decoding performance issue

Hi, in my implementation i have to decode the same JWT token twice. First one is used in decorator to verify authentication and the second one is used in main function just to extract user information. Say i add "verify=False" in my second one, will this gain a little bit performance benefit?

Perhaps allow audience= and issuer= args to .encode()

This would be nice for API parity with .decode() and would allow applications to ignore the iss and aud abbreviations used by JWT, and it would also give pyjwt control over the the way those fields are formatted, making it less likely that .encode() spits out a non-conforming token.

verify RS256 signature failing

Since updating PyJWT to v4.1 (from v3.2) we are no longer able to verify RS256 signed messages.

I now get a "Could not unserialize key data" ValueError exception. This stack trace shows the relevant place that the error occurs:

Traceback (most recent call last):
  File "/Users/username/Projects/platform-api/flaskapp/api_v1/views.py", line 247, in verify_LCD_token_internal
    jwt.verify_signature(token, signing, header, signature, subjectPublicKeyInfo)
  File "/Users/username/.virtualenvs/api-test/lib/python2.7/site-packages/jwt/__init__.py", line 365, in verify_signature
    key = prepare_key_methods[algorithm](key)
  File "/Users/username/.virtualenvs/api-test/lib/python2.7/site-packages/jwt/__init__.py", line 156, in prepare_RS_key
    key = load_pem_public_key(key, backend=default_backend())
  File "/Users/username/.virtualenvs/api-test/lib/python2.7/site-packages/cryptography/hazmat/primitives/serialization.py", line 48, in load_pem_public_key
    return backend.load_pem_public_key(data)
  File "/Users/username/.virtualenvs/api-test/lib/python2.7/site-packages/cryptography/hazmat/backends/multibackend.py", line 325, in load_pem_public_key
    return b.load_pem_public_key(data)
  File "/Users/username/.virtualenvs/api-test/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 699, in load_pem_public_key
    None,
  File "/Users/username/.virtualenvs/api-test/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 761, in _load_key
    self._handle_key_loading_error()
  File "/Users/username/.virtualenvs/api-test/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 833, in _handle_key_loading_error
    raise ValueError("Could not unserialize key data.") 

I'm not sure exactly which version this stopped working, but I assume it was when the crypto library dependancy switched from PyCrypto to cryptography

If there's anything else relevant that I can provide, then please ask.
Cheers
Buzzrick

timing attack vulnerability

From Jack [email protected]:

I noticed a timing attack vulnerability in your code for JWT hmac verification. When comparing the hmac signature of a foreign JWT with the calculated signature, the computation shortcircuits depending on how many bytes of the signatures match. This timing leak allows attackers to gain information about the secret signing key by sending specially crafted signatures. Here are some blogs posts describing the problem and fix in more detail:

http://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/
http://rdist.root.org/2010/01/07/timing-independent-array-comparison/

I found this vulnerability because I made the same mistake while implementing a JWT library in Lua. The solution requires making the string comparison always loop over the length of the signatures. Another potential pitfall is that the char by char checks should be performed with bitwise OR's as opposed to logical comparisons because the latter also leaks timing information.

Post 0.1.6 to PyPi

Would be great to have the latest version installed by default with pip.

Alternatively, tagging the release in git would make finding the release commit faster...

Unicode causes unnecessary DecodeError

A simple self.request.get('jwt') very often returns a unicode string in Python.

However, feeding this JWT to jwt.decode throws a DecodeError (it expects ASCII text rather than unicode). This should be more flexible to allow for the naive user to avoid a half hour wasted debugging the error.

Non-ascii keys in Python3 not working

I'm not actually sure if this is intended to work but based on other discussions (see e.g. issue #6), it seems like it is intended to work...

This is PyJWT-0.2.0 (pip installed), python 3.3 on a mac. I have a workaround (monkeypatch) shown below, but obviously this isn't the right solution...

>>> import jwt
>>> key=b'\x01\x02\x03'
>>> jwt.encode({}, key=key)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/gwachob/Desktop/1356/tapcentive-msi-server/venv/lib/python3.3/site-packages/jwt/__init__.py", line 165, in encode
    key = prepare_key_methods[algorithm](key)
  File "/Users/gwachob/Desktop/1356/tapcentive-msi-server/venv/lib/python3.3/site-packages/jwt/__init__.py", line 55, in prepare_HS_key
    raise TypeError("Expecting a string-formatted key.")
TypeError: Expecting a string-formatted key.

Monkey-patching

    def my_prepare_HS_key(key):
        return key
    for method in jwt.prepare_key_methods.keys():
        jwt.prepare_key_methods[method] = my_prepare_HS_key

Setup Travis CI

@progrium Included a .travis.yml that should work using tox. What do you feel about setting up this repo on Travis? Can you do it?

usage of unicode_literals breaks "import *"

As mentioned in #67, unicode_literals is evil in code that needs to work unchanged in Python 2 and Python 3.

I know that import * is an anti-pattern, but this is an example of what breaks because of unicode_literals in Python 2:

>>> from jwt import *
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Item in ``from list'' not a string

Other tools using __all__ (IDEs perhaps? I don't use those) will likely break as well.

Payload missing padding (==)

The payload is missing padding, removing the last } from json payload.

Example:

!/bin/sh

token=$(python << END
import jwt
print jwt.encode({'clientId': 'XXX', 'exp' : 1426505519 }, 'secret')
END)

payload=$(echo $token | cut -d'.' -f 2)
echo $(echo ${payload} |base64 --decode)

version -0.2.1?, testsuite

Have just added this to portage. The latest release listed and made available here is 0.2.0. I have the 0,2,1 at pypi but, as often happens, it's missing the testsuite; any and all files to run the testsuite. The testsuite is an extra however I generally include them if present. It's in the repo but absent from the tarball. Is this intended?
It won't be the first time if it isn't.

Can't decode tokens encoded with the "none" algorithm

There seems to be some problems with decoding tokens using the "none" algorithm:

>>> jwt.encode({'some': 'payload'}, 'secret', 'none')
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzb21lIjoicGF5bG9hZCJ9.'
>>> jwt.decode('eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzb21lIjoicGF5bG9hZCJ9.', 'secret')
[...]
KeyError: 'NONE'
[...]
DecodeError: Algorithm not supported

PyPI package cleanup

The PyPI packages is somewhat messy and provides some strange copies of PyJWT.egg-info/SOURCES. Maybe this should be cleaned up.

> ls work/PyJWT-0.4.1/PyJWT.egg-info/
PKG-INFO
SOURCES (Joses-iMac's conflicted copy 2014-10-17).txt
SOURCES.txt
dependency_links.txt
top_level.txt

pip install PyJWT fails

Hello. easy_install PyJWT works fine but pip install PyJWT fails because there is no source distribution. When registering on PyPI you can add a source distribution alongside the egg like this:

python setup.py bdist_egg sdist register upload -s

pip is nicer to use because it doesn't do confusing things with .pth files. http://pypi.python.org/pypi/pip

thanks for a python implementation of JWT!

Support for App Engine

Google App Engine's python runtime environment unfortunately only supports the "pycrypto" library and not the newer "cryptography" library (they have a pre-vetted list of native libraries that are supported): https://cloud.google.com/appengine/docs/python/tools/libraries27. I'm using the 0.3.x branch of pyjwt on App Engine right now and it'd be nice to be able to ugprade to 0.4.x.

The only solution I can think of is to bring back the old pycrypto code and use it as a fallback when the "cryptography" library isn't available. If you're ok with continuing to support pycrypto within pyjwt, I don't mind putting together a pull request to implement the fallback logic.

empty strings for issuer and audience are treated as "not present"

Parts of the current code such as this snippet:

issuer = kwargs.get('issuer')
if issuer:
    if payload.get('iss') != issuer:
        raise InvalidIssuer('Invalid issuer')

treat an empty string as issuer, i.e. "", the same as "no issuer specified". Though it's a rather bad practice to use empty strings for these values, this might lead to unexpected results. Changing the test to be if issuer is None: fixes this.

The same applies to audience, and possibly more.

Custom JSON Encoder

It would be helpful to be able to set the 'cls' attribute on the json.dumps method used by jwt.encode. This allows datatypes which do not have a built-in serializer to be present in the JWT payload.

To do this externally from JWT, one could do the following.

class CustomJSONEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, datetime.datetime):
            return http_date(o)
        if isinstance(o, uuid.UUID):
            return str(o)
        return json.JSONEncoder.default(self, o)

data = json.dumps(data, cls=CustomJSONEncoder)

It could be helpful to also supply a deserializer in the same way.

Encoding with RSA public key and decoding with private key

In the documentation it says:

When using the RSASSA-PKCS1-v1_5 algorithms, the key argument in both jwt.encode() and jwt.decode() ("secret" in the examples) is expected to be either an RSA public or private key in PEM format.

When i try to encode the payload with the public key i get an error:

>>> jwt_message = jwt.encode(payload, pub_rsakey, 'RS384')
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/Users/sven/code/sso/env/lib/python2.7/site-packages/jwt/__init__.py",
 line 295, in encode
    signature = signing_methods[algorithm](signing_input, key)
  File "/Users/sven/code/sso/env/lib/python2.7/site-packages/jwt/__init__.py",
 line 131, in <lambda>
    'RS384': lambda msg, key: sign_rsa(msg, key, hashes.SHA384()),
  File "/Users/sven/code/sso/env/lib/python2.7/site-packages/jwt/__init__.py",
 line 106, in sign_rsa
    signer = key.signer(
AttributeError: '_RSAPublicKey' object has no attribute 'signer'

What is happening is that the implementation in algorithms.py, line 137 tries to sign with the public key, but the cryptography.hazmat.backends.openssl.rsa._RSAPublicKey has no signer method: https://cryptography.io/en/latest/hazmat/primitives/interfaces/#cryptography.hazmat.primitives.interfaces.RSAPublicKey

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.