Middleware¶
The middleware builds upon Starlette’s AuthenticationMiddleware
(see the
docs).
TokenAuthBackend
is used to extract the token from the request. If the token
is present and correct, then the request is accepted and the corresponding user
is added to the scope, otherwise it is rejected.
TokenAuthBackend
can work with several different TokenAuthProvider
subclasses. The following are provided by default, but custom ones can be
written by creating your own TokenAuthProvider
subclasses.
SecretTokenAuthProvider
¶
This provider checks whether the token provided by the client matches a list of predefined tokens.
from starlette.middleware.authentication import AuthenticationMiddleware
from piccolo_api.token_auth.middleware import (
TokenAuthBackend,
SecretTokenAuthProvider,
)
app = AuthenticationMiddleware(
my_asgi_app,
backend=TokenAuthBackend(SecretTokenAuthProvider(tokens=["abc123"])),
)
If successful a user called secret_token_user
is added to the scope.
This provider is useful for protecting internal services, where the client is trusted not to leak the tokens.
It is also useful for protecting login endpoints when accessed from native apps. The client provides the token to be able to access the login endpoint, after which they obtain a unique token, which is used to authenticate with other endpoints.
PiccoloTokenAuthProvider
¶
This provider checks a Piccolo database table for a corresponding token, and retrieves a matching user ID. It is the default provider.
from starlette.middleware.authentication import AuthenticationMiddleware
from piccolo_api.token_auth.middleware import (
TokenAuthBackend,
PiccoloTokenAuthProvider,
)
app = AuthenticationMiddleware(
my_asgi_app,
backend=TokenAuthBackend(PiccoloTokenAuthProvider()),
)
You’ll have to run the migrations for this to work correctly.
TokenAuthBackend
¶
excluded_paths
¶
By default, the middleware protects all of the endpoints it is wrapping (i.e. if a token isn’t present in the header then the request is rejected).
However, we may want to exclude certain endpoints - for example, if there’s a
Swagger docs endpoint, and allow access to them without a token. This is
possible using excluded_paths
.
Paths can be specified explicitly, or using wildcards:
TokenAuthBackend(
PiccoloTokenAuthProvider(),
excluded_paths=["/docs", "/openapi.json", "/foo/*"],
)
Note
In the above example /foo/*
matches /foo/
, /foo/a
, /foo/b
, /foo/b/1
etc.
This is useful when using Swagger docs as they can be viewed in a browser, but they are still token protected.
FastAPI example¶
If we want to communicate with the API endpoints via the Swagger docs, we need to set FastAPI APIKeyHeader as a dependency. After that we can authorise the user with a valid token as in the example below.
"""
An example usage of excluded_paths.
"""
from fastapi import Depends, FastAPI
from fastapi.middleware import Middleware
from fastapi.security.api_key import APIKeyHeader
from starlette.middleware.authentication import AuthenticationMiddleware
from tables import Movie # An example Table
from piccolo_api.crud.endpoints import PiccoloCRUD
from piccolo_api.fastapi.endpoints import FastAPIKwargs, FastAPIWrapper
from piccolo_api.token_auth.middleware import (
SecretTokenAuthProvider,
TokenAuthBackend,
)
app = FastAPI(
dependencies=[Depends(APIKeyHeader(name="Authorization"))],
middleware=[
Middleware(
AuthenticationMiddleware,
backend=TokenAuthBackend(
SecretTokenAuthProvider(tokens=["abc123"]),
excluded_paths=["/docs", "/openapi.json"],
),
)
],
)
# This is a quick way of building FastAPI endpoints using Piccolo, but isn't
# required:
FastAPIWrapper(
"/movies/",
fastapi_app=app,
piccolo_crud=PiccoloCRUD(Movie, read_only=False),
fastapi_kwargs=FastAPIKwargs(
all_routes={"tags": ["Movie"]},
),
)
The user can then use the Swagger docs to interact with the API.
Note
The full source code is available on GitHub. Find the source for this
documentation page, and look at the examples
folder.
Source¶
- class piccolo_api.token_auth.middleware.TokenAuthBackend(token_auth_provider: TokenAuthProvider = DEFAULT_PROVIDER, excluded_paths: Sequence[str] | None = None)[source]¶
- Parameters:
token_auth_provider – Used to verify that a token is correct.
excluded_paths – These paths don’t require a token - useful if you want to exclude a few URLs, such as docs.
- class piccolo_api.token_auth.middleware.TokenAuthProvider[source]¶
Subclass to create your own token provider.