{ "info": { "author": "Bastian Meyer", "author_email": "bastian@bastianmeyer.eu", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8" ], "description": "# EasyJWT\n\n[![PyPI](https://img.shields.io/pypi/v/easyjwt.svg)](https://pypi.org/project/easyjwt/)\n[![PyPI - License](https://img.shields.io/pypi/l/easyjwt.svg)](https://github.com/BMeu/EasyJWT/blob/master/LICENSE)\n[![Build Status](https://travis-ci.org/BMeu/EasyJWT.svg?branch=master)](https://travis-ci.org/BMeu/EasyJWT)\n[![codecov](https://codecov.io/gh/BMeu/EasyJWT/branch/master/graph/badge.svg)](https://codecov.io/gh/BMeu/EasyJWT)\n[![Documentation Status](https://readthedocs.org/projects/easyjwt/badge/?version=latest)](https://easyjwt.readthedocs.io/en/latest/?badge=latest)\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/easyjwt.svg)\n\nEasyJWT provides a simple interface to creating and verifying\n[JSON Web Tokens (JWTs)](https://tools.ietf.org/html/rfc7519) in Python. It allows you to once define the claims of the\nJWT, and to then create and accept tokens with these claims without having to check if all the required data is given\nor if the token actually is the one you expect.\n\n```python\nfrom easyjwt import EasyJWT\n\n# Define the claims of your token.\nclass MySuperSimpleJWT(EasyJWT):\n\n def __init__(self, key):\n super().__init__(key)\n\n # Define a claim `name`.\n self.name = None\n\n# Create a token with some values.\ntoken_object = MySuperSimpleJWT('Super secret key')\ntoken_object.name = 'Zaphod Beeblebrox'\ntoken = token_object.create()\n\n# Verify the created token.\nverified_token_object = MySuperSimpleJWT.verify(token, 'Super secret key')\nassert verified_token_object.name == 'Zaphod Beeblebrox'\n```\n\n## Features\n\n * Define the claims of your token once as a class, then use this class to easily create and verify multiple tokens.\n * No worries about typos in dictionary keys: the definition of your claim set as a class enables IDEs to find those\n typos for you.\n * Multiple tokens may have the same claims, but different intentions. EasyJWT will take care of this for you: you can\n define a token for account validation and one for account deletion, both with the account ID as a claim, and you\n don't need to worry about accidentally deleting a newly created account instead of validating it, just because\n someone mixed up the tokens.\n * Tokens will be rejected if mandatory claims are missing or unexpected claims are included.\n * You can define optional claims for your tokens.\n * All registered JWT claims are supported: `aud`, `exp`, `iat`, `iss`, `jti`, `nbf`, and `sub`.\n\n## System Requirements & Installation\n\nEasyJWT requires Python 3.6 or newer.\n\nEasyJWT is available [on PyPI](https://pypi.org/project/easyjwt/). You can install it using your favorite package\nmanager.\n\n * PIP:\n\n ```bash\n python -m pip install easyjwt\n ```\n\n * Pipenv:\n\n ```bash\n pipenv install easyjwt\n ```\n\n## Usage\n\nBefore you can create tokens, you need to define the claims that your token will have. You do this by creating a token\nclass that inherits from `EasyJWT`. In its `__init__` method, you specify the claims of your token, simply by defining\nattributes with the name of your claims. EasyJWT will consider all attributes to be claims, unless they start with an\nunderscore `_`. Remember to call the `__init__` method on the parent class to correctly initialize the objects of your\nclass.\n\n```python\nfrom easyjwt import EasyJWT\n\nclass MySuperSimpleJWT(EasyJWT):\n\n def __init__(self, key):\n super().__init__(key)\n\n # These are the claims of your token: `name` and `email`.\n self.name = None\n self.email = None\n\n # This attribute will not become a claim since it starts with an underscore.\n self._not_an_attribute = True\n```\n\nYou can now create the actual token by instantiating your class with the key with which the token will be encoded,\nsetting your values on this token object, and then calling EasyJWT's `create` method.\n\n```python\ntoken_object = MySuperSimpleJWT('Super secret key')\ntoken_object.name = 'Zaphod Beeblebrox'\ntoken_object.email = 'elprez@universe.gov'\n\ntoken = token_object.create()\n```\n\nIf you forget to set the value of one your claims, the creation will fail with an `MissingRequiredClaimsError`\nexception (see below for information on how to define [optional claims](#optional-claims)).\n\nOnce you receive a token to verify, you simply pass it and the key with which it has been encoded to EasyJWT's `verify`\nmethod. If the token is valid, the returned object will contain the values of the token.\n\n```python\nverified_token_object = MySuperSimpleJWT.verify(token, 'Super secret key')\n\nassert verified_token_object.name == 'Zaphod Beeblebrox'\nassert verified_token_object.email == 'elprez@universe.gov'\n```\n\nIf you try to verify a token that is missing one or more of the claims specified in your token class, or it includes one\nor more claims that you did not specify in your token class, the verification will fail by raising an\n`InvalidClaimSetError` exception. Thus, you always know that the data you expect in the token will in fact be present.\n\nThe neat thing about EasyJWT is: it knows with which class a token has been created, and will only accept tokens if they\nhave been created with the class with which you are trying to verify it ([see below](#accepting-third-party-tokens)\nfor more information and how to disable this behavior). Thus, you can have multiple token classes with the same claims,\nbut different contexts, and you don't have to worry about mixing up their tokens!\n\n```python\nfrom easyjwt import EasyJWT\n\nclass AccountValidationToken(EasyJWT):\n \"\"\" Validate the newly created user account with the specified ID. \"\"\"\n\n def __init__(self, key):\n super().__init__(key)\n\n self.user_id = None\n\nclass AccountDeletionToken(EasyJWT):\n \"\"\" Delete the user account with the specified ID. \"\"\"\n\n def __init__(self, key):\n super().__init__(key)\n\n self.user_id = None\n\nvalidation_token_object = AccountValidationToken('Super secret key')\nvalidation_token_object.user_id = 42\nvalidation_token = validation_token_object.create()\n\n# Verifying the validation token with the deletion token class will fail!\n# AccountDeletionToken.verify(validation_token, 'Super secret key')\n```\n\nIf you try to verify a token with a wrong class, EasyJWT will automatically reject your token by raising an\n`InvalidClassError` exception.\n\n### Accepting Third-Party Tokens\n\nBy default, EasyJWT will only accept tokens that have been created by the class with which you verify\nit.[1] This is\ndone by including a special claim in the token upon creation. This claim is required when verifying a token. Tokens\nwithout this claim or with a wrong value for this claim will fail verification. Usually, tokens from other sources will\nnot include this claim, and thus the validation of such a token will fail.\n\nYou can disable the verification of this special claim by setting a special flag in your token class. This flag will\nalso prevent the special claim from being included in the created tokens.\n\n```python\nfrom easyjwt import EasyJWT\n\nclass ThirdPartyJWT(EasyJWT):\n\n # Disable the validation of the special claim.\n strict_verification = False\n\n # The usual definition of the token's claim set ...\n```\n\nIf you try to verify a token without this special claim and without disabling the strict verification mode, EasyJWT\nwill raise an `UnspecifiedClassError` exception.\n\n---\n\n> [1]: To be precise, the name of the class with which the token has been created must\n> be the same as the name of the class with which it is being verified. This class name is included in each token\n> created by EasyJWT in the special claim `_easyjwt_class`.\n\n### Encoding Algorithms\n\nTokens created by EasyJWT are encoded using the HS256 algorithm by default. If you want to use a different algorithm,\nyou can specify this algorithm in the definition of your token class.\n\n```python\nfrom easyjwt import Algorithm\nfrom easyjwt import EasyJWT\n\nclass MySuperSimpleJWT(EasyJWT):\n\n # Use the HS512 algorithm.\n algorithm = Algorithm.HS512\n\n # The usual definition of the token's claim set ...\n```\n\nIf you have previously created tokens with your token class, and later want to change the algorithm for new tokens,\nyou should tell EasyJWT to still use the previous algorithms for decoding tokens. Otherwise, tokens created with the old\nversion of your code cannot be verified!\n\n```python\nfrom easyjwt import Algorithm\nfrom easyjwt import EasyJWT\n\nclass MySuperSimpleJWT(EasyJWT):\n\n # Use the HS512 algorithm.\n algorithm = Algorithm.HS512\n\n # Previously, tokens have been encoded with HS256, EasyJWT's default algorithm.\n # Thus, list it here.\n previous_algorithms = {Algorithm.HS256}\n\n # The usual definition of the token's claim set ...\n```\n\nYou can find a list of all available algorithms in the\n[API documentation](https://easyjwt.readthedocs.io/en/latest/api.html#easyjwt.Algorithm).\n\n### Optional Claims\n\nAll the claims you specify in the `__init__` method of your token class are mandatory, both for creating a token of this\nclass and for verifying a token. If you want some of these claims to be optional (both for creating and verifying a\ntoken), you can override EasyJWT's `_optional_claims` class variable. You can override this class variable in your token\nclass to include the names of your optional claims. Note that you must include the value of `EasyJWT._optional_claims`\nin your class. Otherwise, the registered claims will become mandatory.\n\n```python\nfrom easyjwt import EasyJWT\n\nclass MySuperSimpleJWT(EasyJWT):\n\n # The claim `my_optional_claim` is optional. All other claims are still mandatory.\n _optional_claims = EasyJWT._optional_claims.union({'my_optional_claim'})\n\n def __init__(self, key):\n super().__init__(key)\n\n self.my_optional_claim = None\n self.my_mandatory_claim = None\n\ntoken_object = MySuperSimpleJWT('Super secret key')\ntoken_object.my_mandatory_claim = 'Some value'\n\ntoken = token_object.create()\n```\n\n### Registered Claims\n\nEasyJWT supports all registered claims of the JWT specification: `aud`, `exp`, `iat`, `iss`, `jti`, `nbf`, and `sub`.\nAll of these claims are optional.\n\n#### Audience: `aud`\n\nThe audience identifies the recipients of the token, and can either be a string or a list of strings.\n\nYou can set an audience for your token using the attribute `audience` of your token object. This attribute will\nautomatically be mapped to the `aud` claim when creating the token.\n\n```python\nfrom easyjwt import EasyJWT\n\nclass MySuperSimpleJWT(EasyJWT):\n\n def __init__(self, key):\n super().__init__(key)\n\n self.name = None\n\ntoken_object = MySuperSimpleJWT('Super secret key')\ntoken_object.name = 'Zaphod Beeblebrox'\n\n# This token is intended for everyone, and especially for Zaphod Beeblebrox.\ntoken_object.audience = ['Zaphod Beeblebrox', 'Everyone']\n\ntoken = token_object.create()\n```\n\nTo verify a token with an audience, you must pass at least one of the audience values to EasyJWT's `verify` method.\nOtherwise, the verification will fail with an `InvalidAudienceError` exception. After the verification, the token's\naudience will be set on the `audience` attribute.\n\n```python\n# We are everyone, so this token is intended for us.\nverified_token_object = MySuperSimpleJWT.verify(token, 'Super secret key', audience='Everyone')\n\nassert verified_token_object.audience == ['Zaphod Beeblebrox', 'Everyone']\n```\n\n#### Expiration Date: `exp`\n\nThe expiration date specifies how long the token will be valid. If a token with an expiration date is verified after its\nexpiration date has passed, the token will be invalid.\n\nYou can set an expiration date for your token using the attribute `expiration_date` to a `datetime` object. This\nattribute will automatically be mapped to the `exp` claim when creating the token. Note that you must specify the\nexpiration date in UTC.\n\n```python\nimport datetime\nfrom easyjwt import EasyJWT\n\nclass MySuperSimpleJWT(EasyJWT):\n\n def __init__(self, key):\n super().__init__(key)\n\n self.name = None\n\ntoken_object = MySuperSimpleJWT('Super secret key')\ntoken_object.name = 'Zaphod Beeblebrox'\n\n# This token will expire in 15 minutes.\ntoken_object.expiration_date = datetime.datetime.utcnow() + datetime.timedelta(minutes=15)\n\ntoken = token_object.create()\n```\n\nWhen verifying a token with an expiration date, EasyJWT automatically checks if the expiration date has passed. If this\nis the case, the verification will fail with an `ExpiredTokenError` exception. After the verification, the token's\nexpiration date will be set on the `expiration_date` attribute as a `datetime` object in UTC.\n\n#### Issued At: `iat`\n\nThe issued at-date specifies the token's time of creation.\n\nWhen creating a token, this claim will automatically be set to the current time. If you want to set a different\nissued at-date, you can pass a `datetime` object (in UTC) to the optional `issued_at` parameter of EasyJWT's `create`\nmethod.\n\n```python\nimport datetime\nfrom easyjwt import EasyJWT\n\nclass MySuperSimpleJWT(EasyJWT):\n\n def __init__(self, key):\n super().__init__(key)\n\n self.name = None\n\ntoken_object = MySuperSimpleJWT('Super secret key')\ntoken_object.name = 'Zaphod Beeblebrox'\n\n# This token was issued five minutes ago.\ntoken = token_object.create(issued_at=datetime.datetime.utcnow() - datetime.timedelta(minutes=5))\n```\n\nAfter verifying a token with an issued at-date, its issued at-date will be set on the `issued_at_date` attribute.\n\n#### Issuer: `iss`\n\nThe issuer identifies the creator of the token.\n\nYou can set the issuer of your token using the `issuer` attribute of your token object. This attribute will\nautomatically be mapped to the `iss` claim when creating the token.\n\n```python\nfrom easyjwt import EasyJWT\n\nclass MySuperSimpleJWT(EasyJWT):\n\n def __init__(self, key):\n super().__init__(key)\n\n self.name = None\n\ntoken_object = MySuperSimpleJWT('Super secret key')\ntoken_object.name = 'Zaphod Beeblebrox'\n\n# This token is intended for everyone, and especially for Zaphod Beeblebrox.\ntoken_object.issuer = 'Arthur Dent'\n\ntoken = token_object.create()\n```\n\nTo verify a token with an issuer, you must pass the issuer specified in the token to EasyJWT's `verify` method.\nOtherwise, the verification will fail with an `InvalidIssuerError` exception. After the verification, the token's issuer\nwill be set on the `issuer` attribute.\n\n```python\n# We are everyone, so this token is intended for us.\nverified_token_object = MySuperSimpleJWT.verify(token, 'Super secret key', issuer='Arthur Dent')\n\nassert verified_token_object.issuer == 'Arthur Dent'\n```\n\n#### JWT ID: `jti`\n\nThe JWT ID is an identifier for your token. It must be unique for each token.\n\nYou can set the JWT ID of your token using the `JWT_ID` attribute of your token object. This attribute will\nautomatically be mapped to the `jti` claim when creating the token\n\n```python\nfrom easyjwt import EasyJWT\n\nclass MySuperSimpleJWT(EasyJWT):\n\n def __init__(self, key):\n super().__init__(key)\n\n self.name = None\n\ntoken_object = MySuperSimpleJWT('Super secret key')\ntoken_object.name = 'Zaphod Beeblebrox'\n\n# This ID must be unique for each token.\ntoken_object.JWT_ID = 'My super simple JWT 1'\n\ntoken = token_object.create()\n```\n\nAfter verifying a token with a JWT ID, this ID will be set on the `JWT_ID` attribute.\n\nNote that this claim is not verified by EasyJWT. It is your responsibility to validate it after verifying the token if\nyou need this validation.\n\n#### Not Before: `nbf`\n\nThe not before-date specifies the time before which the token will not be valid. If a token with a not before-date is\nverified before its not before-date has been reached, the token will be invalid.\n\nYou can set a not before-date for your token using the attribute `not_before_date` to a datetime object. This attribute\nwill automatically be mapped to the `nbf` claim when creating the token. Note that you must specify the not before-date\nin UTC.\n\n```python\nimport datetime\nfrom easyjwt import EasyJWT\n\nclass MySuperSimpleJWT(EasyJWT):\n\n def __init__(self, key):\n super().__init__(key)\n\n self.name = None\n\ntoken_object = MySuperSimpleJWT('Super secret key')\ntoken_object.name = 'Zaphod Beeblebrox'\n\n# This token will be valid in 5 minutes.\ntoken_object.not_before_date = datetime.datetime.utcnow() + datetime.timedelta(minutes=5)\n\ntoken = token_object.create()\n```\n\nWhen verifying a token with a not before-date, EasyJWT automatically checks if the not before-date has been reached. If\nthis is not the case, the verification will fail with an `ImmatureTokenError` exception. After the verification, the\ntoken's not before-date will be set on the `not_before_date` attribute as a `datetime` object in UTC.\n\n#### Subject: `sub`\n\nThe subject specifies the topic of your token.\n\nYou can set the subject of your token using the `subject` attribute of your token object. This attribute will\nautomatically be mapped to the `sub` claim when creating the token.\n\n```python\nfrom easyjwt import EasyJWT\n\nclass MySuperSimpleJWT(EasyJWT):\n\n def __init__(self, key):\n super().__init__(key)\n\n self.name = None\n\ntoken_object = MySuperSimpleJWT('Super secret key')\ntoken_object.name = 'Zaphod Beeblebrox'\n\n# This token is all about Douglas Adams' master work.\ntoken_object.subject = 'The Hitchhiker\\'s Guide to the Galaxy'\n\ntoken = token_object.create()\n```\n\nAfter verifying a token with a subject, this subject will be set on the `subject` attribute.\n\nNote that this claim is not verified by EasyJWT. It is your responsibility to validate it after verifying the token if\nyou need this validation.\n\n## Future Ideas\n\n * Allow creating tokens without an issued at-date.\n * Add a mode to accept arbitrary claims and create corresponding attributes as needed.\n * Allow specifying functions to pack and unpack claim values before creating a token and after verifying a token,\n respectively.\n\n## Acknowledgements\n\nEasyJWT is just an easy-to-use abstraction layer around Jos\u00e9 Padilla's [PyJWT library](https://pypi.org/project/PyJWT/)\nthat does the actual work of creating and verifying the tokens according to the JWT specification. Without his work,\nEasyJWT would not be possible.\n\n## License\n\nEasyJWT is developed by [Bastian Meyer](https://www.bastianmeyer.eu)\n<[bastian@bastianmeyer.eu](mailto:bastian@bastianmeyer.eu)> and is licensed under the\n[MIT License]((http://www.opensource.org/licenses/MIT)). For details, see the attached [LICENSE](LICENSE) file. \n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/BMeu/EasyJWT", "keywords": "jwt token tokens JSON", "license": "", "maintainer": "", "maintainer_email": "", "name": "easyjwt", "package_url": "https://pypi.org/project/easyjwt/", "platform": "", "project_url": "https://pypi.org/project/easyjwt/", "project_urls": { "Documentation": "https://easyjwt.readthedocs.io/en/latest/?badge=latest", "Homepage": "https://github.com/BMeu/EasyJWT", "Source": "https://github.com/BMeu/EasyJWT", "Tracker": "https://github.com/BMeu/EasyJWT/issues" }, "release_url": "https://pypi.org/project/easyjwt/0.1.1/", "requires_dist": [ "bidict", "PyJWT" ], "requires_python": ">=3.6", "summary": "Super simple JSON Web Tokens with Python", "version": "0.1.1" }, "last_serial": 5252437, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "7a006fc8d29c66b6120623cc10608113", "sha256": "0dd111624ef3c1d9a792d7bfc5be89bef6f7b8bc4bcfc81effb1f9658438e3fb" }, "downloads": -1, "filename": "easyjwt-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "7a006fc8d29c66b6120623cc10608113", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 15933, "upload_time": "2019-05-05T15:16:37", "url": "https://files.pythonhosted.org/packages/62/5c/34b6ea90043597ca36e897952e5cf62665557f932bf5f7bb4ff2e237338b/easyjwt-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a89dc84155f46dfa7d98dd7614a38f4e", "sha256": "8192ffd5cb19cc11f55e48067af469be83f5cc6005ab507c8e2f1b6137898f0e" }, "downloads": -1, "filename": "easyjwt-0.1.0.tar.gz", "has_sig": false, "md5_digest": "a89dc84155f46dfa7d98dd7614a38f4e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 14559, "upload_time": "2019-05-05T15:16:40", "url": "https://files.pythonhosted.org/packages/27/f0/f6a34ab4b2a2b5e2279fd3e348fdd39f33ac00eb3dde5b3bf985f8d8a839/easyjwt-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "e677a1b05303890159a0cc5a8543b9ba", "sha256": "a2d03018678bc0eb2356cf7cdf1cc231a2a37b99dfa400f577d62de81269f805" }, "downloads": -1, "filename": "easyjwt-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "e677a1b05303890159a0cc5a8543b9ba", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 16075, "upload_time": "2019-05-10T14:19:36", "url": "https://files.pythonhosted.org/packages/62/56/7eeb1adfc09f0de3a2da06982b929a583364921d695f4c3c54ff65fa766d/easyjwt-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "18a0b326cea69c529e570ad2a4d2c480", "sha256": "ddf34d3b6062e6ff30f1ee80de70ad157b4991d823ec9fc83dd7ded9e56ac9da" }, "downloads": -1, "filename": "easyjwt-0.1.1.tar.gz", "has_sig": false, "md5_digest": "18a0b326cea69c529e570ad2a4d2c480", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 14752, "upload_time": "2019-05-10T14:19:39", "url": "https://files.pythonhosted.org/packages/72/8d/e8850277c2ea32caef3b360d54e0b7da405a03d78463a91d3f254bf5d13d/easyjwt-0.1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "e677a1b05303890159a0cc5a8543b9ba", "sha256": "a2d03018678bc0eb2356cf7cdf1cc231a2a37b99dfa400f577d62de81269f805" }, "downloads": -1, "filename": "easyjwt-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "e677a1b05303890159a0cc5a8543b9ba", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 16075, "upload_time": "2019-05-10T14:19:36", "url": "https://files.pythonhosted.org/packages/62/56/7eeb1adfc09f0de3a2da06982b929a583364921d695f4c3c54ff65fa766d/easyjwt-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "18a0b326cea69c529e570ad2a4d2c480", "sha256": "ddf34d3b6062e6ff30f1ee80de70ad157b4991d823ec9fc83dd7ded9e56ac9da" }, "downloads": -1, "filename": "easyjwt-0.1.1.tar.gz", "has_sig": false, "md5_digest": "18a0b326cea69c529e570ad2a4d2c480", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 14752, "upload_time": "2019-05-10T14:19:39", "url": "https://files.pythonhosted.org/packages/72/8d/e8850277c2ea32caef3b360d54e0b7da405a03d78463a91d3f254bf5d13d/easyjwt-0.1.1.tar.gz" } ] }