Home > Blockchain >  How to use api key authentication with Quart API?
How to use api key authentication with Quart API?

Time:03-02

I have a Python/Quart API REST microservice and want to apply API key based authentication.

What is the conventional way to do this and what is the general way to store API keys?

Can the package do this or do I need to implement my own by manually checking "?api_key=asdfasdf" values etc?

I see quart_auth has basic authentication but not API key based authentication...

CodePudding user response:

There isn't a built in way to do this (Quart is agnostic, and Quart-Auth focuses on cookie and basic authentication). However the following will work for header based API keys,

from quart import (
    current_app, 
    has_request_context, 
    has_websocket_context, 
    request, 
    websocket,
)
from werkzeug.exceptions import Unauthorized

def api_key_required(
    api_config_key: str = "API_KEY",
) -> Callable:
    """A decorator to restrict route access to requests with an API key. 

    This should be used to wrap a route handler (or view function) to
    enforce that only api key authenticated requests can access it. The
    key value is configurable via the app configuration with API_KEY key
    used by default. Note that it is important that this decorator be 
    wrapped by the route decorator and not vice, versa, as below.

    .. code-block:: python

        @app.route('/')
        @api_key_required()
        async def index():
            ...

    If the request is not authenticated a
    `werkzeug.exceptions.Unauthorized` exception will be raised.

    """

    def decorator(func: Callable) -> Callable:
        @wraps(func)
        async def wrapper(*args: Any, **kwargs: Any) -> Any:
            if has_request_context():
                api_key = request.headers.get("X-API-Key", "")
            elif has_websocket_context():
                api_key = websocket.headers.get("X-API-Key", "")
            else:
                raise RuntimeError("Not used in a valid request/websocket context")

            if (compare_digest(api_key, current_app.config[api_config_key])):
                return await current_app.ensure_async(func)(*args, **kwargs)
            else:
                raise Unauthorized()

        return wrapper

    return decorator

For query string or cookie based API keys request.args and request.cookies can be used instead of request.headers.

  • Related