Skip to main content

starlette-auth-toolkit

travis pypi python black

Authentication backends and helpers for Starlette-based ASGI apps and frameworks.

Note: documentation is in progress. In the meantime, feel free to read the source code.

Features

  • Database-agnostic.
  • User model-agnostic.
  • Password hashing and hash migration support.
  • Built-in support for common authentication flows, including Basic and Token authentication.
  • Support for multiple authentication backends.
  • Easy integration with orm.

Contents

Installation

pip install starlette-auth-toolkit

Quickstart

import typing

from starlette.applications import Starlette
from starlette.authentication import requires
from starlette.middleware.authentication import AuthenticationMiddleware
from starlette.responses import JSONResponse, PlainTextResponse

from starlette_auth_toolkit.base.backends import BaseBasicAuth
from starlette_auth_toolkit.cryptography import PBKDF2Hasher

# Password hasher
hasher = PBKDF2Hasher()


# Example user model
class User(typing.NamedTuple):
    username: str
    password: str


# Fake user storage
USERS = {
    "alice": User(username="alice", password=hasher.make_sync("alicepwd")),
    "bob": User(username="bob", password=hasher.make_sync("bobpwd")),
}

# Authentication backend
class BasicAuth(BaseBasicAuth):
    async def find_user(self, username: str):
        return USERS.get(username)

    async def verify_password(self, user: User, password: str):
        return await hasher.verify(password, user.password)


# Application

app = Starlette()

app.add_middleware(
    AuthenticationMiddleware,
    backend=BasicAuth(),
    on_error=lambda _, exc: PlainTextResponse(str(exc), status_code=401),
)


@app.route("/protected")
@requires("authenticated")
async def protected(request):
    return JSONResponse({"message": f"Hello, {request.user.username}!"})

Save this file as app.py. Then, assuming you have uvicorn installed, run $ uvicorn app:app and make requests:

  • Anonymous request:
curl -i http://localhost:8000/protected
HTTP/1.1 403 Forbidden
date: Tue, 23 Jul 2019 20:44:52 GMT
server: uvicorn
content-length: 9
content-type: text/plain; charset=utf-8

Forbidden
  • Authenticated request:
curl -i -u alice:alicepwd http://localhost:8000/protected
HTTP/1.1 200 OK
date: Tue, 23 Jul 2019 20:45:24 GMT
server: uvicorn
content-length: 27
content-type: application/json

{"message":"Hello, alice!"}

For a real-world example, see here.

Dependencies

Like Starlette, starlette-auth-toolkit does not have any hard dependencies, but you can optionally install the following:

  • passlib - Required if you want to use password hashers.

Base backends

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

These backends grant a set of scopes when authentication succeeds.

Although base backends are user model agnostic, we recommend you implement the interface specified by starlette.authentication.BaseUser (see also Starlette authentication).

They are available at starlette_auth_toolkit.base.backends.

BaseBasicAuth

Base implementation of the Basic authentication scheme.

Request header format

Authorization: Basic {credentials}

where {credentials} refers to the base64 encoding of {username}:{password}.

Example

# myapp/auth.py
from starlette.authentication import SimpleUser  # or a custom user model
from starlette_auth_toolkit.base.backends import BaseBasicAuth

class BasicAuth(BaseBasicAuth):
    async def verify(self, username: str, password: str):
        # In practice, request the database to find the user associated
        # to `username`, and validate that its password hash matches the
        # given password.
        if (username, password) != ("bob", "s3kr3t"):
            return None
        return SimpleUser(username)

Abstract methods

  • async .verify(self, username: str, password: str) -> Optional[BaseUser]

    If username and password are valid, return the corresponding user. Otherwise, return None.

Scopes

  • authenticated

BaseTokenAuth

Base implementation of token authentication, a simplified version of the Bearer authentication scheme.

Request header format

Authorization: Token {token}

Example

# myapp/auth.py
from starlette.authentication import SimpleUser  # or a custom user model
from starlette_auth_toolkit.base.backends import BaseTokenAuth

class TokenAuth(BaseTokenAuth):
    async def verify(self, token: str):
        # In practice, request the database to find the token object
        # associated to `token`, and return its associated user.
        if token != "abcd":
            return None
        return SimpleUser("bob")

Abstract methods

  • async .verify(self, token: str) -> Optional[BaseUser]

    If token refers to a valid token, return the corresponding user. Otherwise, return None.

Scopes

  • authenticated

Backends

Authentication backends listed here are ready-to-use implementations and are available in the backends module, unless specified otherwise.

contrib.orm.ModelBasicAuth

A ready-to-use implementation of BaseBasicAuth using an orm user model.

Note: orm must be installed to use this backend.

Example

from starlette.applications import Starlette
from starlette_auth_toolkit.contrib.orm import ModelBasicAuth
from starlette_auth_toolkit.cryptography import PBKDF2Hasher

from myproject.models import User  # DIY

hasher = PBKDF2Hasher()

app = Starlette()
app.add_middleware(
    AuthenticationMiddleware,
    backend=ModelBasicAuth(User, hasher=hasher)
)

Parameters

  • model (orm.Model or () -> orm.Model): the user model (or a callable for lazy loading).
  • hasher (BaseHasher): a password hasher — the same one used to hash user passwords.
  • password_field (str, optional): field where password hashes are stored on user objects. Defaults to "password".

Scopes

  • authenticated

MultiAuth

This 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).

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 — even if a later backend would have succeeded.

Example

from starlette_auth_toolkit.backends import MultiAuth

from myproject.auth import TokenAuth, BasicAuth  # TODO

# Allow to authenticate using either a token or username/password credentials.
backend = MultiAuth([TokenAuth(), BasicAuth()])

Parameters

  • backends (List[AuthBackend]): a list of authentication backends, which determines which authentication methods clients can use to authenticate.

Scopes

  • authenticated

Password hashers

This package provides password hashing utilities built on top of PassLib.

Usage

  • Asynchronous: await .make() / await .verify() (hashing and verification occurs in the threadpool)
import asyncio
from starlette_auth_toolkit.cryptography import PBKDF2Hasher

async def main():
    # Instanciate a hasher:
    hasher = PBKDF2Hasher()

    # Hash a password:
    pwd = await hasher.make("hello")

    # Verify a password against a known hash:
    assert await hasher.verify("hello", pwd)

# Python 3.7+
asyncio.run(main())
  • Blocking: .make_sync() / .verify_sync()
from starlette_auth_toolkit.cryptography import PBKDF2Hasher

# Instanciate a hasher:
hasher = PBKDF2Hasher()

# Hash a password
pwd = hasher.make_sync("hello")

# Verify a password against a known hash:
assert hasher.verify_sync("hello", pwd)

Hash migration (Advanced)

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

MultiHasher was designed to solve this problem:

from starlette_auth_toolkit.cryptography import Argon2Hasher, PBKDF2Hasher, MultiHasher

hasher = MultiHasher([Argon2Hasher(), PBKDF2Hasher()])

The above hasher will use Argon2 when hashing new passwords, but will be able to verify hashes created using either Argon2 or PBKDF2.

To detect whether a hash needs rehashing, use .needs_update():

valid = await hasher.verify(pwd, pwd_hash)

if hasher.needs_update(pwd_hash):
    new_hash = await hasher.make(pwd)
    # TODO: store new hash

# ...

Note: calling .needs_update() at anytime other than just after calling .verify() will raise a RuntimeError.

Available hashers

Name Requires PassLib algorithm
PBKDF2Hasher pbkdf2_sha256
CryptHasher sha256_crypt
BCryptHasher bcrypt bcrypt
Argon2Hasher argon2-cffi argon2
MultiHasher N/A

For advanced use cases, use Hasher and pass one of the algorithms listed in passlib.hash:

from starlette_auth_toolkit.cryptography import Hasher

hasher = Hasher(algorithm="pbkdf2_sha512")

Authenticating in views

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

auth = MyBasicAuth()

@app.route("/guard")
async def logs_user_in(request):
    data = await request.json()
    username = data["username"]
    password = data["password"]
    user = await auth.verify(username, password)
    # ...

Contributing

Want to contribute? Awesome! Be sure to read our Contributing guidelines.

Changelog

See CHANGELOG.md.

License

MIT

Metadata

Release files for starlette-auth-toolkit 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for starlette-auth-toolkit 0.5.0
File Size Uploaded Provenance Actions
starlette-auth-toolkit-0.5.0.tar.gz 13.3 kB Without provenance Details for starlette-auth-toolkit-0.5.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for starlette-auth-toolkit 0.5.0
File Interpreter ABI Platform Actions
starlette_auth_toolkit-0.5.0-py3-none-any.whl Python 3 none any Details for starlette_auth_toolkit-0.5.0-py3-none-any.whl

Total release size: 24.3 kB

Release files / starlette-auth-toolkit-0.5.0.tar.gz

Download URL starlette-auth-toolkit-0.5.0.tar.gz
Size 13.3 kB
Tags Source
SHA-256 checksum
How to use checksums
9fd041aff89fffe67feb8cd94e10e2a8bbf609aeb6a736a74fce79320254e1f1
BLAKE2b-256 checksum
How to use checksums
74a2d414932fc33b56dff74fa34f4b37f4d3ceedbaf863dacea85d7eee113ce7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.7.1

Release files / starlette_auth_toolkit-0.5.0-py3-none-any.whl

Download URL starlette_auth_toolkit-0.5.0-py3-none-any.whl
Size 11.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5b3b651bf05d3f0332846fac52b7266b06f05d9264c7a9d065ca51dccf765a7a
BLAKE2b-256 checksum
How to use checksums
2470c5d1971ed20d21a78223af79ca7889d715dcb59af628fea9228e79383bc9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.7.1

Security for starlette-auth-toolkit 0.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page