{ "info": { "author": "Florimond Manca", "author_email": "florimond.manca@gmail.com", "bugtrack_url": null, "classifiers": [ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3 :: Only" ], "description": "# starlette-auth-toolkit\n\n[![travis](https://travis-ci.org/florimondmanca/starlette-auth-toolkit.svg?branch=master)](https://travis-ci.org/florimondmanca/starlette-auth-toolkit)\n[![pypi](https://badge.fury.io/py/starlette-auth-toolkit.svg)](https://pypi.org/project/starlette-auth-toolkit)\n![python](https://img.shields.io/pypi/pyversions/starlette-auth-toolkit.svg)\n[![black](https://img.shields.io/badge/code_style-black-000000.svg)](https://github.com/ambv/black)\n\nAuthentication backends and helpers for Starlette-based ASGI apps and frameworks.\n\n> **Note**: documentation is in progress. In the meantime, feel free to [read the source code](https://github.com/florimondmanca/starlette-auth-toolkit/tree/master/starlette_auth_toolkit).\n\n**Features**\n\n- Database-agnostic.\n- User model-agnostic.\n- Password hashing and hash migration support.\n- Built-in support for common authentication flows, including Basic and Token authentication.\n- Support for multiple authentication backends.\n- Easy integration with [`orm`].\n\n[`orm`]: https://github.com/encode/orm\n\n**Contents**\n\n- [Installation](#installation)\n- [Quickstart](#quickstart)\n- [Dependencies](#dependencies)\n- [Base backends](#base-backends)\n- [Backends](#backends)\n- [Authenticating in views](#authenticating-in-views)\n- [Password hashers](#password-hashers)\n\n## Installation\n\n```bash\npip install starlette-auth-toolkit\n```\n\n## Quickstart\n\n```python\nimport typing\n\nfrom starlette.applications import Starlette\nfrom starlette.authentication import requires\nfrom starlette.middleware.authentication import AuthenticationMiddleware\nfrom starlette.responses import JSONResponse, PlainTextResponse\n\nfrom starlette_auth_toolkit.base.backends import BaseBasicAuth\nfrom starlette_auth_toolkit.cryptography import PBKDF2Hasher\n\n# Password hasher\nhasher = PBKDF2Hasher()\n\n\n# Example user model\nclass User(typing.NamedTuple):\n username: str\n password: str\n\n\n# Fake user storage\nUSERS = {\n \"alice\": User(username=\"alice\", password=hasher.make_sync(\"alicepwd\")),\n \"bob\": User(username=\"bob\", password=hasher.make_sync(\"bobpwd\")),\n}\n\n# Authentication backend\nclass BasicAuth(BaseBasicAuth):\n async def find_user(self, username: str):\n return USERS.get(username)\n\n async def verify_password(self, user: User, password: str):\n return await hasher.verify(password, user.password)\n\n\n# Application\n\napp = Starlette()\n\napp.add_middleware(\n AuthenticationMiddleware,\n backend=BasicAuth(),\n on_error=lambda _, exc: PlainTextResponse(str(exc), status_code=401),\n)\n\n\n@app.route(\"/protected\")\n@requires(\"authenticated\")\nasync def protected(request):\n return JSONResponse({\"message\": f\"Hello, {request.user.username}!\"})\n\n```\n\nSave this file as `app.py`. Then, assuming you have [uvicorn](https://www.uvicorn.org/) installed, run `$ uvicorn app:app` and make requests:\n\n- Anonymous request:\n\n```bash\ncurl -i http://localhost:8000/protected\n```\n\n```http\nHTTP/1.1 403 Forbidden\ndate: Tue, 23 Jul 2019 20:44:52 GMT\nserver: uvicorn\ncontent-length: 9\ncontent-type: text/plain; charset=utf-8\n\nForbidden\n```\n\n- Authenticated request:\n\n```bash\ncurl -i -u alice:alicepwd http://localhost:8000/protected\n```\n\n```http\nHTTP/1.1 200 OK\ndate: Tue, 23 Jul 2019 20:45:24 GMT\nserver: uvicorn\ncontent-length: 27\ncontent-type: application/json\n\n{\"message\":\"Hello, alice!\"}\n```\n\nFor a real-world example, [see here](https://github.com/florimondmanca/starlette-auth-toolkit/blob/master/tests/apps/example.py).\n\n## Dependencies\n\nLike Starlette, `starlette-auth-toolkit` does not have any hard dependencies, but you can optionally install the following:\n\n- [`passlib`][passlib] - Required if you want to use password hashers.\n\n[passlib]: https://passlib.readthedocs.io/en/stable/index.html\n\n## Base backends\n\nBase backends implement an **authentication flow**, but the exact implementation of credentials verification is left up to you. This means you can choose to perform a database query, use environment variables or private files, etc.\n\nThese backends grant a set of [scopes](https://www.starlette.io/authentication/#authcredentials) when authentication succeeds.\n\nAlthough base backends are **user model agnostic**, we recommend you implement the interface specified by `starlette.authentication.BaseUser` (see also [Starlette authentication](https://www.starlette.io/authentication/)).\n\nThey are available at `starlette_auth_toolkit.base.backends`.\n\n### `BaseBasicAuth`\n\nBase implementation of the [Basic authentication scheme](https://tools.ietf.org/html/rfc7617).\n\n**Request header format**\n\n```http\nAuthorization: Basic {credentials}\n```\n\nwhere `{credentials}` refers to the base64 encoding of `{username}:{password}`.\n\n**Example**\n\n```python\n# myapp/auth.py\nfrom starlette.authentication import SimpleUser # or a custom user model\nfrom starlette_auth_toolkit.base.backends import BaseBasicAuth\n\nclass BasicAuth(BaseBasicAuth):\n async def verify(self, username: str, password: str):\n # In practice, request the database to find the user associated\n # to `username`, and validate that its password hash matches the\n # given password.\n if (username, password) != (\"bob\", \"s3kr3t\"):\n return None\n return SimpleUser(username)\n```\n\n**Abstract methods**\n\n- _async_ `.verify(self, username: str, password: str) -> Optional[BaseUser]`\n\n If `username` and `password` are valid, return the corresponding user. Otherwise, return `None`.\n\n**Scopes**\n\n- `authenticated`\n\n### `BaseTokenAuth`\n\nBase implementation of token authentication, a simplified version of the [Bearer authentication scheme](https://tools.ietf.org/html/rfc6750).\n\n**Request header format**\n\n```http\nAuthorization: Token {token}\n```\n\n**Example**\n\n```python\n# myapp/auth.py\nfrom starlette.authentication import SimpleUser # or a custom user model\nfrom starlette_auth_toolkit.base.backends import BaseTokenAuth\n\nclass TokenAuth(BaseTokenAuth):\n async def verify(self, token: str):\n # In practice, request the database to find the token object\n # associated to `token`, and return its associated user.\n if token != \"abcd\":\n return None\n return SimpleUser(\"bob\")\n```\n\n**Abstract methods**\n\n- _async_ `.verify(self, token: str) -> Optional[BaseUser]`\n\n If `token` refers to a valid token, return the corresponding user. Otherwise, return `None`.\n\n**Scopes**\n\n- `authenticated`\n\n## Backends\n\nAuthentication backends listed here are ready-to-use implementations and are available in the `backends` module, unless specified otherwise.\n\n### `contrib.orm.ModelBasicAuth`\n\nA ready-to-use implementation of `BaseBasicAuth` using an `orm` user model.\n\n**Note**: [`orm`] must be installed to use this backend.\n\n**Example**\n\n```python\nfrom starlette.applications import Starlette\nfrom starlette_auth_toolkit.contrib.orm import ModelBasicAuth\nfrom starlette_auth_toolkit.cryptography import PBKDF2Hasher\n\nfrom myproject.models import User # DIY\n\nhasher = PBKDF2Hasher()\n\napp = Starlette()\napp.add_middleware(\n AuthenticationMiddleware,\n backend=ModelBasicAuth(User, hasher=hasher)\n)\n```\n\n**Parameters**\n\n- `model` (`orm.Model` or `() -> orm.Model`): the user model (or a callable for lazy loading).\n- `hasher` (`BaseHasher`): a [password hasher](#password-hashers) \u2014 the same one used to hash user passwords.\n- `password_field` (`str`, optional): field where password hashes are stored on user objects. Defaults to `\"password\"`.\n\n**Scopes**\n\n- `authenticated`\n\n### `MultiAuth`\n\nThis backend allows you to support multiple authentication methods in your application. `MultiAuth` attempts authenticating using the given `backends` in order until one succeeds (or all fail).\n\n**Note**: if any backend fails with an `AuthenticationError` (e.g. because some credentials were provided but they were invalid), `MultiAuth` will propagate the exception and no further attempts will be made \u2014 even if a later backend would have succeeded.\n\n**Example**\n\n```python\nfrom starlette_auth_toolkit.backends import MultiAuth\n\nfrom myproject.auth import TokenAuth, BasicAuth # TODO\n\n# Allow to authenticate using either a token or username/password credentials.\nbackend = MultiAuth([TokenAuth(), BasicAuth()])\n```\n\n**Parameters**\n\n- `backends` (`List[AuthBackend]`): a list of authentication backends, which determines which authentication methods clients can use to authenticate.\n\n**Scopes**\n\n- `authenticated`\n\n## Password hashers\n\nThis package provides password hashing utilities built on top of [PassLib].\n\n### Usage\n\n- Asynchronous: `await .make()` / `await .verify()` (hashing and verification occurs in the threadpool)\n\n```python\nimport asyncio\nfrom starlette_auth_toolkit.cryptography import PBKDF2Hasher\n\nasync def main():\n # Instanciate a hasher:\n hasher = PBKDF2Hasher()\n\n # Hash a password:\n pwd = await hasher.make(\"hello\")\n\n # Verify a password against a known hash:\n assert await hasher.verify(\"hello\", pwd)\n\n# Python 3.7+\nasyncio.run(main())\n```\n\n- Blocking: `.make_sync()` / `.verify_sync()`\n\n```python\nfrom starlette_auth_toolkit.cryptography import PBKDF2Hasher\n\n# Instanciate a hasher:\nhasher = PBKDF2Hasher()\n\n# Hash a password\npwd = hasher.make_sync(\"hello\")\n\n# Verify a password against a known hash:\nassert hasher.verify_sync(\"hello\", pwd)\n```\n\n### Hash migration (Advanced)\n\nIf you need to change the hash algorithm (say from PBKDF2 to Argon2), you will typically want to keep support for existing hashes, but rehash them with the new algorithm as soon as possible.\n\n`MultiHasher` was designed to solve this problem:\n\n```python\nfrom starlette_auth_toolkit.cryptography import Argon2Hasher, PBKDF2Hasher, MultiHasher\n\nhasher = MultiHasher([Argon2Hasher(), PBKDF2Hasher()])\n```\n\nThe above `hasher` will use Argon2 when hashing new passwords, but will be able to verify hashes created using either Argon2 or PBKDF2.\n\nTo detect whether a hash needs rehashing, use `.needs_update()`:\n\n```python\nvalid = await hasher.verify(pwd, pwd_hash)\n\nif hasher.needs_update(pwd_hash):\n new_hash = await hasher.make(pwd)\n # TODO: store new hash\n\n# ...\n```\n\n> **Note**: calling `.needs_update()` at anytime other than just after calling `.verify()` will raise a `RuntimeError`.\n\n### Available hashers\n\n| Name | Requires | PassLib algorithm |\n| -------------- | ------------- | ----------------- |\n| `PBKDF2Hasher` | | `pbkdf2_sha256` |\n| `CryptHasher` | | `sha256_crypt` |\n| `BCryptHasher` | `bcrypt` | `bcrypt` |\n| `Argon2Hasher` | `argon2-cffi` | `argon2` |\n| `MultiHasher` | | N/A |\n\nFor advanced use cases, use `Hasher` and pass one of the algorithms listed in [passlib.hash](https://passlib.readthedocs.io/en/stable/lib/passlib.hash.html):\n\n```python\nfrom starlette_auth_toolkit.cryptography import Hasher\n\nhasher = Hasher(algorithm=\"pbkdf2_sha512\")\n```\n\n## Authenticating in views\n\nIf you need to authenticate a user inside a view, i.e. exchange a pair of `username` and `password` for the actual `user`, use your `BasicAuth` backend:\n\n```python\nauth = MyBasicAuth()\n\n@app.route(\"/guard\")\nasync def logs_user_in(request):\n data = await request.json()\n username = data[\"username\"]\n password = data[\"password\"]\n user = await auth.verify(username, password)\n # ...\n```\n\n## Contributing\n\nWant to contribute? Awesome! Be sure to read our [Contributing guidelines](https://github.com/florimondmanca/starlette-auth-toolkit/tree/master/CONTRIBUTING.md).\n\n## Changelog\n\nSee [CHANGELOG.md](https://github.com/florimondmanca/starlette-auth-toolkit/tree/master/CHANGELOG.md).\n\n## License\n\nMIT\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/florimondmanca/starlette-auth-toolkit.git", "keywords": "", "license": "License :: OSI Approved :: MIT License", "maintainer": "", "maintainer_email": "", "name": "starlette-auth-toolkit", "package_url": "https://pypi.org/project/starlette-auth-toolkit/", "platform": "", "project_url": "https://pypi.org/project/starlette-auth-toolkit/", "project_urls": { "Homepage": "https://github.com/florimondmanca/starlette-auth-toolkit.git" }, "release_url": "https://pypi.org/project/starlette-auth-toolkit/0.5.0/", "requires_dist": [ "starlette (>=0.11)", "pytest ; extra == 'dev'", "pytest-asyncio ; extra == 'dev'", "requests ; extra == 'dev'", "uvicorn ; extra == 'dev'", "argon2-cffi ; extra == 'dev'", "bcrypt ; extra == 'dev'", "orm ; extra == 'dev'", "databases[sqlite] ; extra == 'dev'", "black ; extra == 'dev'", "pylint ; extra == 'dev'", "bumpversion ; extra == 'dev'", "passlib (<2,>=1.7) ; extra == 'passwords'" ], "requires_python": ">=3.6", "summary": "Authentication backends and helpers for Starlette-based ASGI apps and frameworks", "version": "0.5.0" }, "last_serial": 5636242, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "a1592623a88133ff1d8b6c5b7334a9f0", "sha256": "d229a6ecf4d3c2275908861955a2bc75472bbd394a1687fc729a34f2fae2e530" }, "downloads": -1, "filename": "starlette_auth_toolkit-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "a1592623a88133ff1d8b6c5b7334a9f0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 5367, "upload_time": "2019-05-12T17:45:45", "url": "https://files.pythonhosted.org/packages/43/60/3945f9d2ce54e41f71cb6cf098732dc12a5c34900e605ec9c5cbb5966a4f/starlette_auth_toolkit-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2543ea7bfd2435069c90f2929469e776", "sha256": "90867e9250b65be9e98002c0b9238d3acaf917e7b515338685ae38425c57832e" }, "downloads": -1, "filename": "starlette-auth-toolkit-0.1.0.tar.gz", "has_sig": false, "md5_digest": "2543ea7bfd2435069c90f2929469e776", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 4483, "upload_time": "2019-05-12T17:45:47", "url": "https://files.pythonhosted.org/packages/21/b7/ac79a9728e76eff8744f2ea0237e3b1c96cc40a91796916785d6994e2259/starlette-auth-toolkit-0.1.0.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "6966918115166b7b31ed2494e9a6caf0", "sha256": "e791935728597d6d3f344c20e58ffb45ff1d200617b59b565bef20a7e32fe562" }, "downloads": -1, "filename": "starlette_auth_toolkit-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "6966918115166b7b31ed2494e9a6caf0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 5895, "upload_time": "2019-07-14T15:59:17", "url": "https://files.pythonhosted.org/packages/26/b6/bd6b7ffba535599df80af009abe9553401c80940eea59ca8086481df7e0b/starlette_auth_toolkit-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7d3a250be7c0e67d45e8c663d61366e7", "sha256": "50a778ecd6c5f07f0e36e38215d8944852dc1b29dcf7d92be07efc57e529b227" }, "downloads": -1, "filename": "starlette-auth-toolkit-0.2.0.tar.gz", "has_sig": false, "md5_digest": "7d3a250be7c0e67d45e8c663d61366e7", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 5182, "upload_time": "2019-07-14T15:59:18", "url": "https://files.pythonhosted.org/packages/28/b4/1502b04de7bb89fcfd3ea600c29c345419fee06accd74714bd195f2ebe16/starlette-auth-toolkit-0.2.0.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "f80531cba5d599efad81f5bc45e9d00a", "sha256": "dbb5939df9637d536ce2b62f0b43145139a2492061ee00be7630334b91979f84" }, "downloads": -1, "filename": "starlette_auth_toolkit-0.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "f80531cba5d599efad81f5bc45e9d00a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 8077, "upload_time": "2019-07-21T10:50:02", "url": "https://files.pythonhosted.org/packages/7b/fe/294ebfbd1132a5b35d4617292582cde0b200eb02baf61d4143971bf77bea/starlette_auth_toolkit-0.3.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a0dd5dbe81141e42d955665a67dbdada", "sha256": "bb851f4312a384c4b417c3a69cc27dc7d6bc0f5d22ca1d18c9433abc1975ab5a" }, "downloads": -1, "filename": "starlette-auth-toolkit-0.3.0.tar.gz", "has_sig": false, "md5_digest": "a0dd5dbe81141e42d955665a67dbdada", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 7835, "upload_time": "2019-07-21T10:50:04", "url": "https://files.pythonhosted.org/packages/02/2c/d5e8981390d4eeecec95cb18bc443d22de1afce9d537fe1e2362aa69178d/starlette-auth-toolkit-0.3.0.tar.gz" } ], "0.4.0": [ { "comment_text": "", "digests": { "md5": "a5f0c22847e66eabf4071102beacd034", "sha256": "c06966d337a05f8f27049c898d6e1da05c3f57a874f23820c817919808f527db" }, "downloads": -1, "filename": "starlette_auth_toolkit-0.4.0-py3-none-any.whl", "has_sig": false, "md5_digest": "a5f0c22847e66eabf4071102beacd034", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 11199, "upload_time": "2019-07-21T21:31:27", "url": "https://files.pythonhosted.org/packages/8f/79/8b5388b5bd0871227a2da5982e246dccf2caa2534754680bca136183facd/starlette_auth_toolkit-0.4.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "33e1cfd90e3b669de3cefd504e10d34b", "sha256": "31e75776ba49e1caa808458554ba362f65d8619b73567c9be83ca8bebb8416c6" }, "downloads": -1, "filename": "starlette-auth-toolkit-0.4.0.tar.gz", "has_sig": false, "md5_digest": "33e1cfd90e3b669de3cefd504e10d34b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 13348, "upload_time": "2019-07-21T21:31:28", "url": "https://files.pythonhosted.org/packages/73/4f/27108516a782439f0870526f4b178d5046eb53d5ac523ad34401bf335314/starlette-auth-toolkit-0.4.0.tar.gz" } ], "0.5.0": [ { "comment_text": "", "digests": { "md5": "d400a73074bd05444fe8ae91f42b05bc", "sha256": "5b3b651bf05d3f0332846fac52b7266b06f05d9264c7a9d065ca51dccf765a7a" }, "downloads": -1, "filename": "starlette_auth_toolkit-0.5.0-py3-none-any.whl", "has_sig": false, "md5_digest": "d400a73074bd05444fe8ae91f42b05bc", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 10955, "upload_time": "2019-08-05T20:30:10", "url": "https://files.pythonhosted.org/packages/24/70/c5d1971ed20d21a78223af79ca7889d715dcb59af628fea9228e79383bc9/starlette_auth_toolkit-0.5.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d765eb9639aa96b416bc03d0b8fcbdcd", "sha256": "9fd041aff89fffe67feb8cd94e10e2a8bbf609aeb6a736a74fce79320254e1f1" }, "downloads": -1, "filename": "starlette-auth-toolkit-0.5.0.tar.gz", "has_sig": false, "md5_digest": "d765eb9639aa96b416bc03d0b8fcbdcd", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 13322, "upload_time": "2019-08-05T20:30:12", "url": "https://files.pythonhosted.org/packages/74/a2/d414932fc33b56dff74fa34f4b37f4d3ceedbaf863dacea85d7eee113ce7/starlette-auth-toolkit-0.5.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "d400a73074bd05444fe8ae91f42b05bc", "sha256": "5b3b651bf05d3f0332846fac52b7266b06f05d9264c7a9d065ca51dccf765a7a" }, "downloads": -1, "filename": "starlette_auth_toolkit-0.5.0-py3-none-any.whl", "has_sig": false, "md5_digest": "d400a73074bd05444fe8ae91f42b05bc", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 10955, "upload_time": "2019-08-05T20:30:10", "url": "https://files.pythonhosted.org/packages/24/70/c5d1971ed20d21a78223af79ca7889d715dcb59af628fea9228e79383bc9/starlette_auth_toolkit-0.5.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d765eb9639aa96b416bc03d0b8fcbdcd", "sha256": "9fd041aff89fffe67feb8cd94e10e2a8bbf609aeb6a736a74fce79320254e1f1" }, "downloads": -1, "filename": "starlette-auth-toolkit-0.5.0.tar.gz", "has_sig": false, "md5_digest": "d765eb9639aa96b416bc03d0b8fcbdcd", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 13322, "upload_time": "2019-08-05T20:30:12", "url": "https://files.pythonhosted.org/packages/74/a2/d414932fc33b56dff74fa34f4b37f4d3ceedbaf863dacea85d7eee113ce7/starlette-auth-toolkit-0.5.0.tar.gz" } ] }