Request Headers

Headers dataclass

A dataclass representing the headers of an HTTP request. This is primarily used for extracting authentication tokens and API keys from the request headers and cookies.

This class provides a convenient way to access authentication tokens and API keys, regardless of whether they are provided in the standard headers or in cookies. It provides properties to check the presence of these tokens and keys.

This class is designed to be immutable and uses slots for memory efficiency.

Attributes:
  • auth_token (str | None) –

    The authentication token, typically a JWT, extracted from the "Authorization" header or from cookies.

  • auth_token_type (str | None) –

    The type of the authentication token, typically "Bearer".

  • refresh_token (str | None) –

    The refresh token, extracted from the "X-Refresh-Token" header or from cookies.

  • api_key (str | None) –

    The API key, extracted from the "X-API-Key" header or from cookies.

  • cookies (dict[str, str]) –

    A mapping of cookie names to their values, if any cookies are present.

Source code in src/alpha/utils/request_headers.py
@dataclass(frozen=True, slots=True)
class Headers:
    """A dataclass representing the headers of an HTTP request. This is
    primarily used for extracting authentication tokens and API keys from the
    request headers and cookies.

    This class provides a convenient way to access authentication tokens and
    API keys, regardless of whether they are provided in the standard headers
    or in cookies. It provides properties to check the presence of these tokens
    and keys.

    This class is designed to be immutable and uses slots for memory
    efficiency.

    Attributes
    ----------
    auth_token
        The authentication token, typically a JWT, extracted from the
        "Authorization" header or from cookies.
    auth_token_type
        The type of the authentication token, typically "Bearer".
    refresh_token
        The refresh token, extracted from the "X-Refresh-Token" header or from
        cookies.
    api_key
        The API key, extracted from the "X-API-Key" header or from cookies.
    cookies
        A mapping of cookie names to their values, if any cookies are present.
    """

    auth_token: str | None = None
    auth_token_type: str | None = None
    refresh_token: str | None = None
    api_key: str | None = None
    _cookie_jar: SimpleCookie | None = None

    @classmethod
    def from_headers(
        cls,
        headers: Mapping[str, str],
        auth_token_cookie_name: str = "auth_token",
        refresh_token_cookie_name: str = "refresh_token",
        api_key_cookie_name: str = "api_key",
    ) -> Self:
        """Create a Headers instance from a mapping of headers.

        For the auth token, the method first checks the "Authorization" header.
        If present, it extracts the token and its type (e.g., "Bearer"). If it
        is not present, it looks for a cookie with the name specified by
        `auth_token_cookie_name`. The same logic applies to the refresh token
        and API key, checking the "X-Refresh-Token" and "X-API-Key" headers. If
        they are not present, it looks for cookies with the names specified by
        `refresh_token_cookie_name` and `api_key_cookie_name`.

        Parameters
        ----------
        headers
            A mapping of header names to their values.
        auth_token_cookie_name
            The name of the cookie containing the auth token, default is
            "auth_token".
        refresh_token_cookie_name
            The name of the cookie containing the refresh token, default is
            "refresh_token".
        api_key_cookie_name
            The name of the cookie containing the API key, default is
            "api_key".

        Returns
        -------
            An instance of the Headers class.
        """
        auth_token = None
        auth_token_type = None
        authorization_header = headers.get("Authorization")
        if authorization_header is not None:
            parts = authorization_header.split()
            if len(parts) == 2:
                auth_token_type, auth_token = parts
                if auth_token_type.lower() == "bearer":
                    auth_token_type = "Bearer"

        refresh_token = headers.get("X-Refresh-Token")
        api_key = headers.get("X-API-Key")
        cookies_header = headers.get("Cookie")

        cookie_jar: SimpleCookie | None = None
        if cookies_header is not None:
            cookie_jar = SimpleCookie(cookies_header)

            if not auth_token and auth_token_cookie_name in cookie_jar:
                auth_token = cookie_jar[auth_token_cookie_name].value
                auth_token_type = "Bearer"
            if not refresh_token and refresh_token_cookie_name in cookie_jar:
                refresh_token = cookie_jar[refresh_token_cookie_name].value
            if not api_key and api_key_cookie_name in cookie_jar:
                api_key = cookie_jar[api_key_cookie_name].value

        return cls(
            auth_token=auth_token,
            auth_token_type=auth_token_type,
            refresh_token=refresh_token,
            api_key=api_key,
            _cookie_jar=cookie_jar,
        )

    @property
    def has_auth_token(self) -> bool:
        if not self.auth_token:
            return False
        if not self.auth_token_type:
            return False
        return self.auth_token_type.lower() == "bearer"

    @property
    def has_refresh_token(self) -> bool:
        return True if self.refresh_token else False

    @property
    def has_api_key(self) -> bool:
        return True if self.api_key else False

    @property
    def cookies(self) -> dict[str, str]:
        """Return a dictionary of cookies extracted from the request headers.

        Returns
        -------
        dict[str, str]
            A dictionary mapping cookie names to their values. If no cookies
            are present, an empty dictionary is returned.
        """
        if self._cookie_jar is None:
            return {}
        return self._cookie_jar_to_dict(self._cookie_jar)

    def __repr__(self) -> str:
        return (
            f"Headers(auth_token={'***' if self.auth_token else None}, "
            f"auth_token_type={self.auth_token_type}, "
            f"refresh_token={'***' if self.refresh_token else None}, "
            f"api_key={'***' if self.api_key else None})"
        )

    @staticmethod
    def _cookie_jar_to_dict(cookie_jar: SimpleCookie) -> dict[str, str]:
        """Convert a SimpleCookie object to a dictionary.

        Parameters
        ----------
        cookie_jar
            A SimpleCookie object containing the cookies.

        Returns
        -------
        dict[str, str]
            A dictionary mapping cookie names to their values.
        """
        return {key: morsel.value for key, morsel in cookie_jar.items()}

