Skip to content

RFC: Add a mechanism for passing authorization headers to child links #886

@john-dupuy

Description

@john-dupuy

I recently discovered this project and it's awesome! I am dealing with a STAC catalog that requires authentication and I noticed that there is no mechanism for me to pass an auth header for when I want to walk a STAC catalog.

As a simple scenario consider the following:

from pystac import Catalog
catalog =  Catalog.from_dict(requests.get(<stac-url-requiring-auth>, headers={"Authorization": "api-key <my-api-key>"}))
catalog.validate_all()

In this situation, we will get an exception at the first link with an exception:

urllib.error.HTTPError: HTTP Error 401: Unauthorized

coming from this line:

pystac/stac_io.py", line 292, in read_text_from_href
    with urlopen(href) as f:

It would be great if we could add an auth header when we create the STAC object. As a workaround I created a class like

class StacIOWithAuth(DefaultStacIO):
    """Override 'read_text_from_href' so that we can add authn (api-key) to the requests that pystac makes."""

    def __init__(self, api_key):
        self.api_key = api_key

    def read_text_from_href(self, href: str) -> str:
        """Reads file as a UTF-8 string.

        If ``href`` has a "scheme" (e.g. if it starts with "https://") then this will
        use :func:`urllib.request.urlopen` to open the file and read the contents;
        otherwise, :func:`open` will be used to open a local file.

        Args:

            href : The URI of the file to open.
        """
        parsed = safe_urlparse(href)
        href_contents: str
        if parsed.scheme != "":
            try:
                req = Request(href, headers={"Authorization": f"api-key {self.api_key}"})
                with urlopen(req) as f:
                    href_contents = f.read().decode("utf-8")
            except HTTPError as e:
                raise Exception("Could not read uri {}".format(href)) from e
        else:
            with open(href, encoding="utf-8") as f:
                href_contents = f.read()
        return href_contents

And then just set catalog._stac_io = StacIOWithAuth(<api_key>).

Thanks for reading - I'm happy to take this on as a first issue if no one has bandwidth to tackle it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions