JSON Web Token implementation in Python




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


auth0-logo If you want to quickly add secure token-based authentication to Python projects, feel free to check Auth0's Python SDK and free plan at auth0.com/developers.


Install with pip:

$ pip install PyJWT


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


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


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

$ tox
  • AttributeError: module 'jwt' has no attribute 'encode'

    AttributeError: module 'jwt' has no attribute 'encode'

    Using import jwt

    encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256') Traceback (most recent call last): File "< stdin >", line 1, in AttribureError: module 'jwt' has no attribure 'encode'

    Same issue with using decode

    opened by tekpriest 25
  • RSA256 not supported despite having cryptography (was: pycrypto) installed

    RSA256 not supported despite having cryptography (was: pycrypto) installed

    Python 3.2.3 on a RPi (Linux raspberrypi 3.18.11+ #781 PREEMPT Tue Apr 21 18:02:18 BST 2015 armv6l GNU/Linux).

    PyCrypto is installed:

    pycrypto                  - Cryptographic modules for Python.
      INSTALLED: 2.6.1 (latest)

    python3-dev and python3-crypto are installed as well. Note: the same issue is present whether either of pycrypto or python3-crypto are installed, or both, or neither.

    The following call crashes with an unsupported algorithm:

    myjwt = jwt.encode(claim, private_key, algorithm='RS256', headers={"alg": "RS256", "typ": "JWT"}).decode('utf-8')

    Exception in thread Thread-1:
    Traceback (most recent call last):
      File "/usr/local/lib/python3.2/dist-packages/jwt/api_jws.py", line 96, in encode
        alg_obj = self._algorithms[algorithm]
    KeyError: 'RS256'
    During handling of the above exception, another exception occurred:
    Traceback (most recent call last):
      File "/usr/lib/python3.2/threading.py", line 740, in _bootstrap_inner
      File "/usr/lib/python3.2/threading.py", line 693, in run
        self._target(*self._args, **self._kwargs)
      File "galarmclock.py", line 241, in getcalendar
      File "/root/galarmclock/googleauth.py", line 32, in gettoken
        myjwt = jwt.encode(claim, private_key, algorithm='RS256', headers={"alg": "RS256", "typ": "JWT"}).decode('utf-8')
      File "/usr/local/lib/python3.2/dist-packages/jwt/api_jwt.py", line 56, in encode
        json_payload, key, algorithm, headers, json_encoder
      File "/usr/local/lib/python3.2/dist-packages/jwt/api_jws.py", line 101, in encode
        raise NotImplementedError('Algorithm not supported')
    NotImplementedError: Algorithm not supported
    opened by wsw70 24
  • verify RS256 signature failing

    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
      File "/Users/username/.virtualenvs/api-test/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 761, in _load_key
      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

    opened by buzzrick 23
  • Change optparse for argparse.

    Change optparse for argparse.

    • Change optparse for the more modern argparse.
    • Refactored main() to fit new argparse code.
    • Added two subcommands: encode and decode
    • Added default functions for encode and decode subcommands
    • Replaced implicit arguments with standard Python syntax in usage text.
    opened by froi 22
  • Better error messages when missing cryptography package

    Better error messages when missing cryptography package

    In reference to #230. If trying to use a cryptography algorithm without the cryptography package installed, you will get this error:

    NotImplementedError: "cryptography" package must be installed to use this algorithm

    instead of:

    NotImplementedError: Algorithm not supported
    opened by vimalloc 21
  • RS256 Token Validation & Decoding using Public Key Not Working

    RS256 Token Validation & Decoding using Public Key Not Working "ValueError: Could not deserialize key data."

    I'm trying to validate Google's ID Tokens for user authentication on a web app. The id token can be decoded fine if I disable verification, but won't verify when I pass it the RSA256 Public Key. The Public Key in question is Base64urlUInt-Encoded (RFC 7518 Specification).

    The Entire Public Key Response

       "kty": "RSA",
       "alg": "RS256",
       "use": "sig",
       "kid": "8c9eb968f73744eaed421e48010142bce51a067f",
       "n": "uweJ3hFY9wqZ6ZG-iSNhQwHtKCGl8G_jcQgGPjOrS-Rum3dyDjicqkAyfS8XDn480KD_TZ5m-lqBjqfimePu2_cH4URDPIwsqSzJI2_piEhaqnXRptIe5YB5imAL6iETKaOPjw284Fc7EdHK-ekHMn3AXjsy9AIErwAVw4-4ZXXwHbyQXJy1DyUB4ZzxiEvw_qkQmLdltmrNkLOw-Xh-C9UkTZ9NA58bYPBnxLwnAu_ggw_g_-hCAs6OvXZbAfFHhIGBLyjtdDLVrfXo1112QREB9d5sEds0bKZtJcD9afl4E7Ht6G-g3jNP2clAu6-6B-cIe4-j8Ph1uJDPkAmDfw",
       "e": "AQAB"

    According to the Specification I linked above, the "n" parameter is the Modulus, and the "e" parameter is the exponent. I've tried absolutely every combination of decoding these to common Base64 format, but no matter what I do, pyJWT doesn't like it.

    Expected Result

    A Verified, decoded JSON data packet.

    Actual Result

    Traceback (most recent call last):
      File "/anaconda3/lib/python3.6/site-packages/jwt/algorithms.py", line 205, in prepare_key
        key = load_pem_private_key(key, password=None, backend=default_backend())
      File "/anaconda3/lib/python3.6/site-packages/cryptography/hazmat/primitives/serialization.py", line 20, in load_pem_private_key
        return backend.load_pem_private_key(data, password)
      File "/anaconda3/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1015, in load_pem_private_key
      File "/anaconda3/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1234, in _load_key
      File "/anaconda3/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1292, in _handle_key_loading_error
        raise ValueError("Could not deserialize key data.")
    ValueError: Could not deserialize key data.
    During handling of the above exception, another exception occurred:
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/anaconda3/lib/python3.6/site-packages/jwt/api_jwt.py", line 93, in decode
        jwt, key=key, algorithms=algorithms, options=options, **kwargs
      File "/anaconda3/lib/python3.6/site-packages/jwt/api_jws.py", line 157, in decode
        key, algorithms)
      File "/anaconda3/lib/python3.6/site-packages/jwt/api_jws.py", line 221, in _verify_signature
        key = alg_obj.prepare_key(key)
      File "/anaconda3/lib/python3.6/site-packages/jwt/algorithms.py", line 207, in prepare_key
        key = load_pem_public_key(key, backend=default_backend())
      File "/anaconda3/lib/python3.6/site-packages/cryptography/hazmat/primitives/serialization.py", line 24, in load_pem_public_key
        return backend.load_pem_public_key(data)
      File "/anaconda3/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1041, in load_pem_public_key
      File "/anaconda3/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1292, in _handle_key_loading_error
        raise ValueError("Could not deserialize key data.")
    ValueError: Could not deserialize key data.

    Reproduction Steps

    import jwt
    IDjwt = <my id_token here>  # Decoding this with verify=False works correctly, so the problem isn't with the ID Token
    GoogPubKey = b'uweJ3hFY9wqZ6ZG-iSNhQwHtKCGl8G_jcQgGPjOrS-Rum3dyDjicqkAyfS8XDn480KD_TZ5m-lqBjqfimePu2_cH4URDPIwsqSzJI2_piEhaqnXRptIe5YB5imAL6iETKaOPjw284Fc7EdHK-ekHMn3AXjsy9AIErwAVw4-4ZXXwHbyQXJy1DyUB4ZzxiEvw_qkQmLdltmrNkLOw-Xh-C9UkTZ9NA58bYPBnxLwnAu_ggw_g_-hCAs6OvXZbAfFHhIGBLyjtdDLVrfXo1112QREB9d5sEds0bKZtJcD9afl4E7Ht6G-g3jNP2clAu6-6B-cIe4-j8Ph1uJDPkAmDfw'
    #Convert to Base64 (replace '-', '_' with '+', '/', respectively, and pad with '=' to make multiple of 4)
    GoogPubKey = GoogPubKey.replace(b'-', b'+')
    GoogPubKey = GoogPubKey.replace(b'_', b'/')
    GoogPubKey += b'=='
    len(GoogPubKey) % 4  # 0
    GoogPubKey = b'-----BEGIN PUBLIC KEY-----\n' + GoogPubKey + b'\n-----END PUBLIC KEY-----'
    decoded = jwt.decode(IDjwt, GoogPubKey, algorithms='RS256')

    Again, I've tried over a dozen different ways of using this RSA Public Key Google supplies, but nothing works (Using Base64url like they provide, using or not using the 'BEGIN PUBLIC KEY' prefix/suffix, type bytes or str, adding the "AQAB" prefix in multiple places, nothing works)

    Any help would be greatly appreciated!! Thank you

    System Information

    $ python -m jwt.help
      "cryptography": {
        "version": "2.1.4"
      "implementation": {
        "name": "CPython",
        "version": "3.6.4"
      "platform": {
        "release": "17.4.0",
        "system": "Darwin"
      "pyjwt": {
        "version": "1.6.4"
    opened by tyrelkostyk 19
  • Fix the ECDSA signature serialization format

    Fix the ECDSA signature serialization format

    According to the JSON Web Algorithms Draft, section 3.4 the ECDSA signature should be serialized by concatenating the R and S values.

    The code was using ecdsa.util.sigencode_der, that encodes the signature using the DER serialization format, instead of using ecdsa.util.sigencode_string, that does exactly what the draft asks.

    opened by esneider 18
  • Fix type annotation for `decode()`/`encode()`'s parameter key

    Fix type annotation for `decode()`/`encode()`'s parameter key

    See #602 for details.

    The issue suggests that the parameter key should not accept str. I've not included this for backwards compatibility and because I'm not sure if that's really necessary.

    Closes jpadilla/pyjwt#602

    opened by michael-k 17
  • Add flexible and complete verification options

    Add flexible and complete verification options

    This adds the ability to use a more flexible option dictionary. The options dictionary can be specified at the PyJWT object level or as an override passed directly into decode()

    Attempts to fix #127

    opened by michaeldavis-wf 17
  • Invalid validation of audience claim

    Invalid validation of audience claim

    The spec at http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#audDef states:

    The aud (audience) claim identifies the recipients that the JWT is intended for. Each principal intended to process the JWT MUST identify itself with a value in the audience claim. If the principal processing the claim does not identify itself with a value in the aud claim when this claim is present, then the JWT MUST be rejected.

    As I understand it, Pyjwt doesn't seem to implement this requirement correctly. Basically it reverses the checks. Let me explain.

    Pyjwt only checks the audience claim when an audience=... arg was specified to decode(), meaning that any audience claim in the JWT is blindly ignored if no such arg was passed. This results in the JWT bein accepted, instead of being rejected. (Security problem!)

    Furthermore, the decode(audience=...) arg allows both a string and a list of strings, but the audience claim in the JWT payload is always assumed to be a single string, which is against the spec:

    In the general case, the aud value is an array of case-sensitive strings, each containing a StringOrURI value. In the special case when the JWT has one audience, the aud value MAY be a single case-sensitive string containing a StringOrURI value. The interpretation of audience values is generally application specific. Use of this claim is OPTIONAL.

    Offending code:

        if audience is not None:
            if isinstance(audience, list):
                audiences = audience
                audiences = [audience]
            if payload.get('aud') not in audiences:
                raise InvalidAudience('Invalid audience')

    Hopefully you understand what I meant when I said pyjwt "reverses" the checks.

    Let me know your thoughts; I can come up with a PR when we agree on the correct approach and understanding of the spec.

    opened by wbolster 17
  • AttributeError: '_RSAPrivateKey' object has no attribute 'sign'

    AttributeError: '_RSAPrivateKey' object has no attribute 'sign'

    When using a pair of RSA keys to try the example given in the docs:

    encoded = jwt.encode({'some': 'payload'}, private_key, algorithm='RS256')
    decoded = jwt.decode(encoded, public_key, algorithms='RS256')

    Expected Result

    I'm expecting to get both variables assigned without problem.

    Actual Result

    But what happens instead is that I'm getting:

    AttributeError: '_RSAPrivateKey' object has no attribute 'sign'

    Reproduction Steps

    import jwt
    private_key = open("private.pem").read()
    public_key = open("public.pem").read()
    encoded = jwt.encode({'some': 'payload'}, private_key, algorithm='RS256')
    decoded = jwt.decode(encoded, public_key, algorithms='RS256')

    System Information

    $ python -m jwt.help
      "cryptography": {
        "version": "1.3.2"
      "implementation": {
        "name": "CPython",
        "version": "3.5.1"
      "platform": {
        "release": "18.0.0",
        "system": "Darwin"
      "pyjwt": {
        "version": "1.6.4"

    This command is only available on PyJWT v1.6.3 and greater. Otherwise, please provide some basic information about your system.

    opened by benjamimo1 16
  • How do I detect an invalid token?

    How do I detect an invalid token?

    Suppose a hacker tries to pass a token to my server, that did not originate from my server. How do I detect when this happens?

    I am guessing that If the token was not something generated and signed with my key, then one of two things will happen:

    1. pyjwt will throw a JSONDecode error. jwt.decode won't even be able to decode the token, as the decryption algorithm will produce garbledygook.
    2. jwt.decode returns an object, but it won't have any of the expected keys (because, again, garbledygook) so any attempt to access an expected key will result in a KeyError.
    opened by moonman239 2
  • jwt.decode verifying against local time

    jwt.decode verifying against local time

    jwt_token = jwt.encode(payload={"exp": datetime.datetime.utcnow()}, key="secret")

    jwt.decode(jwt=jwt_token, key="secret", leewayTIme=120, algorithms=['HS256'])

    the last statement raises ExpiredSignatureError, but if I use datetime.datetime.now() insetead of utcnow(), it works and returns the decoded token.

    The documentation mentions that expiration time is compared against UTC timestamp.

    opened by duggalmayank 0
  • Version 2.6 breaks unit tests

    Version 2.6 breaks unit tests

    Framework used: Django 4.1.4 / Django Restframework 3.14.0 / Django Restframework SimpleJWT 5.2.2 pyjwt version: 2.6

    The following code works in pyjwt 2.5 but fails with pyjwt 2.6:

    from rest_framework.test import APIClient
    client = APIClient()
    client.login(username='username', password='pass')
    client.credentials(**self.create_headers('username')) # function returns the HTTP_AUTHORIZATION header
    client.post(url, data)
    # EXPECTED: status 201
    # ACTUAL: status 401

    Here is the error under pyjwt 2.6:

    {'detail': ErrorDetail(string='Given token not valid for any token type', code='token_not_valid'), 'code': ErrorDetail(string='token_not_valid', code='token_not_valid'), 'messages': [{'token_class': ErrorDetail(string='AccessToken', code='token_not_valid'), 'token_type': ErrorDetail(string='access', code='token_not_valid'), 'message': ErrorDetail(string='Token is invalid or expired', code='token_not_valid')}]}

    The release notes did not indicate a breaking change, am I missing something?

    opened by LukasKlement 0
  • CVE-2022-3602 and CVE-2022-3786 fixes in cryptography 38.0.3

    CVE-2022-3602 and CVE-2022-3786 fixes in cryptography 38.0.3

    Hey folks,

    You probably have already looked into this, but since I couldn't find any closed issues on this I decided to create this as more of an FYI.

    cryptography package was affected by CVE-2022-3602 and CVE-2022-3786 and they have addressed the issue in the v38.0.3 release.

    Since pyjwt is not pointing to a specific version of cryptography, installing pyjwt[crypto] pulls in the latest version of cryptography. So I think the risk here is minimal. Just wanted to let you know anyway. Do you think it is worth updating the minimum version of cryptography in dependencies? https://github.com/jpadilla/pyjwt/blob/300348f7bc4a520448b8fbefa525c9434e82141d/setup.cfg#L48

    opened by lahirumaramba 1
  • Allow custom headers to be set on JWKClient requests

    Allow custom headers to be set on JWKClient requests

    When using PyJWKClient to access a jwks server behind a firewall, I've run into problems with my request being denied due to the default Python-urllib/3.9 user agent.

    Would the maintainers entertain allowing users to specify a custom headers dictionary when creating the pyJWKClient that would automatically be set on fetch requests to retrieve the JWK? By allowing a generic header dictionary to be included, you could solve not only the user agent difficulties I've run into, but other use cases as well.

    Thank you!

    opened by thundercat1 1
  • very unhelpfull / missleading error messages on get_signing_key_from_jwt

    very unhelpfull / missleading error messages on get_signing_key_from_jwt


    I spend a few hours today for a bug that shouldn't have been there. I set up my python application where I recieve a jwt token from oauth-proxy, validate, decode and echo the contents. Running locally, everything went perfect. Running in a container I got the message "The JWK Set did not contain any usable keys". I checked, oauth configs, credentials, my code, put a few hours into trying to debug the python code while running in podman.

    Then after a few hours my colleague helped and ran the project on his machine. He got the same error. So what does his machine has not, that mine has? Dependencies.

    After another hour of debuging, we found out, that my jwt token is encoded with RSA. For pyjwt to decode the key we need to use RSA. To use RSA the cryptography is nessecary. I got this installed in my global dependencies and forgot to use an env.

    The thing is: Alls this could have been prevented, if the raised error message would be "found RSA - cannot decode because dependency cryptography is missing"

    Instead the error handling is as follows:

    api_jwk.py - PyJWKSet:

    class PyJWKSet:
        def __init__(self, keys: list[dict]) -> None:
            self.keys = []
            if not keys:
                raise PyJWKSetError("The JWK Set did not contain any keys")
            if not isinstance(keys, list):
                raise PyJWKSetError("Invalid JWK Set value")
            for key in keys:
                *except PyJWKError:*
                    # skip unusable keys
            if len(self.keys) == 0:
                raise PyJWKSetError("The JWK Set did not contain any usable keys")


    class PyJWK:
        def __init__(self, jwk_data, algorithm=None):
            self._algorithms = get_default_algorithms()


    ef get_default_algorithms():
        Returns the algorithms that are implemented by the library.
        default_algorithms = {
            "none": NoneAlgorithm(),
            "HS256": HMACAlgorithm(HMACAlgorithm.SHA256),
            "HS384": HMACAlgorithm(HMACAlgorithm.SHA384),
            "HS512": HMACAlgorithm(HMACAlgorithm.SHA512),
        if has_crypto:
                    "RS256": RSAAlgorithm(RSAAlgorithm.SHA256),

    and has_crypto comes from algorithms.py

        import cryptography.exceptions
    except ModuleNotFoundError:
        has_crypto = False

    As summary: You iterate through every key, looking if there is an algorithm, find that a dependecie is missing and skip this key, and buring the error message. Afterwards the length of the list of keys is 0 - you get the message of no usable keys and are none the wiser, why this is the case. please rework you try catch error flow, so that a developer knows when a dependency is missing for the current key!

    opened by julianhahn 5
  • 2.6.0(Oct 24, 2022)

    What's Changed

    • fix: version 2.5.0 heading typo by @c0state in https://github.com/jpadilla/pyjwt/pull/803
    • Remove types-cryptography from crypto extra by @lautat in https://github.com/jpadilla/pyjwt/pull/805
    • bump up cryptography >= 3.4.0 by @jpadilla in https://github.com/jpadilla/pyjwt/pull/807
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/798
    • Bump actions/stale from 5 to 6 by @dependabot in https://github.com/jpadilla/pyjwt/pull/808
    • Invalidate exp when exp == now() by @wcedmisten-reify in https://github.com/jpadilla/pyjwt/pull/797
    • Handling 'ImmatureSignatureError' for issued_at time by @sriharan16 in https://github.com/jpadilla/pyjwt/pull/794
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/810
    • Bump version to 2.6.0 by @jpadilla in https://github.com/jpadilla/pyjwt/pull/813

    New Contributors

    • @c0state made their first contribution in https://github.com/jpadilla/pyjwt/pull/803
    • @lautat made their first contribution in https://github.com/jpadilla/pyjwt/pull/805
    • @wcedmisten-reify made their first contribution in https://github.com/jpadilla/pyjwt/pull/797
    • @sriharan16 made their first contribution in https://github.com/jpadilla/pyjwt/pull/794

    Full Changelog: https://github.com/jpadilla/pyjwt/compare/2.5.0...2.6.0

    Source code(tar.gz)
    Source code(zip)
  • 2.5.0(Sep 17, 2022)

    What's Changed

    • Bump actions/checkout from 2 to 3 by @dependabot in https://github.com/jpadilla/pyjwt/pull/758
    • Bump codecov/codecov-action from 1 to 3 by @dependabot in https://github.com/jpadilla/pyjwt/pull/757
    • Bump actions/setup-python from 2 to 3 by @dependabot in https://github.com/jpadilla/pyjwt/pull/756
    • adding support for compressed payloads by @danieltmiles in https://github.com/jpadilla/pyjwt/pull/753
    • Revert "adding support for compressed payloads" by @auvipy in https://github.com/jpadilla/pyjwt/pull/761
    • Add to_jwk static method to ECAlgorithm by @leonsmith in https://github.com/jpadilla/pyjwt/pull/732
    • Remove redundant wheel dep from pyproject.toml by @mgorny in https://github.com/jpadilla/pyjwt/pull/765
    • Adjust expected exceptions in option merging tests for PyPy3 by @mgorny in https://github.com/jpadilla/pyjwt/pull/763
    • Do not fail when an unusable key occurs by @DaGuich in https://github.com/jpadilla/pyjwt/pull/762
    • Fixes for pyright on strict mode by @brandon-leapyear in https://github.com/jpadilla/pyjwt/pull/747
    • Bump actions/setup-python from 3 to 4 by @dependabot in https://github.com/jpadilla/pyjwt/pull/769
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/770
    • docs: fix simple typo, iinstance -> isinstance by @timgates42 in https://github.com/jpadilla/pyjwt/pull/774
    • Expose get_algorithm_by_name as new method by @sirosen in https://github.com/jpadilla/pyjwt/pull/773
    • Remove support for python3.6 by @sirosen in https://github.com/jpadilla/pyjwt/pull/777
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/778
    • Emit a deprecation warning for unsupported kwargs by @sirosen in https://github.com/jpadilla/pyjwt/pull/776
    • Fix typo: priot -> prior by @jdufresne in https://github.com/jpadilla/pyjwt/pull/780
    • Fix for headers disorder issue by @kadabusha in https://github.com/jpadilla/pyjwt/pull/721
    • Update audience typing by @JulianMaurin in https://github.com/jpadilla/pyjwt/pull/782
    • Improve PyJWKSet error accuracy by @JulianMaurin in https://github.com/jpadilla/pyjwt/pull/786
    • Add type hints to jwt/help.py and add missing types dependency by @kkirsche in https://github.com/jpadilla/pyjwt/pull/784
    • Add cacheing functionality for JWK set by @wuhaoyujerry in https://github.com/jpadilla/pyjwt/pull/781
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/788
    • Mypy as pre-commit check + api_jws typing by @JulianMaurin in https://github.com/jpadilla/pyjwt/pull/787
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/791
    • Bump version to 2.5.0 by @jpadilla in https://github.com/jpadilla/pyjwt/pull/801

    New Contributors

    • @dependabot made their first contribution in https://github.com/jpadilla/pyjwt/pull/758
    • @danieltmiles made their first contribution in https://github.com/jpadilla/pyjwt/pull/753
    • @leonsmith made their first contribution in https://github.com/jpadilla/pyjwt/pull/732
    • @mgorny made their first contribution in https://github.com/jpadilla/pyjwt/pull/765
    • @DaGuich made their first contribution in https://github.com/jpadilla/pyjwt/pull/762
    • @brandon-leapyear made their first contribution in https://github.com/jpadilla/pyjwt/pull/747
    • @sirosen made their first contribution in https://github.com/jpadilla/pyjwt/pull/773
    • @kadabusha made their first contribution in https://github.com/jpadilla/pyjwt/pull/721
    • @JulianMaurin made their first contribution in https://github.com/jpadilla/pyjwt/pull/782
    • @wuhaoyujerry made their first contribution in https://github.com/jpadilla/pyjwt/pull/781

    Full Changelog: https://github.com/jpadilla/pyjwt/compare/2.4.0...2.5.0

    Source code(tar.gz)
    Source code(zip)
  • 2.4.0(May 12, 2022)


    • [CVE-2022-29217] Prevent key confusion through non-blocklisted public key formats. https://github.com/jpadilla/pyjwt/security/advisories/GHSA-ffqj-6fqr-9h24

    What's Changed

    • Add support for Python 3.10 by @hugovk in https://github.com/jpadilla/pyjwt/pull/699
    • Don't use implicit optionals by @rekyungmin in https://github.com/jpadilla/pyjwt/pull/705
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/708
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/710
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/711
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/712
    • documentation fix: show correct scope for decode_complete() by @sseering in https://github.com/jpadilla/pyjwt/pull/661
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/716
    • Explicit check the key for ECAlgorithm by @estin in https://github.com/jpadilla/pyjwt/pull/713
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/720
    • api_jwk: Add PyJWKSet.getitem by @woodruffw in https://github.com/jpadilla/pyjwt/pull/725
    • Update usage.rst by @guneybilen in https://github.com/jpadilla/pyjwt/pull/727
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/728
    • fix: Update copyright information by @kkirsche in https://github.com/jpadilla/pyjwt/pull/729
    • Docs: mention performance reasons for reusing RSAPrivateKey when encoding by @dmahr1 in https://github.com/jpadilla/pyjwt/pull/734
    • Fixed typo in usage.rst by @israelabraham in https://github.com/jpadilla/pyjwt/pull/738
    • Add detached payload support for JWS encoding and decoding by @fviard in https://github.com/jpadilla/pyjwt/pull/723
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/740
    • Raise DeprecationWarning for jwt.decode(verify=...) by @akx in https://github.com/jpadilla/pyjwt/pull/742
    • Don't mutate options dictionary in .decode_complete() by @akx in https://github.com/jpadilla/pyjwt/pull/743
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/748
    • Replace various string interpolations with f-strings by @akx in https://github.com/jpadilla/pyjwt/pull/744
    • Update CHANGELOG.rst by @hipertracker in https://github.com/jpadilla/pyjwt/pull/751

    New Contributors

    • @hugovk made their first contribution in https://github.com/jpadilla/pyjwt/pull/699
    • @rekyungmin made their first contribution in https://github.com/jpadilla/pyjwt/pull/705
    • @sseering made their first contribution in https://github.com/jpadilla/pyjwt/pull/661
    • @estin made their first contribution in https://github.com/jpadilla/pyjwt/pull/713
    • @woodruffw made their first contribution in https://github.com/jpadilla/pyjwt/pull/725
    • @guneybilen made their first contribution in https://github.com/jpadilla/pyjwt/pull/727
    • @dmahr1 made their first contribution in https://github.com/jpadilla/pyjwt/pull/734
    • @israelabraham made their first contribution in https://github.com/jpadilla/pyjwt/pull/738
    • @fviard made their first contribution in https://github.com/jpadilla/pyjwt/pull/723
    • @akx made their first contribution in https://github.com/jpadilla/pyjwt/pull/742
    • @hipertracker made their first contribution in https://github.com/jpadilla/pyjwt/pull/751

    Full Changelog: https://github.com/jpadilla/pyjwt/compare/2.3.0...2.4.0

    Source code(tar.gz)
    Source code(zip)
  • 2.3.0(Oct 18, 2021)

    What's Changed

    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/700
    • Add exception chaining by @ehdgua01 in https://github.com/jpadilla/pyjwt/pull/702
    • Revert "Remove arbitrary kwargs." by @auvipy in https://github.com/jpadilla/pyjwt/pull/701
    • Bump up version to v2.3.0 by @jpadilla in https://github.com/jpadilla/pyjwt/pull/703

    New Contributors

    • @ehdgua01 made their first contribution in https://github.com/jpadilla/pyjwt/pull/702
    • @auvipy made their first contribution in https://github.com/jpadilla/pyjwt/pull/701

    Full Changelog: https://github.com/jpadilla/pyjwt/compare/2.2.0...2.3.0

    Source code(tar.gz)
    Source code(zip)
  • 2.2.0(Oct 6, 2021)

    What's Changed

    • Complete jwt documentation by @johachi in https://github.com/jpadilla/pyjwt/pull/654
    • Ignore coverage files generated during test runs by @makusu2 in https://github.com/jpadilla/pyjwt/pull/617
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/656
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/658
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/667
    • Fix aud validation to support {'aud': null} case. by @dajiaji in https://github.com/jpadilla/pyjwt/pull/670
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/678
    • Prefer headers['alg'] to algorithm parameter in encode(). by @dajiaji in https://github.com/jpadilla/pyjwt/pull/673
    • DOC: Clarify RSA encoding and decoding depend on the cryptography package by @TPXP in https://github.com/jpadilla/pyjwt/pull/664
    • Make typ optional by @dajiaji in https://github.com/jpadilla/pyjwt/pull/644
    • Remove arbitrary kwargs. by @dajiaji in https://github.com/jpadilla/pyjwt/pull/657
    • Assume JWK is valid for signing if "use" is omitted by @Klavionik in https://github.com/jpadilla/pyjwt/pull/668
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/684
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/686
    • [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci in https://github.com/jpadilla/pyjwt/pull/689
    • Remove upper bound on cryptography version by @riconnon in https://github.com/jpadilla/pyjwt/pull/693
    • Add support for Ed448/EdDSA. by @dajiaji in https://github.com/jpadilla/pyjwt/pull/675
    • Chore: inline Variables that immediately Returned by @yezz123 in https://github.com/jpadilla/pyjwt/pull/690
    • Use timezone package as Python 3.5+ is required by @kkirsche in https://github.com/jpadilla/pyjwt/pull/694
    • Bump up version to v2.2.0 by @jpadilla in https://github.com/jpadilla/pyjwt/pull/697

    New Contributors

    • @TPXP made their first contribution in https://github.com/jpadilla/pyjwt/pull/664
    • @Klavionik made their first contribution in https://github.com/jpadilla/pyjwt/pull/668
    • @riconnon made their first contribution in https://github.com/jpadilla/pyjwt/pull/693
    • @yezz123 made their first contribution in https://github.com/jpadilla/pyjwt/pull/690
    • @kkirsche made their first contribution in https://github.com/jpadilla/pyjwt/pull/694

    Full Changelog: https://github.com/jpadilla/pyjwt/compare/2.1.0...2.2.0

    Source code(tar.gz)
    Source code(zip)
  • 2.1.0(Apr 28, 2021)



    • Allow claims validation without making JWT signature validation mandatory. #608


    • Remove padding from JWK test data. #628
    • Make kty mandatory in JWK to be compliant with RFC7517. #624
    • Allow JWK without alg to be compliant with RFC7517. #624
    • Allow to verify with private key on ECAlgorithm, as well as on Ed25519Algorithm. #645


    • Add caching by default to PyJWKClient #611
    • Add missing exceptions.InvalidKeyError to jwt module __init__ imports #620
    • Add support for ES256K algorithm #629
    • Add from_jwk() to Ed25519Algorithm #621
    • Add to_jwk() to Ed25519Algorithm #643
    • Export PyJWK and PyJWKSet #652
    Source code(tar.gz)
    Source code(zip)
  • 2.0.1(Jan 17, 2021)

  • 2.0.0(Dec 22, 2020)


    Introduce better experience for JWKs

    Introduce PyJWK, PyJWKSet, and PyJWKClient.

    import jwt
    from jwt import PyJWKClient
    token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FRTFRVVJCT1RNNE16STVSa0ZETlRZeE9UVTFNRGcyT0Rnd1EwVXpNVGsxUWpZeVJrUkZRdyJ9.eyJpc3MiOiJodHRwczovL2Rldi04N2V2eDlydS5hdXRoMC5jb20vIiwic3ViIjoiYVc0Q2NhNzl4UmVMV1V6MGFFMkg2a0QwTzNjWEJWdENAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZXhwZW5zZXMtYXBpIiwiaWF0IjoxNTcyMDA2OTU0LCJleHAiOjE1NzIwMDY5NjQsImF6cCI6ImFXNENjYTc5eFJlTFdVejBhRTJINmtEME8zY1hCVnRDIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.PUxE7xn52aTCohGiWoSdMBZGiYAHwE5FYie0Y1qUT68IHSTXwXVd6hn02HTah6epvHHVKA2FqcFZ4GGv5VTHEvYpeggiiZMgbxFrmTEY0csL6VNkX1eaJGcuehwQCRBKRLL3zKmA5IKGy5GeUnIbpPHLHDxr-GXvgFzsdsyWlVQvPX2xjeaQ217r2PtxDeqjlf66UYl6oY6AqNS8DH3iryCvIfCcybRZkc_hdy-6ZMoKT6Piijvk_aXdm7-QQqKJFHLuEqrVSOuBqqiNfVrG27QzAPuPOxvfXTVLXL2jek5meH6n-VWgrBdoMFH93QEszEDowDAEhQPHVs0xj7SIzA"
    url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json"
    jwks_client = PyJWKClient(url)
    signing_key = jwks_client.get_signing_key_from_jwt(token)
    data = jwt.decode(
        options={"verify_exp": False},

    Support for JWKs containing ECDSA keys

    Drop support for Python 2

    Require cryptography >= 3

    Drop support for PyCrypto and ECDSA

    We've kept this around for a long time, mostly for environments that didn't allow installing cryptography.

    Drop CLI

    Dropped the included cli entry point.

    Improve typings

    We no longer need to use mypy Python 2 compatibility mode (comments)

    Add support for Ed25519 / EdDSA


    • Add PyPy3 to the test matrix (#550) by @jdufresne
    • Require tweak (#280) by @psafont
    • Decode return type is dict[str, Any] (#393) by @jacopofar
    • Fix linter error in test_cli (#414) by @jaraco
    • Run mypy with tox (#421) by @jpadilla
    • Document (and prefer) pyjwt[crypto] req format (#426) by @gthb
    • Correct type for json_encoder argument (#438) by @jdufresne
    • Prefer https:// links where available (#439) by @jdufresne
    • Pass python_requires argument to setuptools (#440) by @jdufresne
    • Rename [wheel] section to [bdist_wheel] as the former is legacy (#441) by @jdufresne
    • Remove setup.py test command in favor of pytest and tox (#442) by @jdufresne
    • Fix mypy errors (#449) by @jpadilla
    • DX Tweaks (#450) by @jpadilla
    • Add support of python 3.8 (#452) by @Djailla
    • Fix 406 (#454) by @justinbaur
    • Add support for Ed25519 / EdDSA, with unit tests (#455) by @Someguy123
    • Remove Python 2.7 compatibility (#457) by @Djailla
    • Fix simple typo: encododed -> encoded (#462) by @timgates42
    • Enhance tracebacks. (#477) by @JulienPalard
    • Simplify python_requires (#478) by @michael-k
    • Document top-level .encode and .decode to close #459 (#482) by @dimaqq
    • Improve documentation for audience usage (#484) by @CorreyL
    • Correct README on how to run tests locally (#489) by @jdufresne
    • Fix tox -e lint warnings and errors (#490) by @jdufresne
    • Run pyupgrade across project to use modern Python 3 conventions (#491) by @jdufresne
    • Add Python-3-only trove classifier and remove "universal" from wheel (#492) by @jdufresne
    • Emit warnings about user code, not pyjwt code (#494) by @mgedmin
    • Move setup information to declarative setup.cfg (#495) by @jdufresne
    • CLI options for verifying audience and issuer (#496) by @GeoffRichards
    • Specify the target Python version for mypy (#497) by @jdufresne
    • Remove unnecessary compatibility shims for Python 2 (#498) by @jdufresne
    • Setup GH Actions (#499) by @jpadilla
    • Implementation of ECAlgorithm.from_jwk (#500) by @jpadilla
    • Remove cli entry point (#501) by @jpadilla
    • Expose InvalidKeyError on jwt module (#503) by @russellcardullo
    • Avoid loading token twice in pyjwt.decode (#506) by @CaselIT
    • Default links to stable version of documentation (#508) by @salcedo
    • Update README.md badges (#510) by @jpadilla
    • Introduce better experience for JWKs (#511) by @jpadilla
    • Fix tox conditional extras (#512) by @jpadilla
    • Return tokens as string not bytes (#513) by @jpadilla
    • Drop support for legacy contrib algorithms (#514) by @jpadilla
    • Drop deprecation warnings (#515) by @jpadilla
    • Update Auth0 sponsorship link (#519) by @Sambego
    • Update return type for jwt.encode (#521) by @moomoolive
    • Run tests against Python 3.9 and add trove classifier (#522) by @michael-k
    • Removed redundant default_backend() (#523) by @rohitkg98
    • Documents how to use private keys with passphrases (#525) by @rayluo
    • Update version to 2.0.0a1 (#528) by @jpadilla
    • Fix usage example (#530) by @nijel
    • add EdDSA to docs (#531) by @CircleOnCircles
    • Remove support for EOL Python 3.5 (#532) by @jdufresne
    • Upgrade to isort 5 and adjust configurations (#533) by @jdufresne
    • Remove unused argument "verify" from PyJWS.decode() (#534) by @jdufresne
    • Update typing syntax and usage for Python 3.6+ (#535) by @jdufresne
    • Run pyupgrade to simplify code and use Python 3.6 syntax (#536) by @jdufresne
    • Drop unknown pytest config option: strict (#537) by @jdufresne
    • Upgrade black version and usage (#538) by @jdufresne
    • Remove "Command line" sections from docs (#539) by @jdufresne
    • Use existing key_path() utility function throughout tests (#540) by @jdufresne
    • Replace force_bytes()/force_unicode() in tests with literals (#541) by @jdufresne
    • Remove unnecessary Unicode decoding before json.loads() (#542) by @jdufresne
    • Remove unnecessary force_bytes() calls priot to base64url_decode() (#543) by @jdufresne
    • Remove deprecated arguments from docs (#544) by @jdufresne
    • Update code blocks in docs (#545) by @jdufresne
    • Refactor jwt/jwks_client.py without requests dependency (#546) by @jdufresne
    • Tighten bytes/str boundaries and remove unnecessary coercing (#547) by @jdufresne
    • Replace codecs.open() with builtin open() (#548) by @jdufresne
    • Replace int_from_bytes() with builtin int.from_bytes() (#549) by @jdufresne
    • Enforce .encode() return type using mypy (#551) by @jdufresne
    • Prefer direct indexing over options.get() (#552) by @jdufresne
    • Cleanup "noqa" comments (#553) by @jdufresne
    • Replace merge_dict() with builtin dict unpacking generalizations (#555) by @jdufresne
    • Do not mutate the input payload in PyJWT.encode() (#557) by @jdufresne
    • Use direct indexing in PyJWKClient.get_signing_key_from_jwt() (#558) by @jdufresne
    • Split PyJWT/PyJWS classes to tighten type interfaces (#559) by @jdufresne
    • Simplify mocked_response test utility function (#560) by @jdufresne
    • Autoupdate pre-commit hooks and apply them (#561) by @jdufresne
    • Remove unused argument "payload" from PyJWS._verify_signature() (#562) by @jdufresne
    • Add utility functions to assist test skipping (#563) by @jdufresne
    • Type hint jwt.utils module (#564) by @jdufresne
    • Prefer ModuleNotFoundError over ImportError (#565) by @jdufresne
    • Fix tox "manifest" environment to pass (#566) by @jdufresne
    • Fix tox "docs" environment to pass (#567) by @jdufresne
    • Simplify black configuration to be closer to upstream defaults (#568) by @jdufresne
    • Use generator expressions (#569) by @jdufresne
    • Simplify from_base64url_uint() (#570) by @jdufresne
    • Drop lint environment from GitHub actions in favor of pre-commit.ci (#571) by @jdufresne
    • [pre-commit.ci] pre-commit autoupdate (#572)
    • Simplify tox configuration (#573) by @jdufresne
    • Combine identical test functions using pytest.mark.parametrize() (#574) by @jdufresne
    • Complete type hinting of jwks_client.py (#578) by @jdufresne

    Thanks to all that helped made this release happen one way or another. Special shout out to @jdufresne for all the amazing work getting this project into tip-top shape.

    Source code(tar.gz)
    Source code(zip)
  • 2.0.0a2(Dec 20, 2020)

  • 1.7.1(Dec 7, 2018)


    • Update test dependencies with pinned ranges (b65e1ac6dc4d11801f3642eaab34ae6a54162c18)
    • Fix pytest deprecation warnings (b65e1ac6dc4d11801f3642eaab34ae6a54162c18)
    Source code(tar.gz)
    Source code(zip)
  • 1.7.0(Dec 2, 2018)

  • 1.6.4(May 24, 2018)

  • 1.6.3(May 19, 2018)

    Note: I accidentally published v1.6.2 and removed it from PyPI, that's why the jump to v1.6.3


    • All exceptions inherit from PyJWTError #340


    • Add type hints #344
    • Add help module 7ca41e53b3d7d9f5cd31bdd8a2b832d192006239


    • Added section to usage docs for jwt.get_unverified_header() #350
    • Update legacy instructions for using pycrypto #337
    Source code(tar.gz)
    Source code(zip)
  • 1.6.1(Mar 18, 2018)

  • 1.6.0(Mar 3, 2018)


    • Dropped support for python 2.6 and 3.3 #301
    • An invalid signature now raises an InvalidSignatureError instead of DecodeError #316


    • Fix over-eager fallback to stdin #304


    • Audience parameter now supports iterables #306
    Source code(tar.gz)
    Source code(zip)
  • 1.5.3(Sep 5, 2017)


    • Increase required version of the cryptography package to >=1.4.0.


    • Remove uses of deprecated functions from the cryptography package.
    • Warn about missing algorithms param to decode() only when verify param is True #281
    Source code(tar.gz)
    Source code(zip)
  • 1.5.2(Jun 22, 2017)

  • 1.5.1(Jun 22, 2017)


    • Change optparse for argparse. #238


    • Guard against PKCS1 PEM encododed public keys #277
    • Add deprecation warning when decoding without specifying algorithms #277
    • Improve deprecation messages #270
    • PyJWT.decode: move verify param into options #271


    • Support for Python 3.6 #262
    • Expose jwt.InvalidAlgorithmError #264
    Source code(tar.gz)
    Source code(zip)
  • 1.5.0(Apr 19, 2017)


    • Add support for ECDSA public keys in RFC 4253 (OpenSSH) format #244
    • Renamed commandline script jwt to jwt-cli to avoid issues with the script clobbering the jwt module in some circumstances. #187
    • Better error messages when using an algorithm that requires the cryptography package, but it isn't available #230
    • Tokens with future 'iat' values are no longer rejected #190
    • Non-numeric 'iat' values now raise InvalidIssuedAtError instead of DecodeError
    • Remove rejection of future 'iat' claims #252


    • Add back 'ES512' for backward compatibility (for now) #225
    • Fix incorrectly named ECDSA algorithm #219
    • Fix rpm build #196


    • Add JWK support for HMAC and RSA keys #202
    Source code(tar.gz)
    Source code(zip)
  • 1.4.2(Aug 8, 2016)

  • 1.3.0(May 23, 2015)


    • ECDSA (ES256, ES384, ES512) signatures are now being properly serialized [#158][
    • RSA-PSS (PS256, PS384, PS512) signatures now use the proper salt length for PSS padding. [#163]


    • Added a new jwt.get_unverified_header() to parse and return the header portion of a token prior to signature verification.


    • Python 3.2 is no longer a supported platform. This version of Python is rarely used. Users affected by this should upgrade to 3.3+.
    Source code(tar.gz)
    Source code(zip)
  • 1.2.0(May 23, 2015)


    • Added back verify_expiration= argument to jwt.decode() that was erroneously removed in 1.1.0.


    • Refactored JWS-specific logic out of PyJWT and into PyJWS superclass. [#141]


    • verify_expiration= argument to jwt.decode() is now deprecated and will be removed in a future version. Use the option= argument instead.
    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(May 22, 2015)


    • Added support for PS256, PS384, and PS512 algorithms. [#132]
    • Added flexible and complete verification options during decode. [#131]
    • Added this CHANGELOG.md file.


    • Deprecated usage of the .decode(..., verify=False) parameter.


    • Fixed command line encoding. [#128]
    Source code(tar.gz)
    Source code(zip)
  • 1.0.1(Apr 2, 2015)

  • 1.0.0(Mar 18, 2015)


    • [CLEANUP] Removed api.header. #85
    • [DOCS] README details how to extract public / private keys from an x509 certificate. #100
    • [ENHANCEMENT] Refactor api.py functions into an object (PyJWT). #101
    • [ENHANCEMENT] Support PyCrypto and ecdsa when cryptography isn't available. #103
    • [SECURITY] Added some fixes related to algorithm and key choice. #109
    • [SECURITY] Added support for whitelist validation of the alg header. #110


    A security researcher has notified JSON Web Token library maintainers about a number of vulnerabilities allowing attackers to bypass the verification step. Read more about some of this issues here.

    This release fixes the vulnerabilities reported, continue reading for details.

    None algorithm

    Applies if you

    • rely on and do not validate the alg field in the token header.
    • implement the "none" algorithm.


    Attackers can craft a malicious token containing an arbitrary payload that passes the verification step.


    Create a token with the header {"typ":"JWT","alg":"none"}. Include any payload. Do not include a signature (i.e. the token should end with a period). Note: some implementations include some basic but insufficient checking for a missing signature -- some minor fiddling may be required to produce an exploit.

    Asymmetric key of a token signed with a symmetric key

    Applies if you

    • rely on and do not validate the alg field in the token header.
    • implement at least one of the HMAC algorithms and at least one of the asymmetric algorithms (e.g. HS256 and RS256).


    If the system is expecting a token signed with one of the asymmetric algorithms, an attacker can bypass the verification step by knowing only the public key.


    Create an HS256 token. Generate the HMAC signature using the literal bytes of the public key file (often in the PEM format). This will confuse the implementation into interpreting the public key file as an HMAC key.

    This release was possible thanks to the awesome @mark-adams.

    Source code(tar.gz)
    Source code(zip)
  • 0.4.2(Feb 18, 2015)

  • 0.4.1(Jan 8, 2015)

    • [Fix] Invalid validation of audience claim. #72
    • [Enhancement] Verify that decoded header and payload are JSON objects. #66
    • [Enhancement] Use constant time string comparison routine from hmac module. #64
    • [Enhancement] Add base exception InvalidTokenError for invalid tokens. #60
    • [Enhancement] Allow datetime.timedelta for leeway argument. #56

    Pending Deprecation

    The following exceptions have been marked for deprecation in favor of a renamed one to follow a better convention and will be removed in the next major version release.

    • ExpiredSignature will be deprecated in favor of ExpiredSignatureError.
    • InvalidAudience will be deprecated in favor of InvalidAudienceError.
    • InvalidIssuer will be deprecated in favor of InvalidIssuerError.

    Thanks to @mark-adams and @wbolster for all the work and feedback that went into this release.

    Source code(tar.gz)
    Source code(zip)
  • 0.4.0(Dec 23, 2014)

  • 0.3.2(Dec 13, 2014)

    Allow using a custom JSON encoder in jwt.encode()

    PR #49 by @defyrlt Ref #37


    import json
    import decimal
    import jwt
    class CustomJSONEncoder(json.JSONEncoder):
        def default(self, o):
            if isinstance(o, decimal.Decimal):
                return float(o)
            return super(CustomJSONEncoder, self).default(o)
    data = {
        'some_decimal': decimal.Decimal('2.2')
    token = jwt.encode(data, 'secret', json_encoder=CustomJSONEncoder)
    Source code(tar.gz)
    Source code(zip)
José Padilla
@auth0 + @filepreviews
José Padilla
Simple yet powerful authorization / authentication client library for Python web applications.

Authomatic Authomatic is a framework agnostic library for Python web applications with a minimalistic but powerful interface which simplifies authenti

1k Dec 28, 2022
Authentication Module for django rest auth

django-rest-knox Authentication Module for django rest auth Knox provides easy to use authentication for Django REST Framework The aim is to allow for

James McMahon 878 Jan 04, 2023
A Python inplementation for OAuth2

OAuth2-Python Discord Inplementation for OAuth2 login systems. This is a simple Python 'app' made to inplement in your programs that require (shitty)

Prifixy 0 Jan 06, 2022
Official implementation of the AAAI 2022 paper "Learning Token-based Representation for Image Retrieval"

Token: Token-based Representation for Image Retrieval PyTorch training code for Token-based Representation for Image Retrieval. We propose a joint loc

Hui Wu 42 Dec 06, 2022
This Python based program checks your CC Stripe Auth 1$ Based Checker

CC-Checker This Python based program checks your CC Stripe Auth 1$ Based Checker About Author Coded by xBlackx Reach Me On Telegram @xBlackx_Coder jOI

xBlackxCoder 11 Nov 20, 2022
A Python package, that allows you to acquire your RecNet authorization bearer token with your account credentials!

RecNet-Login This is a Python package, that allows you to acquire your RecNet bearer token with your account credentials! Installation Done via git: p

Jesse 6 Aug 18, 2022
Django Admin Two-Factor Authentication, allows you to login django admin with google authenticator.

Django Admin Two-Factor Authentication Django Admin Two-Factor Authentication, allows you to login django admin with google authenticator. Why Django

Iman Karimi 9 Dec 07, 2022
A generic, spec-compliant, thorough implementation of the OAuth request-signing logic

OAuthLib - Python Framework for OAuth1 & OAuth2 *A generic, spec-compliant, thorough implementation of the OAuth request-signing logic for Python 3.5+

OAuthlib 2.5k Jan 01, 2023
Out-of-the-box support register, sign in, email verification and password recovery workflows for websites based on Django and MongoDB

Using djmongoauth What is it? djmongoauth provides out-of-the-box support for basic user management and additional operations including user registrat

hao 3 Oct 21, 2021
Generate payloads that force authentication against an attacker machine

Hashgrab Generates scf, url & lnk payloads to put onto a smb share. These force authentication to an attacker machine in order to grab hashes (for exa

xct 35 Dec 20, 2022
Phishing Abusing Microsoft 365 OAuth Authorization Flow

Microsoft365_devicePhish Abusing Microsoft 365 OAuth Authorization Flow for Phishing Attack This is a simple proof-of-concept script that allows an at

bigb0ss 11 Dec 11, 2022
Skit-auth - Authorization for skit.ai's platform

skit-auth This is a simple authentication library for Skit's platform. Provides

Skit 3 Jan 08, 2022
python-social-auth and oauth2 support for django-rest-framework

Django REST Framework Social OAuth2 This module provides OAuth2 social authentication support for applications in Django REST Framework. The aim of th

1k Dec 22, 2022
Implements authentication and authorization as FastAPI dependencies

FastAPI Security Implements authentication and authorization as dependencies in FastAPI. Features Authentication via JWT-based OAuth 2 access tokens a

Jacob Magnusson 111 Jan 07, 2023
Toolkit for Pyramid, a Pylons Project, to add Authentication and Authorization using Velruse (OAuth) and/or a local database, CSRF, ReCaptcha, Sessions, Flash messages and I18N

Apex Authentication, Form Library, I18N/L10N, Flash Message Template (not associated with Pyramid, a Pylons project) Uses alchemy Authentication Authe

95 Nov 28, 2022
Get inside your stronghold and make all your Django views default login_required

Stronghold Get inside your stronghold and make all your Django views default login_required Stronghold is a very small and easy to use django app that

Mike Grouchy 384 Nov 23, 2022
Two factor authentication system using azure services and python language and its api's


The ultimate Python library in building OAuth, OpenID Connect clients and servers. JWS,JWE,JWK,JWA,JWT included.

Authlib The ultimate Python library in building OAuth and OpenID Connect servers. JWS, JWK, JWA, JWT are included. Authlib is compatible with Python2.

Hsiaoming Yang 3.4k Jan 04, 2023
OAuthlib support for Python-Requests!

Requests-OAuthlib This project provides first-class OAuth library support for Requests. The OAuth 1 workflow OAuth 1 can seem overly complicated and i

1.6k Dec 28, 2022
OAuth2 goodies for the Djangonauts!

Django OAuth Toolkit OAuth2 goodies for the Djangonauts! If you are facing one or more of the following: Your Django app exposes a web API you want to

Jazzband 2.7k Jan 01, 2023