cookies property
cookies

Return a dictionary of cookies extracted from the request headers.

Returns:
  • dict[str, str] –

    A dictionary mapping cookie names to their values. If no cookies are present, an empty dictionary is returned.

Methods:

from_headers classmethod
from_headers(headers, auth_token_cookie_name='auth_token', refresh_token_cookie_name='refresh_token', api_key_cookie_name='api_key')

Create a Headers instance from a mapping of headers.

For the auth token, the method first checks the "Authorization" header. If present, it extracts the token and its type (e.g., "Bearer"). If it is not present, it looks for a cookie with the name specified by auth_token_cookie_name. The same logic applies to the refresh token and API key, checking the "X-Refresh-Token" and "X-API-Key" headers. If they are not present, it looks for cookies with the names specified by refresh_token_cookie_name and api_key_cookie_name.

Parameters:
  • headers (Mapping[str, str]) –

    A mapping of header names to their values.

  • auth_token_cookie_name (str, default: 'auth_token' ) –

    The name of the cookie containing the auth token, default is "auth_token".

  • refresh_token_cookie_name (str, default: 'refresh_token' ) –

    The name of the cookie containing the refresh token, default is "refresh_token".

  • api_key_cookie_name (str, default: 'api_key' ) –

    The name of the cookie containing the API key, default is "api_key".

Returns:
  • An instance of the Headers class. –
Source code in src/alpha/utils/request_headers.py
@classmethod
def from_headers(
    cls,
    headers: Mapping[str, str],
    auth_token_cookie_name: str = "auth_token",
    refresh_token_cookie_name: str = "refresh_token",
    api_key_cookie_name: str = "api_key",
) -> Self:
    """Create a Headers instance from a mapping of headers.

    For the auth token, the method first checks the "Authorization" header.
    If present, it extracts the token and its type (e.g., "Bearer"). If it
    is not present, it looks for a cookie with the name specified by
    `auth_token_cookie_name`. The same logic applies to the refresh token
    and API key, checking the "X-Refresh-Token" and "X-API-Key" headers. If
    they are not present, it looks for cookies with the names specified by
    `refresh_token_cookie_name` and `api_key_cookie_name`.

    Parameters
    ----------
    headers
        A mapping of header names to their values.
    auth_token_cookie_name
        The name of the cookie containing the auth token, default is
        "auth_token".
    refresh_token_cookie_name
        The name of the cookie containing the refresh token, default is
        "refresh_token".
    api_key_cookie_name
        The name of the cookie containing the API key, default is
        "api_key".

    Returns
    -------
        An instance of the Headers class.
    """
    auth_token = None
    auth_token_type = None
    authorization_header = headers.get("Authorization")
    if authorization_header is not None:
        parts = authorization_header.split()
        if len(parts) == 2:
            auth_token_type, auth_token = parts
            if auth_token_type.lower() == "bearer":
                auth_token_type = "Bearer"

    refresh_token = headers.get("X-Refresh-Token")
    api_key = headers.get("X-API-Key")
    cookies_header = headers.get("Cookie")

    cookie_jar: SimpleCookie | None = None
    if cookies_header is not None:
        cookie_jar = SimpleCookie(cookies_header)

        if not auth_token and auth_token_cookie_name in cookie_jar:
            auth_token = cookie_jar[auth_token_cookie_name].value
            auth_token_type = "Bearer"
        if not refresh_token and refresh_token_cookie_name in cookie_jar:
            refresh_token = cookie_jar[refresh_token_cookie_name].value
        if not api_key and api_key_cookie_name in cookie_jar:
            api_key = cookie_jar[api_key_cookie_name].value

    return cls(
        auth_token=auth_token,
        auth_token_type=auth_token_type,
        refresh_token=refresh_token,
        api_key=api_key,
        _cookie_jar=cookie_jar,
    )