Authentication Middleware¶
Service may require an authentication to authorize http requests.
The authentication part is not a part of the contract of a route, but generally for a whole service or even for the whole registry.
For concistency, every service should use the same authorization pattern.
With blacksmith, the authentication mechanism is declared in the AsyncClientFactory to get the authentication working. It also can be overridden on every api call.
Example¶
from blacksmith import (
AsyncClientFactory,
AsyncConsulDiscovery,
AsyncHTTPBearerMiddleware,
)
access_token = "abc"
sd = AsyncConsulDiscovery()
auth = AsyncHTTPBearerMiddleware(access_token)
cli = AsyncClientFactory(sd).add_middleware(auth)
# Now every call of the client will have the header
# Authorization: Bearer abc
async def main():
api = await cli("api")
protected_resource = await api.protected_resource.get({}) # noqa
In the example above, the bearer token is share for every clients, of the factory, which is ok for a service like prometheus where the token is a configuration key, but most of the time, a token depends on users.
So in the example below, we set the token only on a particular client.
from blacksmith import (
AsyncClientFactory,
AsyncConsulDiscovery,
AsyncHTTPBearerMiddleware,
)
sd = AsyncConsulDiscovery()
cli = AsyncClientFactory(sd)
async def a_dummy_api_view(request):
api = await cli("api")
api.add_middleware(AsyncHTTPBearerMiddleware(request.access_token))
protected_resource = await api.protected_resource.get({}) # noqa
In that example, we have a fake web framework that parse the authorization
header and expose the bearer token under a variable request.access_token
.
And we provide the middleware only for the execution ot that request.
Create a custom authentication based on http header¶
Imagine that you have an api that consume a “X-Secret” header to validate call.
from blacksmith import (
AsyncClientFactory,
AsyncConsulDiscovery,
AsyncHTTPAddHeadersMiddleware,
)
class AsyncBasicAuthorization(AsyncHTTPAddHeadersMiddleware):
def __init__(self, secret):
return super().__init__(headers={"X-Secret": secret})
sd = AsyncConsulDiscovery()
auth = AsyncBasicAuthorization("secret")
cli = AsyncClientFactory(sd).add_middleware(auth)
Create a custom authentication based on querystring parameter¶
It is not recommended to pass server in a querystring, because get parameter are oftenly logged by server, and secret should never be logged. So blacksmith does not provide a middleware to handle this query, but, you can still implementing it by yourself.
See how to implement it in the section Generic Middleware.