about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/google/auth/transport
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/google/auth/transport
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/google/auth/transport')
-rw-r--r--.venv/lib/python3.12/site-packages/google/auth/transport/__init__.py103
-rw-r--r--.venv/lib/python3.12/site-packages/google/auth/transport/_aiohttp_requests.py391
-rw-r--r--.venv/lib/python3.12/site-packages/google/auth/transport/_custom_tls_signer.py283
-rw-r--r--.venv/lib/python3.12/site-packages/google/auth/transport/_http_client.py113
-rw-r--r--.venv/lib/python3.12/site-packages/google/auth/transport/_mtls_helper.py407
-rw-r--r--.venv/lib/python3.12/site-packages/google/auth/transport/_requests_base.py53
-rw-r--r--.venv/lib/python3.12/site-packages/google/auth/transport/grpc.py343
-rw-r--r--.venv/lib/python3.12/site-packages/google/auth/transport/mtls.py112
-rw-r--r--.venv/lib/python3.12/site-packages/google/auth/transport/requests.py599
-rw-r--r--.venv/lib/python3.12/site-packages/google/auth/transport/urllib3.py444
10 files changed, 2848 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/google/auth/transport/__init__.py b/.venv/lib/python3.12/site-packages/google/auth/transport/__init__.py
new file mode 100644
index 00000000..724568e5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/google/auth/transport/__init__.py
@@ -0,0 +1,103 @@
+# Copyright 2016 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Transport - HTTP client library support.
+
+:mod:`google.auth` is designed to work with various HTTP client libraries such
+as urllib3 and requests. In order to work across these libraries with different
+interfaces some abstraction is needed.
+
+This module provides two interfaces that are implemented by transport adapters
+to support HTTP libraries. :class:`Request` defines the interface expected by
+:mod:`google.auth` to make requests. :class:`Response` defines the interface
+for the return value of :class:`Request`.
+"""
+
+import abc
+import http.client as http_client
+
+DEFAULT_RETRYABLE_STATUS_CODES = (
+    http_client.INTERNAL_SERVER_ERROR,
+    http_client.SERVICE_UNAVAILABLE,
+    http_client.REQUEST_TIMEOUT,
+    http_client.TOO_MANY_REQUESTS,
+)
+"""Sequence[int]:  HTTP status codes indicating a request can be retried.
+"""
+
+
+DEFAULT_REFRESH_STATUS_CODES = (http_client.UNAUTHORIZED,)
+"""Sequence[int]:  Which HTTP status code indicate that credentials should be
+refreshed.
+"""
+
+DEFAULT_MAX_REFRESH_ATTEMPTS = 2
+"""int: How many times to refresh the credentials and retry a request."""
+
+
+class Response(metaclass=abc.ABCMeta):
+    """HTTP Response data."""
+
+    @abc.abstractproperty
+    def status(self):
+        """int: The HTTP status code."""
+        raise NotImplementedError("status must be implemented.")
+
+    @abc.abstractproperty
+    def headers(self):
+        """Mapping[str, str]: The HTTP response headers."""
+        raise NotImplementedError("headers must be implemented.")
+
+    @abc.abstractproperty
+    def data(self):
+        """bytes: The response body."""
+        raise NotImplementedError("data must be implemented.")
+
+
+class Request(metaclass=abc.ABCMeta):
+    """Interface for a callable that makes HTTP requests.
+
+    Specific transport implementations should provide an implementation of
+    this that adapts their specific request / response API.
+
+    .. automethod:: __call__
+    """
+
+    @abc.abstractmethod
+    def __call__(
+        self, url, method="GET", body=None, headers=None, timeout=None, **kwargs
+    ):
+        """Make an HTTP request.
+
+        Args:
+            url (str): The URI to be requested.
+            method (str): The HTTP method to use for the request. Defaults
+                to 'GET'.
+            body (bytes): The payload / body in HTTP request.
+            headers (Mapping[str, str]): Request headers.
+            timeout (Optional[int]): The number of seconds to wait for a
+                response from the server. If not specified or if None, the
+                transport-specific default timeout will be used.
+            kwargs: Additionally arguments passed on to the transport's
+                request method.
+
+        Returns:
+            Response: The HTTP response.
+
+        Raises:
+            google.auth.exceptions.TransportError: If any exception occurred.
+        """
+        # pylint: disable=redundant-returns-doc, missing-raises-doc
+        # (pylint doesn't play well with abstract docstrings.)
+        raise NotImplementedError("__call__ must be implemented.")
diff --git a/.venv/lib/python3.12/site-packages/google/auth/transport/_aiohttp_requests.py b/.venv/lib/python3.12/site-packages/google/auth/transport/_aiohttp_requests.py
new file mode 100644
index 00000000..bc4d9dc6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/google/auth/transport/_aiohttp_requests.py
@@ -0,0 +1,391 @@
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Transport adapter for Async HTTP (aiohttp).
+
+NOTE: This async support is experimental and marked internal. This surface may
+change in minor releases.
+"""
+
+from __future__ import absolute_import
+
+import asyncio
+import functools
+
+import aiohttp  # type: ignore
+import urllib3  # type: ignore
+
+from google.auth import exceptions
+from google.auth import transport
+from google.auth.transport import requests
+
+# Timeout can be re-defined depending on async requirement. Currently made 60s more than
+# sync timeout.
+_DEFAULT_TIMEOUT = 180  # in seconds
+
+
+class _CombinedResponse(transport.Response):
+    """
+    In order to more closely resemble the `requests` interface, where a raw
+    and deflated content could be accessed at once, this class lazily reads the
+    stream in `transport.Response` so both return forms can be used.
+
+    The gzip and deflate transfer-encodings are automatically decoded for you
+    because the default parameter for autodecompress into the ClientSession is set
+    to False, and therefore we add this class to act as a wrapper for a user to be
+    able to access both the raw and decoded response bodies - mirroring the sync
+    implementation.
+    """
+
+    def __init__(self, response):
+        self._response = response
+        self._raw_content = None
+
+    def _is_compressed(self):
+        headers = self._response.headers
+        return "Content-Encoding" in headers and (
+            headers["Content-Encoding"] == "gzip"
+            or headers["Content-Encoding"] == "deflate"
+        )
+
+    @property
+    def status(self):
+        return self._response.status
+
+    @property
+    def headers(self):
+        return self._response.headers
+
+    @property
+    def data(self):
+        return self._response.content
+
+    async def raw_content(self):
+        if self._raw_content is None:
+            self._raw_content = await self._response.content.read()
+        return self._raw_content
+
+    async def content(self):
+        # Load raw_content if necessary
+        await self.raw_content()
+        if self._is_compressed():
+            decoder = urllib3.response.MultiDecoder(
+                self._response.headers["Content-Encoding"]
+            )
+            decompressed = decoder.decompress(self._raw_content)
+            return decompressed
+
+        return self._raw_content
+
+
+class _Response(transport.Response):
+    """
+    Requests transport response adapter.
+
+    Args:
+        response (requests.Response): The raw Requests response.
+    """
+
+    def __init__(self, response):
+        self._response = response
+
+    @property
+    def status(self):
+        return self._response.status
+
+    @property
+    def headers(self):
+        return self._response.headers
+
+    @property
+    def data(self):
+        return self._response.content
+
+
+class Request(transport.Request):
+    """Requests request adapter.
+
+    This class is used internally for making requests using asyncio transports
+    in a consistent way. If you use :class:`AuthorizedSession` you do not need
+    to construct or use this class directly.
+
+    This class can be useful if you want to manually refresh a
+    :class:`~google.auth.credentials.Credentials` instance::
+
+        import google.auth.transport.aiohttp_requests
+
+        request = google.auth.transport.aiohttp_requests.Request()
+
+        credentials.refresh(request)
+
+    Args:
+        session (aiohttp.ClientSession): An instance :class:`aiohttp.ClientSession` used
+            to make HTTP requests. If not specified, a session will be created.
+
+    .. automethod:: __call__
+    """
+
+    def __init__(self, session=None):
+        # TODO: Use auto_decompress property for aiohttp 3.7+
+        if session is not None and session._auto_decompress:
+            raise exceptions.InvalidOperation(
+                "Client sessions with auto_decompress=True are not supported."
+            )
+        self.session = session
+
+    async def __call__(
+        self,
+        url,
+        method="GET",
+        body=None,
+        headers=None,
+        timeout=_DEFAULT_TIMEOUT,
+        **kwargs,
+    ):
+        """
+        Make an HTTP request using aiohttp.
+
+        Args:
+            url (str): The URL to be requested.
+            method (Optional[str]):
+                The HTTP method to use for the request. Defaults to 'GET'.
+            body (Optional[bytes]):
+                The payload or body in HTTP request.
+            headers (Optional[Mapping[str, str]]):
+                Request headers.
+            timeout (Optional[int]): The number of seconds to wait for a
+                response from the server. If not specified or if None, the
+                requests default timeout will be used.
+            kwargs: Additional arguments passed through to the underlying
+                requests :meth:`requests.Session.request` method.
+
+        Returns:
+            google.auth.transport.Response: The HTTP response.
+
+        Raises:
+            google.auth.exceptions.TransportError: If any exception occurred.
+        """
+
+        try:
+            if self.session is None:  # pragma: NO COVER
+                self.session = aiohttp.ClientSession(
+                    auto_decompress=False
+                )  # pragma: NO COVER
+            requests._LOGGER.debug("Making request: %s %s", method, url)
+            response = await self.session.request(
+                method, url, data=body, headers=headers, timeout=timeout, **kwargs
+            )
+            return _CombinedResponse(response)
+
+        except aiohttp.ClientError as caught_exc:
+            new_exc = exceptions.TransportError(caught_exc)
+            raise new_exc from caught_exc
+
+        except asyncio.TimeoutError as caught_exc:
+            new_exc = exceptions.TransportError(caught_exc)
+            raise new_exc from caught_exc
+
+
+class AuthorizedSession(aiohttp.ClientSession):
+    """This is an async implementation of the Authorized Session class. We utilize an
+    aiohttp transport instance, and the interface mirrors the google.auth.transport.requests
+    Authorized Session class, except for the change in the transport used in the async use case.
+
+    A Requests Session class with credentials.
+
+    This class is used to perform requests to API endpoints that require
+    authorization::
+
+        from google.auth.transport import aiohttp_requests
+
+        async with aiohttp_requests.AuthorizedSession(credentials) as authed_session:
+            response = await authed_session.request(
+                'GET', 'https://www.googleapis.com/storage/v1/b')
+
+    The underlying :meth:`request` implementation handles adding the
+    credentials' headers to the request and refreshing credentials as needed.
+
+    Args:
+        credentials (google.auth._credentials_async.Credentials):
+            The credentials to add to the request.
+        refresh_status_codes (Sequence[int]): Which HTTP status codes indicate
+            that credentials should be refreshed and the request should be
+            retried.
+        max_refresh_attempts (int): The maximum number of times to attempt to
+            refresh the credentials and retry the request.
+        refresh_timeout (Optional[int]): The timeout value in seconds for
+            credential refresh HTTP requests.
+        auth_request (google.auth.transport.aiohttp_requests.Request):
+            (Optional) An instance of
+            :class:`~google.auth.transport.aiohttp_requests.Request` used when
+            refreshing credentials. If not passed,
+            an instance of :class:`~google.auth.transport.aiohttp_requests.Request`
+            is created.
+        kwargs: Additional arguments passed through to the underlying
+            ClientSession :meth:`aiohttp.ClientSession` object.
+    """
+
+    def __init__(
+        self,
+        credentials,
+        refresh_status_codes=transport.DEFAULT_REFRESH_STATUS_CODES,
+        max_refresh_attempts=transport.DEFAULT_MAX_REFRESH_ATTEMPTS,
+        refresh_timeout=None,
+        auth_request=None,
+        auto_decompress=False,
+        **kwargs,
+    ):
+        super(AuthorizedSession, self).__init__(**kwargs)
+        self.credentials = credentials
+        self._refresh_status_codes = refresh_status_codes
+        self._max_refresh_attempts = max_refresh_attempts
+        self._refresh_timeout = refresh_timeout
+        self._is_mtls = False
+        self._auth_request = auth_request
+        self._auth_request_session = None
+        self._loop = asyncio.get_event_loop()
+        self._refresh_lock = asyncio.Lock()
+        self._auto_decompress = auto_decompress
+
+    async def request(
+        self,
+        method,
+        url,
+        data=None,
+        headers=None,
+        max_allowed_time=None,
+        timeout=_DEFAULT_TIMEOUT,
+        auto_decompress=False,
+        **kwargs,
+    ):
+
+        """Implementation of Authorized Session aiohttp request.
+
+        Args:
+            method (str):
+                The http request method used (e.g. GET, PUT, DELETE)
+            url (str):
+                The url at which the http request is sent.
+            data (Optional[dict]): Dictionary, list of tuples, bytes, or file-like
+                object to send in the body of the Request.
+            headers (Optional[dict]): Dictionary of HTTP Headers to send with the
+                Request.
+            timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
+                The amount of time in seconds to wait for the server response
+                with each individual request. Can also be passed as an
+                ``aiohttp.ClientTimeout`` object.
+            max_allowed_time (Optional[float]):
+                If the method runs longer than this, a ``Timeout`` exception is
+                automatically raised. Unlike the ``timeout`` parameter, this
+                value applies to the total method execution time, even if
+                multiple requests are made under the hood.
+
+                Mind that it is not guaranteed that the timeout error is raised
+                at ``max_allowed_time``. It might take longer, for example, if
+                an underlying request takes a lot of time, but the request
+                itself does not timeout, e.g. if a large file is being
+                transmitted. The timout error will be raised after such
+                request completes.
+        """
+        # Headers come in as bytes which isn't expected behavior, the resumable
+        # media libraries in some cases expect a str type for the header values,
+        # but sometimes the operations return these in bytes types.
+        if headers:
+            for key in headers.keys():
+                if type(headers[key]) is bytes:
+                    headers[key] = headers[key].decode("utf-8")
+
+        async with aiohttp.ClientSession(
+            auto_decompress=self._auto_decompress,
+            trust_env=kwargs.get("trust_env", False),
+        ) as self._auth_request_session:
+            auth_request = Request(self._auth_request_session)
+            self._auth_request = auth_request
+
+            # Use a kwarg for this instead of an attribute to maintain
+            # thread-safety.
+            _credential_refresh_attempt = kwargs.pop("_credential_refresh_attempt", 0)
+            # Make a copy of the headers. They will be modified by the credentials
+            # and we want to pass the original headers if we recurse.
+            request_headers = headers.copy() if headers is not None else {}
+
+            # Do not apply the timeout unconditionally in order to not override the
+            # _auth_request's default timeout.
+            auth_request = (
+                self._auth_request
+                if timeout is None
+                else functools.partial(self._auth_request, timeout=timeout)
+            )
+
+            remaining_time = max_allowed_time
+
+            with requests.TimeoutGuard(remaining_time, asyncio.TimeoutError) as guard:
+                await self.credentials.before_request(
+                    auth_request, method, url, request_headers
+                )
+
+            with requests.TimeoutGuard(remaining_time, asyncio.TimeoutError) as guard:
+                response = await super(AuthorizedSession, self).request(
+                    method,
+                    url,
+                    data=data,
+                    headers=request_headers,
+                    timeout=timeout,
+                    **kwargs,
+                )
+
+            remaining_time = guard.remaining_timeout
+
+            if (
+                response.status in self._refresh_status_codes
+                and _credential_refresh_attempt < self._max_refresh_attempts
+            ):
+
+                requests._LOGGER.info(
+                    "Refreshing credentials due to a %s response. Attempt %s/%s.",
+                    response.status,
+                    _credential_refresh_attempt + 1,
+                    self._max_refresh_attempts,
+                )
+
+                # Do not apply the timeout unconditionally in order to not override the
+                # _auth_request's default timeout.
+                auth_request = (
+                    self._auth_request
+                    if timeout is None
+                    else functools.partial(self._auth_request, timeout=timeout)
+                )
+
+                with requests.TimeoutGuard(
+                    remaining_time, asyncio.TimeoutError
+                ) as guard:
+                    async with self._refresh_lock:
+                        await self._loop.run_in_executor(
+                            None, self.credentials.refresh, auth_request
+                        )
+
+                remaining_time = guard.remaining_timeout
+
+                return await self.request(
+                    method,
+                    url,
+                    data=data,
+                    headers=headers,
+                    max_allowed_time=remaining_time,
+                    timeout=timeout,
+                    _credential_refresh_attempt=_credential_refresh_attempt + 1,
+                    **kwargs,
+                )
+
+        return response
diff --git a/.venv/lib/python3.12/site-packages/google/auth/transport/_custom_tls_signer.py b/.venv/lib/python3.12/site-packages/google/auth/transport/_custom_tls_signer.py
new file mode 100644
index 00000000..9279158d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/google/auth/transport/_custom_tls_signer.py
@@ -0,0 +1,283 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Code for configuring client side TLS to offload the signing operation to
+signing libraries.
+"""
+
+import ctypes
+import json
+import logging
+import os
+import sys
+
+import cffi  # type: ignore
+
+from google.auth import exceptions
+
+_LOGGER = logging.getLogger(__name__)
+
+# C++ offload lib requires google-auth lib to provide the following callback:
+#     using SignFunc = int (*)(unsigned char *sig, size_t *sig_len,
+#             const unsigned char *tbs, size_t tbs_len)
+# The bytes to be signed and the length are provided via `tbs` and `tbs_len`,
+# the callback computes the signature, and write the signature and its length
+# into `sig` and `sig_len`.
+# If the signing is successful, the callback returns 1, otherwise it returns 0.
+SIGN_CALLBACK_CTYPE = ctypes.CFUNCTYPE(
+    ctypes.c_int,  # return type
+    ctypes.POINTER(ctypes.c_ubyte),  # sig
+    ctypes.POINTER(ctypes.c_size_t),  # sig_len
+    ctypes.POINTER(ctypes.c_ubyte),  # tbs
+    ctypes.c_size_t,  # tbs_len
+)
+
+
+# Cast SSL_CTX* to void*
+def _cast_ssl_ctx_to_void_p_pyopenssl(ssl_ctx):
+    return ctypes.cast(int(cffi.FFI().cast("intptr_t", ssl_ctx)), ctypes.c_void_p)
+
+
+# Cast SSL_CTX* to void*
+def _cast_ssl_ctx_to_void_p_stdlib(context):
+    return ctypes.c_void_p.from_address(
+        id(context) + ctypes.sizeof(ctypes.c_void_p) * 2
+    )
+
+
+# Load offload library and set up the function types.
+def load_offload_lib(offload_lib_path):
+    _LOGGER.debug("loading offload library from %s", offload_lib_path)
+
+    # winmode parameter is only available for python 3.8+.
+    lib = (
+        ctypes.CDLL(offload_lib_path, winmode=0)
+        if sys.version_info >= (3, 8) and os.name == "nt"
+        else ctypes.CDLL(offload_lib_path)
+    )
+
+    # Set up types for:
+    # int ConfigureSslContext(SignFunc sign_func, const char *cert, SSL_CTX *ctx)
+    lib.ConfigureSslContext.argtypes = [
+        SIGN_CALLBACK_CTYPE,
+        ctypes.c_char_p,
+        ctypes.c_void_p,
+    ]
+    lib.ConfigureSslContext.restype = ctypes.c_int
+
+    return lib
+
+
+# Load signer library and set up the function types.
+# See: https://github.com/googleapis/enterprise-certificate-proxy/blob/main/cshared/main.go
+def load_signer_lib(signer_lib_path):
+    _LOGGER.debug("loading signer library from %s", signer_lib_path)
+
+    # winmode parameter is only available for python 3.8+.
+    lib = (
+        ctypes.CDLL(signer_lib_path, winmode=0)
+        if sys.version_info >= (3, 8) and os.name == "nt"
+        else ctypes.CDLL(signer_lib_path)
+    )
+
+    # Set up types for:
+    # func GetCertPemForPython(configFilePath *C.char, certHolder *byte, certHolderLen int)
+    lib.GetCertPemForPython.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int]
+    # Returns: certLen
+    lib.GetCertPemForPython.restype = ctypes.c_int
+
+    # Set up types for:
+    # func SignForPython(configFilePath *C.char, digest *byte, digestLen int,
+    #     sigHolder *byte, sigHolderLen int)
+    lib.SignForPython.argtypes = [
+        ctypes.c_char_p,
+        ctypes.c_char_p,
+        ctypes.c_int,
+        ctypes.c_char_p,
+        ctypes.c_int,
+    ]
+    # Returns: the signature length
+    lib.SignForPython.restype = ctypes.c_int
+
+    return lib
+
+
+def load_provider_lib(provider_lib_path):
+    _LOGGER.debug("loading provider library from %s", provider_lib_path)
+
+    # winmode parameter is only available for python 3.8+.
+    lib = (
+        ctypes.CDLL(provider_lib_path, winmode=0)
+        if sys.version_info >= (3, 8) and os.name == "nt"
+        else ctypes.CDLL(provider_lib_path)
+    )
+
+    lib.ECP_attach_to_ctx.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
+    lib.ECP_attach_to_ctx.restype = ctypes.c_int
+
+    return lib
+
+
+# Computes SHA256 hash.
+def _compute_sha256_digest(to_be_signed, to_be_signed_len):
+    from cryptography.hazmat.primitives import hashes
+
+    data = ctypes.string_at(to_be_signed, to_be_signed_len)
+    hash = hashes.Hash(hashes.SHA256())
+    hash.update(data)
+    return hash.finalize()
+
+
+# Create the signing callback. The actual signing work is done by the
+# `SignForPython` method from the signer lib.
+def get_sign_callback(signer_lib, config_file_path):
+    def sign_callback(sig, sig_len, tbs, tbs_len):
+        _LOGGER.debug("calling sign callback...")
+
+        digest = _compute_sha256_digest(tbs, tbs_len)
+        digestArray = ctypes.c_char * len(digest)
+
+        # reserve 2000 bytes for the signature, shoud be more then enough.
+        # RSA signature is 256 bytes, EC signature is 70~72.
+        sig_holder_len = 2000
+        sig_holder = ctypes.create_string_buffer(sig_holder_len)
+
+        signature_len = signer_lib.SignForPython(
+            config_file_path.encode(),  # configFilePath
+            digestArray.from_buffer(bytearray(digest)),  # digest
+            len(digest),  # digestLen
+            sig_holder,  # sigHolder
+            sig_holder_len,  # sigHolderLen
+        )
+
+        if signature_len == 0:
+            # signing failed, return 0
+            return 0
+
+        sig_len[0] = signature_len
+        bs = bytearray(sig_holder)
+        for i in range(signature_len):
+            sig[i] = bs[i]
+
+        return 1
+
+    return SIGN_CALLBACK_CTYPE(sign_callback)
+
+
+# Obtain the certificate bytes by calling the `GetCertPemForPython` method from
+# the signer lib. The method is called twice, the first time is to compute the
+# cert length, then we create a buffer to hold the cert, and call it again to
+# fill the buffer.
+def get_cert(signer_lib, config_file_path):
+    # First call to calculate the cert length
+    cert_len = signer_lib.GetCertPemForPython(
+        config_file_path.encode(),  # configFilePath
+        None,  # certHolder
+        0,  # certHolderLen
+    )
+    if cert_len == 0:
+        raise exceptions.MutualTLSChannelError("failed to get certificate")
+
+    # Then we create an array to hold the cert, and call again to fill the cert
+    cert_holder = ctypes.create_string_buffer(cert_len)
+    signer_lib.GetCertPemForPython(
+        config_file_path.encode(),  # configFilePath
+        cert_holder,  # certHolder
+        cert_len,  # certHolderLen
+    )
+    return bytes(cert_holder)
+
+
+class CustomTlsSigner(object):
+    def __init__(self, enterprise_cert_file_path):
+        """
+        This class loads the offload and signer library, and calls APIs from
+        these libraries to obtain the cert and a signing callback, and attach
+        them to SSL context. The cert and the signing callback will be used
+        for client authentication in TLS handshake.
+
+        Args:
+            enterprise_cert_file_path (str): the path to a enterprise cert JSON
+                file. The file should contain the following field:
+
+                    {
+                        "libs": {
+                            "ecp_client": "...",
+                            "tls_offload": "..."
+                        }
+                    }
+        """
+        self._enterprise_cert_file_path = enterprise_cert_file_path
+        self._cert = None
+        self._sign_callback = None
+        self._provider_lib = None
+
+    def load_libraries(self):
+        with open(self._enterprise_cert_file_path, "r") as f:
+            enterprise_cert_json = json.load(f)
+            libs = enterprise_cert_json.get("libs", {})
+
+            signer_library = libs.get("ecp_client", None)
+            offload_library = libs.get("tls_offload", None)
+            provider_library = libs.get("ecp_provider", None)
+
+        # Using newer provider implementation. This is mutually exclusive to the
+        # offload implementation.
+        if provider_library:
+            self._provider_lib = load_provider_lib(provider_library)
+            return
+
+        # Using old offload implementation
+        if offload_library and signer_library:
+            self._offload_lib = load_offload_lib(offload_library)
+            self._signer_lib = load_signer_lib(signer_library)
+            self.set_up_custom_key()
+            return
+
+        raise exceptions.MutualTLSChannelError("enterprise cert file is invalid")
+
+    def set_up_custom_key(self):
+        # We need to keep a reference of the cert and sign callback so it won't
+        # be garbage collected, otherwise it will crash when used by signer lib.
+        self._cert = get_cert(self._signer_lib, self._enterprise_cert_file_path)
+        self._sign_callback = get_sign_callback(
+            self._signer_lib, self._enterprise_cert_file_path
+        )
+
+    def should_use_provider(self):
+        if self._provider_lib:
+            return True
+        return False
+
+    def attach_to_ssl_context(self, ctx):
+        if self.should_use_provider():
+            if not self._provider_lib.ECP_attach_to_ctx(
+                _cast_ssl_ctx_to_void_p_stdlib(ctx),
+                self._enterprise_cert_file_path.encode("ascii"),
+            ):
+                raise exceptions.MutualTLSChannelError(
+                    "failed to configure ECP Provider SSL context"
+                )
+        elif self._offload_lib and self._signer_lib:
+            if not self._offload_lib.ConfigureSslContext(
+                self._sign_callback,
+                ctypes.c_char_p(self._cert),
+                _cast_ssl_ctx_to_void_p_pyopenssl(ctx._ctx._context),
+            ):
+                raise exceptions.MutualTLSChannelError(
+                    "failed to configure ECP Offload SSL context"
+                )
+        else:
+            raise exceptions.MutualTLSChannelError("Invalid ECP configuration.")
diff --git a/.venv/lib/python3.12/site-packages/google/auth/transport/_http_client.py b/.venv/lib/python3.12/site-packages/google/auth/transport/_http_client.py
new file mode 100644
index 00000000..cec0ab73
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/google/auth/transport/_http_client.py
@@ -0,0 +1,113 @@
+# Copyright 2016 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Transport adapter for http.client, for internal use only."""
+
+import http.client as http_client
+import logging
+import socket
+import urllib
+
+from google.auth import exceptions
+from google.auth import transport
+
+_LOGGER = logging.getLogger(__name__)
+
+
+class Response(transport.Response):
+    """http.client transport response adapter.
+
+    Args:
+        response (http.client.HTTPResponse): The raw http client response.
+    """
+
+    def __init__(self, response):
+        self._status = response.status
+        self._headers = {key.lower(): value for key, value in response.getheaders()}
+        self._data = response.read()
+
+    @property
+    def status(self):
+        return self._status
+
+    @property
+    def headers(self):
+        return self._headers
+
+    @property
+    def data(self):
+        return self._data
+
+
+class Request(transport.Request):
+    """http.client transport request adapter."""
+
+    def __call__(
+        self, url, method="GET", body=None, headers=None, timeout=None, **kwargs
+    ):
+        """Make an HTTP request using http.client.
+
+        Args:
+            url (str): The URI to be requested.
+            method (str): The HTTP method to use for the request. Defaults
+                to 'GET'.
+            body (bytes): The payload / body in HTTP request.
+            headers (Mapping): Request headers.
+            timeout (Optional(int)): The number of seconds to wait for a
+                response from the server. If not specified or if None, the
+                socket global default timeout will be used.
+            kwargs: Additional arguments passed throught to the underlying
+                :meth:`~http.client.HTTPConnection.request` method.
+
+        Returns:
+            Response: The HTTP response.
+
+        Raises:
+            google.auth.exceptions.TransportError: If any exception occurred.
+        """
+        # socket._GLOBAL_DEFAULT_TIMEOUT is the default in http.client.
+        if timeout is None:
+            timeout = socket._GLOBAL_DEFAULT_TIMEOUT
+
+        # http.client doesn't allow None as the headers argument.
+        if headers is None:
+            headers = {}
+
+        # http.client needs the host and path parts specified separately.
+        parts = urllib.parse.urlsplit(url)
+        path = urllib.parse.urlunsplit(
+            ("", "", parts.path, parts.query, parts.fragment)
+        )
+
+        if parts.scheme != "http":
+            raise exceptions.TransportError(
+                "http.client transport only supports the http scheme, {}"
+                "was specified".format(parts.scheme)
+            )
+
+        connection = http_client.HTTPConnection(parts.netloc, timeout=timeout)
+
+        try:
+            _LOGGER.debug("Making request: %s %s", method, url)
+
+            connection.request(method, path, body=body, headers=headers, **kwargs)
+            response = connection.getresponse()
+            return Response(response)
+
+        except (http_client.HTTPException, socket.error) as caught_exc:
+            new_exc = exceptions.TransportError(caught_exc)
+            raise new_exc from caught_exc
+
+        finally:
+            connection.close()
diff --git a/.venv/lib/python3.12/site-packages/google/auth/transport/_mtls_helper.py b/.venv/lib/python3.12/site-packages/google/auth/transport/_mtls_helper.py
new file mode 100644
index 00000000..68568dd6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/google/auth/transport/_mtls_helper.py
@@ -0,0 +1,407 @@
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Helper functions for getting mTLS cert and key."""
+
+import json
+import logging
+from os import environ, path
+import re
+import subprocess
+
+from google.auth import exceptions
+
+CONTEXT_AWARE_METADATA_PATH = "~/.secureConnect/context_aware_metadata.json"
+CERTIFICATE_CONFIGURATION_DEFAULT_PATH = "~/.config/gcloud/certificate_config.json"
+_CERTIFICATE_CONFIGURATION_ENV = "GOOGLE_API_CERTIFICATE_CONFIG"
+_CERT_PROVIDER_COMMAND = "cert_provider_command"
+_CERT_REGEX = re.compile(
+    b"-----BEGIN CERTIFICATE-----.+-----END CERTIFICATE-----\r?\n?", re.DOTALL
+)
+
+# support various format of key files, e.g.
+# "-----BEGIN PRIVATE KEY-----...",
+# "-----BEGIN EC PRIVATE KEY-----...",
+# "-----BEGIN RSA PRIVATE KEY-----..."
+# "-----BEGIN ENCRYPTED PRIVATE KEY-----"
+_KEY_REGEX = re.compile(
+    b"-----BEGIN [A-Z ]*PRIVATE KEY-----.+-----END [A-Z ]*PRIVATE KEY-----\r?\n?",
+    re.DOTALL,
+)
+
+_LOGGER = logging.getLogger(__name__)
+
+
+_PASSPHRASE_REGEX = re.compile(
+    b"-----BEGIN PASSPHRASE-----(.+)-----END PASSPHRASE-----", re.DOTALL
+)
+
+
+def _check_config_path(config_path):
+    """Checks for config file path. If it exists, returns the absolute path with user expansion;
+    otherwise returns None.
+
+    Args:
+        config_path (str): The config file path for either context_aware_metadata.json or certificate_config.json for example
+
+    Returns:
+        str: absolute path if exists and None otherwise.
+    """
+    config_path = path.expanduser(config_path)
+    if not path.exists(config_path):
+        _LOGGER.debug("%s is not found.", config_path)
+        return None
+    return config_path
+
+
+def _load_json_file(path):
+    """Reads and loads JSON from the given path. Used to read both X509 workload certificate and
+    secure connect configurations.
+
+    Args:
+        path (str): the path to read from.
+
+    Returns:
+        Dict[str, str]: The JSON stored at the file.
+
+    Raises:
+        google.auth.exceptions.ClientCertError: If failed to parse the file as JSON.
+    """
+    try:
+        with open(path) as f:
+            json_data = json.load(f)
+    except ValueError as caught_exc:
+        new_exc = exceptions.ClientCertError(caught_exc)
+        raise new_exc from caught_exc
+
+    return json_data
+
+
+def _get_workload_cert_and_key(certificate_config_path=None):
+    """Read the workload identity cert and key files specified in the certificate config provided.
+    If no config path is provided, check the environment variable: "GOOGLE_API_CERTIFICATE_CONFIG"
+    first, then the well known gcloud location: "~/.config/gcloud/certificate_config.json".
+
+    Args:
+        certificate_config_path (string): The certificate config path. If no path is provided,
+        the environment variable will be checked first, then the well known gcloud location.
+
+    Returns:
+        Tuple[Optional[bytes], Optional[bytes]]: client certificate bytes in PEM format and key
+            bytes in PEM format.
+
+    Raises:
+        google.auth.exceptions.ClientCertError: if problems occurs when retrieving
+        the certificate or key information.
+    """
+
+    cert_path, key_path = _get_workload_cert_and_key_paths(certificate_config_path)
+
+    if cert_path is None and key_path is None:
+        return None, None
+
+    return _read_cert_and_key_files(cert_path, key_path)
+
+
+def _get_cert_config_path(certificate_config_path=None):
+    """Get the certificate configuration path based on the following order:
+
+    1: Explicit override, if set
+    2: Environment variable, if set
+    3: Well-known location
+
+    Returns "None" if the selected config file does not exist.
+
+    Args:
+        certificate_config_path (string): The certificate config path. If provided, the well known
+        location and environment variable will be ignored.
+
+    Returns:
+        The absolute path of the certificate config file, and None if the file does not exist.
+    """
+
+    if certificate_config_path is None:
+        env_path = environ.get(_CERTIFICATE_CONFIGURATION_ENV, None)
+        if env_path is not None and env_path != "":
+            certificate_config_path = env_path
+        else:
+            certificate_config_path = CERTIFICATE_CONFIGURATION_DEFAULT_PATH
+
+    certificate_config_path = path.expanduser(certificate_config_path)
+    if not path.exists(certificate_config_path):
+        return None
+    return certificate_config_path
+
+
+def _get_workload_cert_and_key_paths(config_path):
+    absolute_path = _get_cert_config_path(config_path)
+    if absolute_path is None:
+        return None, None
+
+    data = _load_json_file(absolute_path)
+
+    if "cert_configs" not in data:
+        raise exceptions.ClientCertError(
+            'Certificate config file {} is in an invalid format, a "cert configs" object is expected'.format(
+                absolute_path
+            )
+        )
+    cert_configs = data["cert_configs"]
+
+    if "workload" not in cert_configs:
+        raise exceptions.ClientCertError(
+            'Certificate config file {} is in an invalid format, a "workload" cert config is expected'.format(
+                absolute_path
+            )
+        )
+    workload = cert_configs["workload"]
+
+    if "cert_path" not in workload:
+        raise exceptions.ClientCertError(
+            'Certificate config file {} is in an invalid format, a "cert_path" is expected in the workload cert config'.format(
+                absolute_path
+            )
+        )
+    cert_path = workload["cert_path"]
+
+    if "key_path" not in workload:
+        raise exceptions.ClientCertError(
+            'Certificate config file {} is in an invalid format, a "key_path" is expected in the workload cert config'.format(
+                absolute_path
+            )
+        )
+    key_path = workload["key_path"]
+
+    return cert_path, key_path
+
+
+def _read_cert_and_key_files(cert_path, key_path):
+    cert_data = _read_cert_file(cert_path)
+    key_data = _read_key_file(key_path)
+
+    return cert_data, key_data
+
+
+def _read_cert_file(cert_path):
+    with open(cert_path, "rb") as cert_file:
+        cert_data = cert_file.read()
+
+    cert_match = re.findall(_CERT_REGEX, cert_data)
+    if len(cert_match) != 1:
+        raise exceptions.ClientCertError(
+            "Certificate file {} is in an invalid format, a single PEM formatted certificate is expected".format(
+                cert_path
+            )
+        )
+    return cert_match[0]
+
+
+def _read_key_file(key_path):
+    with open(key_path, "rb") as key_file:
+        key_data = key_file.read()
+
+    key_match = re.findall(_KEY_REGEX, key_data)
+    if len(key_match) != 1:
+        raise exceptions.ClientCertError(
+            "Private key file {} is in an invalid format, a single PEM formatted private key is expected".format(
+                key_path
+            )
+        )
+
+    return key_match[0]
+
+
+def _run_cert_provider_command(command, expect_encrypted_key=False):
+    """Run the provided command, and return client side mTLS cert, key and
+    passphrase.
+
+    Args:
+        command (List[str]): cert provider command.
+        expect_encrypted_key (bool): If encrypted private key is expected.
+
+    Returns:
+        Tuple[bytes, bytes, bytes]: client certificate bytes in PEM format, key
+            bytes in PEM format and passphrase bytes.
+
+    Raises:
+        google.auth.exceptions.ClientCertError: if problems occurs when running
+            the cert provider command or generating cert, key and passphrase.
+    """
+    try:
+        process = subprocess.Popen(
+            command, stdout=subprocess.PIPE, stderr=subprocess.PIPE
+        )
+        stdout, stderr = process.communicate()
+    except OSError as caught_exc:
+        new_exc = exceptions.ClientCertError(caught_exc)
+        raise new_exc from caught_exc
+
+    # Check cert provider command execution error.
+    if process.returncode != 0:
+        raise exceptions.ClientCertError(
+            "Cert provider command returns non-zero status code %s" % process.returncode
+        )
+
+    # Extract certificate (chain), key and passphrase.
+    cert_match = re.findall(_CERT_REGEX, stdout)
+    if len(cert_match) != 1:
+        raise exceptions.ClientCertError("Client SSL certificate is missing or invalid")
+    key_match = re.findall(_KEY_REGEX, stdout)
+    if len(key_match) != 1:
+        raise exceptions.ClientCertError("Client SSL key is missing or invalid")
+    passphrase_match = re.findall(_PASSPHRASE_REGEX, stdout)
+
+    if expect_encrypted_key:
+        if len(passphrase_match) != 1:
+            raise exceptions.ClientCertError("Passphrase is missing or invalid")
+        if b"ENCRYPTED" not in key_match[0]:
+            raise exceptions.ClientCertError("Encrypted private key is expected")
+        return cert_match[0], key_match[0], passphrase_match[0].strip()
+
+    if b"ENCRYPTED" in key_match[0]:
+        raise exceptions.ClientCertError("Encrypted private key is not expected")
+    if len(passphrase_match) > 0:
+        raise exceptions.ClientCertError("Passphrase is not expected")
+    return cert_match[0], key_match[0], None
+
+
+def get_client_ssl_credentials(
+    generate_encrypted_key=False,
+    context_aware_metadata_path=CONTEXT_AWARE_METADATA_PATH,
+    certificate_config_path=CERTIFICATE_CONFIGURATION_DEFAULT_PATH,
+):
+    """Returns the client side certificate, private key and passphrase.
+
+    We look for certificates and keys with the following order of priority:
+        1. Certificate and key specified by certificate_config.json.
+               Currently, only X.509 workload certificates are supported.
+        2. Certificate and key specified by context aware metadata (i.e. SecureConnect).
+
+    Args:
+        generate_encrypted_key (bool): If set to True, encrypted private key
+            and passphrase will be generated; otherwise, unencrypted private key
+            will be generated and passphrase will be None. This option only
+            affects keys obtained via context_aware_metadata.json.
+        context_aware_metadata_path (str): The context_aware_metadata.json file path.
+        certificate_config_path (str): The certificate_config.json file path.
+
+    Returns:
+        Tuple[bool, bytes, bytes, bytes]:
+            A boolean indicating if cert, key and passphrase are obtained, the
+            cert bytes and key bytes both in PEM format, and passphrase bytes.
+
+    Raises:
+        google.auth.exceptions.ClientCertError: if problems occurs when getting
+            the cert, key and passphrase.
+    """
+
+    # 1. Check for certificate config json.
+    cert_config_path = _check_config_path(certificate_config_path)
+    if cert_config_path:
+        # Attempt to retrieve X.509 Workload cert and key.
+        cert, key = _get_workload_cert_and_key(cert_config_path)
+        if cert and key:
+            return True, cert, key, None
+
+    # 2. Check for context aware metadata json
+    metadata_path = _check_config_path(context_aware_metadata_path)
+
+    if metadata_path:
+        metadata_json = _load_json_file(metadata_path)
+
+        if _CERT_PROVIDER_COMMAND not in metadata_json:
+            raise exceptions.ClientCertError("Cert provider command is not found")
+
+        command = metadata_json[_CERT_PROVIDER_COMMAND]
+
+        if generate_encrypted_key and "--with_passphrase" not in command:
+            command.append("--with_passphrase")
+
+        # Execute the command.
+        cert, key, passphrase = _run_cert_provider_command(
+            command, expect_encrypted_key=generate_encrypted_key
+        )
+        return True, cert, key, passphrase
+
+    return False, None, None, None
+
+
+def get_client_cert_and_key(client_cert_callback=None):
+    """Returns the client side certificate and private key. The function first
+    tries to get certificate and key from client_cert_callback; if the callback
+    is None or doesn't provide certificate and key, the function tries application
+    default SSL credentials.
+
+    Args:
+        client_cert_callback (Optional[Callable[[], (bytes, bytes)]]): An
+            optional callback which returns client certificate bytes and private
+            key bytes both in PEM format.
+
+    Returns:
+        Tuple[bool, bytes, bytes]:
+            A boolean indicating if cert and key are obtained, the cert bytes
+            and key bytes both in PEM format.
+
+    Raises:
+        google.auth.exceptions.ClientCertError: if problems occurs when getting
+            the cert and key.
+    """
+    if client_cert_callback:
+        cert, key = client_cert_callback()
+        return True, cert, key
+
+    has_cert, cert, key, _ = get_client_ssl_credentials(generate_encrypted_key=False)
+    return has_cert, cert, key
+
+
+def decrypt_private_key(key, passphrase):
+    """A helper function to decrypt the private key with the given passphrase.
+    google-auth library doesn't support passphrase protected private key for
+    mutual TLS channel. This helper function can be used to decrypt the
+    passphrase protected private key in order to estalish mutual TLS channel.
+
+    For example, if you have a function which produces client cert, passphrase
+    protected private key and passphrase, you can convert it to a client cert
+    callback function accepted by google-auth::
+
+        from google.auth.transport import _mtls_helper
+
+        def your_client_cert_function():
+            return cert, encrypted_key, passphrase
+
+        # callback accepted by google-auth for mutual TLS channel.
+        def client_cert_callback():
+            cert, encrypted_key, passphrase = your_client_cert_function()
+            decrypted_key = _mtls_helper.decrypt_private_key(encrypted_key,
+                passphrase)
+            return cert, decrypted_key
+
+    Args:
+        key (bytes): The private key bytes in PEM format.
+        passphrase (bytes): The passphrase bytes.
+
+    Returns:
+        bytes: The decrypted private key in PEM format.
+
+    Raises:
+        ImportError: If pyOpenSSL is not installed.
+        OpenSSL.crypto.Error: If there is any problem decrypting the private key.
+    """
+    from OpenSSL import crypto
+
+    # First convert encrypted_key_bytes to PKey object
+    pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key, passphrase=passphrase)
+
+    # Then dump the decrypted key bytes
+    return crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)
diff --git a/.venv/lib/python3.12/site-packages/google/auth/transport/_requests_base.py b/.venv/lib/python3.12/site-packages/google/auth/transport/_requests_base.py
new file mode 100644
index 00000000..0608223d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/google/auth/transport/_requests_base.py
@@ -0,0 +1,53 @@
+# Copyright 2024 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Transport adapter for Base Requests."""
+# NOTE: The coverage for this file is temporarily disabled in `.coveragerc`
+# since it is currently unused.
+
+import abc
+
+
+_DEFAULT_TIMEOUT = 120  # in second
+
+
+class _BaseAuthorizedSession(metaclass=abc.ABCMeta):
+    """Base class for a Request Session with credentials. This class is intended to capture
+    the common logic between synchronous and asynchronous request sessions and is not intended to
+    be instantiated directly.
+
+    Args:
+        credentials (google.auth._credentials_base.BaseCredentials): The credentials to
+            add to the request.
+    """
+
+    def __init__(self, credentials):
+        self.credentials = credentials
+
+    @abc.abstractmethod
+    def request(
+        self,
+        method,
+        url,
+        data=None,
+        headers=None,
+        max_allowed_time=None,
+        timeout=_DEFAULT_TIMEOUT,
+        **kwargs
+    ):
+        raise NotImplementedError("Request must be implemented")
+
+    @abc.abstractmethod
+    def close(self):
+        raise NotImplementedError("Close must be implemented")
diff --git a/.venv/lib/python3.12/site-packages/google/auth/transport/grpc.py b/.venv/lib/python3.12/site-packages/google/auth/transport/grpc.py
new file mode 100644
index 00000000..1ebe1379
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/google/auth/transport/grpc.py
@@ -0,0 +1,343 @@
+# Copyright 2016 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Authorization support for gRPC."""
+
+from __future__ import absolute_import
+
+import logging
+import os
+
+from google.auth import environment_vars
+from google.auth import exceptions
+from google.auth.transport import _mtls_helper
+from google.oauth2 import service_account
+
+try:
+    import grpc  # type: ignore
+except ImportError as caught_exc:  # pragma: NO COVER
+    raise ImportError(
+        "gRPC is not installed from please install the grpcio package to use the gRPC transport."
+    ) from caught_exc
+
+_LOGGER = logging.getLogger(__name__)
+
+
+class AuthMetadataPlugin(grpc.AuthMetadataPlugin):
+    """A `gRPC AuthMetadataPlugin`_ that inserts the credentials into each
+    request.
+
+    .. _gRPC AuthMetadataPlugin:
+        http://www.grpc.io/grpc/python/grpc.html#grpc.AuthMetadataPlugin
+
+    Args:
+        credentials (google.auth.credentials.Credentials): The credentials to
+            add to requests.
+        request (google.auth.transport.Request): A HTTP transport request
+            object used to refresh credentials as needed.
+        default_host (Optional[str]): A host like "pubsub.googleapis.com".
+            This is used when a self-signed JWT is created from service
+            account credentials.
+    """
+
+    def __init__(self, credentials, request, default_host=None):
+        # pylint: disable=no-value-for-parameter
+        # pylint doesn't realize that the super method takes no arguments
+        # because this class is the same name as the superclass.
+        super(AuthMetadataPlugin, self).__init__()
+        self._credentials = credentials
+        self._request = request
+        self._default_host = default_host
+
+    def _get_authorization_headers(self, context):
+        """Gets the authorization headers for a request.
+
+        Returns:
+            Sequence[Tuple[str, str]]: A list of request headers (key, value)
+                to add to the request.
+        """
+        headers = {}
+
+        # https://google.aip.dev/auth/4111
+        # Attempt to use self-signed JWTs when a service account is used.
+        # A default host must be explicitly provided since it cannot always
+        # be determined from the context.service_url.
+        if isinstance(self._credentials, service_account.Credentials):
+            self._credentials._create_self_signed_jwt(
+                "https://{}/".format(self._default_host) if self._default_host else None
+            )
+
+        self._credentials.before_request(
+            self._request, context.method_name, context.service_url, headers
+        )
+
+        return list(headers.items())
+
+    def __call__(self, context, callback):
+        """Passes authorization metadata into the given callback.
+
+        Args:
+            context (grpc.AuthMetadataContext): The RPC context.
+            callback (grpc.AuthMetadataPluginCallback): The callback that will
+                be invoked to pass in the authorization metadata.
+        """
+        callback(self._get_authorization_headers(context), None)
+
+
+def secure_authorized_channel(
+    credentials,
+    request,
+    target,
+    ssl_credentials=None,
+    client_cert_callback=None,
+    **kwargs
+):
+    """Creates a secure authorized gRPC channel.
+
+    This creates a channel with SSL and :class:`AuthMetadataPlugin`. This
+    channel can be used to create a stub that can make authorized requests.
+    Users can configure client certificate or rely on device certificates to
+    establish a mutual TLS channel, if the `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+    variable is explicitly set to `true`.
+
+    Example::
+
+        import google.auth
+        import google.auth.transport.grpc
+        import google.auth.transport.requests
+        from google.cloud.speech.v1 import cloud_speech_pb2
+
+        # Get credentials.
+        credentials, _ = google.auth.default()
+
+        # Get an HTTP request function to refresh credentials.
+        request = google.auth.transport.requests.Request()
+
+        # Create a channel.
+        channel = google.auth.transport.grpc.secure_authorized_channel(
+            credentials, regular_endpoint, request,
+            ssl_credentials=grpc.ssl_channel_credentials())
+
+        # Use the channel to create a stub.
+        cloud_speech.create_Speech_stub(channel)
+
+    Usage:
+
+    There are actually a couple of options to create a channel, depending on if
+    you want to create a regular or mutual TLS channel.
+
+    First let's list the endpoints (regular vs mutual TLS) to choose from::
+
+        regular_endpoint = 'speech.googleapis.com:443'
+        mtls_endpoint = 'speech.mtls.googleapis.com:443'
+
+    Option 1: create a regular (non-mutual) TLS channel by explicitly setting
+    the ssl_credentials::
+
+        regular_ssl_credentials = grpc.ssl_channel_credentials()
+
+        channel = google.auth.transport.grpc.secure_authorized_channel(
+            credentials, regular_endpoint, request,
+            ssl_credentials=regular_ssl_credentials)
+
+    Option 2: create a mutual TLS channel by calling a callback which returns
+    the client side certificate and the key (Note that
+    `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable must be explicitly
+    set to `true`)::
+
+        def my_client_cert_callback():
+            code_to_load_client_cert_and_key()
+            if loaded:
+                return (pem_cert_bytes, pem_key_bytes)
+            raise MyClientCertFailureException()
+
+        try:
+            channel = google.auth.transport.grpc.secure_authorized_channel(
+                credentials, mtls_endpoint, request,
+                client_cert_callback=my_client_cert_callback)
+        except MyClientCertFailureException:
+            # handle the exception
+
+    Option 3: use application default SSL credentials. It searches and uses
+    the command in a context aware metadata file, which is available on devices
+    with endpoint verification support (Note that
+    `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable must be explicitly
+    set to `true`).
+    See https://cloud.google.com/endpoint-verification/docs/overview::
+
+        try:
+            default_ssl_credentials = SslCredentials()
+        except:
+            # Exception can be raised if the context aware metadata is malformed.
+            # See :class:`SslCredentials` for the possible exceptions.
+
+        # Choose the endpoint based on the SSL credentials type.
+        if default_ssl_credentials.is_mtls:
+            endpoint_to_use = mtls_endpoint
+        else:
+            endpoint_to_use = regular_endpoint
+        channel = google.auth.transport.grpc.secure_authorized_channel(
+            credentials, endpoint_to_use, request,
+            ssl_credentials=default_ssl_credentials)
+
+    Option 4: not setting ssl_credentials and client_cert_callback. For devices
+    without endpoint verification support or `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+    environment variable is not `true`, a regular TLS channel is created;
+    otherwise, a mutual TLS channel is created, however, the call should be
+    wrapped in a try/except block in case of malformed context aware metadata.
+
+    The following code uses regular_endpoint, it works the same no matter the
+    created channle is regular or mutual TLS. Regular endpoint ignores client
+    certificate and key::
+
+        channel = google.auth.transport.grpc.secure_authorized_channel(
+            credentials, regular_endpoint, request)
+
+    The following code uses mtls_endpoint, if the created channle is regular,
+    and API mtls_endpoint is confgured to require client SSL credentials, API
+    calls using this channel will be rejected::
+
+        channel = google.auth.transport.grpc.secure_authorized_channel(
+            credentials, mtls_endpoint, request)
+
+    Args:
+        credentials (google.auth.credentials.Credentials): The credentials to
+            add to requests.
+        request (google.auth.transport.Request): A HTTP transport request
+            object used to refresh credentials as needed. Even though gRPC
+            is a separate transport, there's no way to refresh the credentials
+            without using a standard http transport.
+        target (str): The host and port of the service.
+        ssl_credentials (grpc.ChannelCredentials): Optional SSL channel
+            credentials. This can be used to specify different certificates.
+            This argument is mutually exclusive with client_cert_callback;
+            providing both will raise an exception.
+            If ssl_credentials and client_cert_callback are None, application
+            default SSL credentials are used if `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+            environment variable is explicitly set to `true`, otherwise one way TLS
+            SSL credentials are used.
+        client_cert_callback (Callable[[], (bytes, bytes)]): Optional
+            callback function to obtain client certicate and key for mutual TLS
+            connection. This argument is mutually exclusive with
+            ssl_credentials; providing both will raise an exception.
+            This argument does nothing unless `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+            environment variable is explicitly set to `true`.
+        kwargs: Additional arguments to pass to :func:`grpc.secure_channel`.
+
+    Returns:
+        grpc.Channel: The created gRPC channel.
+
+    Raises:
+        google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
+            creation failed for any reason.
+    """
+    # Create the metadata plugin for inserting the authorization header.
+    metadata_plugin = AuthMetadataPlugin(credentials, request)
+
+    # Create a set of grpc.CallCredentials using the metadata plugin.
+    google_auth_credentials = grpc.metadata_call_credentials(metadata_plugin)
+
+    if ssl_credentials and client_cert_callback:
+        raise exceptions.MalformedError(
+            "Received both ssl_credentials and client_cert_callback; "
+            "these are mutually exclusive."
+        )
+
+    # If SSL credentials are not explicitly set, try client_cert_callback and ADC.
+    if not ssl_credentials:
+        use_client_cert = os.getenv(
+            environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false"
+        )
+        if use_client_cert == "true" and client_cert_callback:
+            # Use the callback if provided.
+            cert, key = client_cert_callback()
+            ssl_credentials = grpc.ssl_channel_credentials(
+                certificate_chain=cert, private_key=key
+            )
+        elif use_client_cert == "true":
+            # Use application default SSL credentials.
+            adc_ssl_credentils = SslCredentials()
+            ssl_credentials = adc_ssl_credentils.ssl_credentials
+        else:
+            ssl_credentials = grpc.ssl_channel_credentials()
+
+    # Combine the ssl credentials and the authorization credentials.
+    composite_credentials = grpc.composite_channel_credentials(
+        ssl_credentials, google_auth_credentials
+    )
+
+    return grpc.secure_channel(target, composite_credentials, **kwargs)
+
+
+class SslCredentials:
+    """Class for application default SSL credentials.
+
+    The behavior is controlled by `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment
+    variable whose default value is `false`. Client certificate will not be used
+    unless the environment variable is explicitly set to `true`. See
+    https://google.aip.dev/auth/4114
+
+    If the environment variable is `true`, then for devices with endpoint verification
+    support, a device certificate will be automatically loaded and mutual TLS will
+    be established.
+    See https://cloud.google.com/endpoint-verification/docs/overview.
+    """
+
+    def __init__(self):
+        use_client_cert = os.getenv(
+            environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false"
+        )
+        if use_client_cert != "true":
+            self._is_mtls = False
+        else:
+            # Load client SSL credentials.
+            metadata_path = _mtls_helper._check_config_path(
+                _mtls_helper.CONTEXT_AWARE_METADATA_PATH
+            )
+            self._is_mtls = metadata_path is not None
+
+    @property
+    def ssl_credentials(self):
+        """Get the created SSL channel credentials.
+
+        For devices with endpoint verification support, if the device certificate
+        loading has any problems, corresponding exceptions will be raised. For
+        a device without endpoint verification support, no exceptions will be
+        raised.
+
+        Returns:
+            grpc.ChannelCredentials: The created grpc channel credentials.
+
+        Raises:
+            google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
+                creation failed for any reason.
+        """
+        if self._is_mtls:
+            try:
+                _, cert, key, _ = _mtls_helper.get_client_ssl_credentials()
+                self._ssl_credentials = grpc.ssl_channel_credentials(
+                    certificate_chain=cert, private_key=key
+                )
+            except exceptions.ClientCertError as caught_exc:
+                new_exc = exceptions.MutualTLSChannelError(caught_exc)
+                raise new_exc from caught_exc
+        else:
+            self._ssl_credentials = grpc.ssl_channel_credentials()
+
+        return self._ssl_credentials
+
+    @property
+    def is_mtls(self):
+        """Indicates if the created SSL channel credentials is mutual TLS."""
+        return self._is_mtls
diff --git a/.venv/lib/python3.12/site-packages/google/auth/transport/mtls.py b/.venv/lib/python3.12/site-packages/google/auth/transport/mtls.py
new file mode 100644
index 00000000..e7a7304f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/google/auth/transport/mtls.py
@@ -0,0 +1,112 @@
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Utilites for mutual TLS."""
+
+from google.auth import exceptions
+from google.auth.transport import _mtls_helper
+
+
+def has_default_client_cert_source():
+    """Check if default client SSL credentials exists on the device.
+
+    Returns:
+        bool: indicating if the default client cert source exists.
+    """
+    if (
+        _mtls_helper._check_config_path(_mtls_helper.CONTEXT_AWARE_METADATA_PATH)
+        is not None
+    ):
+        return True
+    if (
+        _mtls_helper._check_config_path(
+            _mtls_helper.CERTIFICATE_CONFIGURATION_DEFAULT_PATH
+        )
+        is not None
+    ):
+        return True
+    return False
+
+
+def default_client_cert_source():
+    """Get a callback which returns the default client SSL credentials.
+
+    Returns:
+        Callable[[], [bytes, bytes]]: A callback which returns the default
+            client certificate bytes and private key bytes, both in PEM format.
+
+    Raises:
+        google.auth.exceptions.DefaultClientCertSourceError: If the default
+            client SSL credentials don't exist or are malformed.
+    """
+    if not has_default_client_cert_source():
+        raise exceptions.MutualTLSChannelError(
+            "Default client cert source doesn't exist"
+        )
+
+    def callback():
+        try:
+            _, cert_bytes, key_bytes = _mtls_helper.get_client_cert_and_key()
+        except (OSError, RuntimeError, ValueError) as caught_exc:
+            new_exc = exceptions.MutualTLSChannelError(caught_exc)
+            raise new_exc from caught_exc
+
+        return cert_bytes, key_bytes
+
+    return callback
+
+
+def default_client_encrypted_cert_source(cert_path, key_path):
+    """Get a callback which returns the default encrpyted client SSL credentials.
+
+    Args:
+        cert_path (str): The cert file path. The default client certificate will
+            be written to this file when the returned callback is called.
+        key_path (str): The key file path. The default encrypted client key will
+            be written to this file when the returned callback is called.
+
+    Returns:
+        Callable[[], [str, str, bytes]]: A callback which generates the default
+            client certificate, encrpyted private key and passphrase. It writes
+            the certificate and private key into the cert_path and key_path, and
+            returns the cert_path, key_path and passphrase bytes.
+
+    Raises:
+        google.auth.exceptions.DefaultClientCertSourceError: If any problem
+            occurs when loading or saving the client certificate and key.
+    """
+    if not has_default_client_cert_source():
+        raise exceptions.MutualTLSChannelError(
+            "Default client encrypted cert source doesn't exist"
+        )
+
+    def callback():
+        try:
+            (
+                _,
+                cert_bytes,
+                key_bytes,
+                passphrase_bytes,
+            ) = _mtls_helper.get_client_ssl_credentials(generate_encrypted_key=True)
+            with open(cert_path, "wb") as cert_file:
+                cert_file.write(cert_bytes)
+            with open(key_path, "wb") as key_file:
+                key_file.write(key_bytes)
+        except (exceptions.ClientCertError, OSError) as caught_exc:
+            new_exc = exceptions.MutualTLSChannelError(caught_exc)
+            raise new_exc from caught_exc
+
+        return cert_path, key_path, passphrase_bytes
+
+    return callback
diff --git a/.venv/lib/python3.12/site-packages/google/auth/transport/requests.py b/.venv/lib/python3.12/site-packages/google/auth/transport/requests.py
new file mode 100644
index 00000000..23a69783
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/google/auth/transport/requests.py
@@ -0,0 +1,599 @@
+# Copyright 2016 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Transport adapter for Requests."""
+
+from __future__ import absolute_import
+
+import functools
+import logging
+import numbers
+import os
+import time
+
+try:
+    import requests
+except ImportError as caught_exc:  # pragma: NO COVER
+    raise ImportError(
+        "The requests library is not installed from please install the requests package to use the requests transport."
+    ) from caught_exc
+import requests.adapters  # pylint: disable=ungrouped-imports
+import requests.exceptions  # pylint: disable=ungrouped-imports
+from requests.packages.urllib3.util.ssl_ import (  # type: ignore
+    create_urllib3_context,
+)  # pylint: disable=ungrouped-imports
+
+from google.auth import environment_vars
+from google.auth import exceptions
+from google.auth import transport
+import google.auth.transport._mtls_helper
+from google.oauth2 import service_account
+
+_LOGGER = logging.getLogger(__name__)
+
+_DEFAULT_TIMEOUT = 120  # in seconds
+
+
+class _Response(transport.Response):
+    """Requests transport response adapter.
+
+    Args:
+        response (requests.Response): The raw Requests response.
+    """
+
+    def __init__(self, response):
+        self._response = response
+
+    @property
+    def status(self):
+        return self._response.status_code
+
+    @property
+    def headers(self):
+        return self._response.headers
+
+    @property
+    def data(self):
+        return self._response.content
+
+
+class TimeoutGuard(object):
+    """A context manager raising an error if the suite execution took too long.
+
+    Args:
+        timeout (Union[None, Union[float, Tuple[float, float]]]):
+            The maximum number of seconds a suite can run without the context
+            manager raising a timeout exception on exit. If passed as a tuple,
+            the smaller of the values is taken as a timeout. If ``None``, a
+            timeout error is never raised.
+        timeout_error_type (Optional[Exception]):
+            The type of the error to raise on timeout. Defaults to
+            :class:`requests.exceptions.Timeout`.
+    """
+
+    def __init__(self, timeout, timeout_error_type=requests.exceptions.Timeout):
+        self._timeout = timeout
+        self.remaining_timeout = timeout
+        self._timeout_error_type = timeout_error_type
+
+    def __enter__(self):
+        self._start = time.time()
+        return self
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        if exc_value:
+            return  # let the error bubble up automatically
+
+        if self._timeout is None:
+            return  # nothing to do, the timeout was not specified
+
+        elapsed = time.time() - self._start
+        deadline_hit = False
+
+        if isinstance(self._timeout, numbers.Number):
+            self.remaining_timeout = self._timeout - elapsed
+            deadline_hit = self.remaining_timeout <= 0
+        else:
+            self.remaining_timeout = tuple(x - elapsed for x in self._timeout)
+            deadline_hit = min(self.remaining_timeout) <= 0
+
+        if deadline_hit:
+            raise self._timeout_error_type()
+
+
+class Request(transport.Request):
+    """Requests request adapter.
+
+    This class is used internally for making requests using various transports
+    in a consistent way. If you use :class:`AuthorizedSession` you do not need
+    to construct or use this class directly.
+
+    This class can be useful if you want to manually refresh a
+    :class:`~google.auth.credentials.Credentials` instance::
+
+        import google.auth.transport.requests
+        import requests
+
+        request = google.auth.transport.requests.Request()
+
+        credentials.refresh(request)
+
+    Args:
+        session (requests.Session): An instance :class:`requests.Session` used
+            to make HTTP requests. If not specified, a session will be created.
+
+    .. automethod:: __call__
+    """
+
+    def __init__(self, session=None):
+        if not session:
+            session = requests.Session()
+
+        self.session = session
+
+    def __del__(self):
+        try:
+            if hasattr(self, "session") and self.session is not None:
+                self.session.close()
+        except TypeError:
+            # NOTE: For certain Python binary built, the queue.Empty exception
+            # might not be considered a normal Python exception causing
+            # TypeError.
+            pass
+
+    def __call__(
+        self,
+        url,
+        method="GET",
+        body=None,
+        headers=None,
+        timeout=_DEFAULT_TIMEOUT,
+        **kwargs
+    ):
+        """Make an HTTP request using requests.
+
+        Args:
+            url (str): The URI to be requested.
+            method (str): The HTTP method to use for the request. Defaults
+                to 'GET'.
+            body (bytes): The payload or body in HTTP request.
+            headers (Mapping[str, str]): Request headers.
+            timeout (Optional[int]): The number of seconds to wait for a
+                response from the server. If not specified or if None, the
+                requests default timeout will be used.
+            kwargs: Additional arguments passed through to the underlying
+                requests :meth:`~requests.Session.request` method.
+
+        Returns:
+            google.auth.transport.Response: The HTTP response.
+
+        Raises:
+            google.auth.exceptions.TransportError: If any exception occurred.
+        """
+        try:
+            _LOGGER.debug("Making request: %s %s", method, url)
+            response = self.session.request(
+                method, url, data=body, headers=headers, timeout=timeout, **kwargs
+            )
+            return _Response(response)
+        except requests.exceptions.RequestException as caught_exc:
+            new_exc = exceptions.TransportError(caught_exc)
+            raise new_exc from caught_exc
+
+
+class _MutualTlsAdapter(requests.adapters.HTTPAdapter):
+    """
+    A TransportAdapter that enables mutual TLS.
+
+    Args:
+        cert (bytes): client certificate in PEM format
+        key (bytes): client private key in PEM format
+
+    Raises:
+        ImportError: if certifi or pyOpenSSL is not installed
+        OpenSSL.crypto.Error: if client cert or key is invalid
+    """
+
+    def __init__(self, cert, key):
+        import certifi
+        from OpenSSL import crypto
+        import urllib3.contrib.pyopenssl  # type: ignore
+
+        urllib3.contrib.pyopenssl.inject_into_urllib3()
+
+        pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key)
+        x509 = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
+
+        ctx_poolmanager = create_urllib3_context()
+        ctx_poolmanager.load_verify_locations(cafile=certifi.where())
+        ctx_poolmanager._ctx.use_certificate(x509)
+        ctx_poolmanager._ctx.use_privatekey(pkey)
+        self._ctx_poolmanager = ctx_poolmanager
+
+        ctx_proxymanager = create_urllib3_context()
+        ctx_proxymanager.load_verify_locations(cafile=certifi.where())
+        ctx_proxymanager._ctx.use_certificate(x509)
+        ctx_proxymanager._ctx.use_privatekey(pkey)
+        self._ctx_proxymanager = ctx_proxymanager
+
+        super(_MutualTlsAdapter, self).__init__()
+
+    def init_poolmanager(self, *args, **kwargs):
+        kwargs["ssl_context"] = self._ctx_poolmanager
+        super(_MutualTlsAdapter, self).init_poolmanager(*args, **kwargs)
+
+    def proxy_manager_for(self, *args, **kwargs):
+        kwargs["ssl_context"] = self._ctx_proxymanager
+        return super(_MutualTlsAdapter, self).proxy_manager_for(*args, **kwargs)
+
+
+class _MutualTlsOffloadAdapter(requests.adapters.HTTPAdapter):
+    """
+    A TransportAdapter that enables mutual TLS and offloads the client side
+    signing operation to the signing library.
+
+    Args:
+        enterprise_cert_file_path (str): the path to a enterprise cert JSON
+            file. The file should contain the following field:
+
+                {
+                    "libs": {
+                        "signer_library": "...",
+                        "offload_library": "..."
+                    }
+                }
+
+    Raises:
+        ImportError: if certifi or pyOpenSSL is not installed
+        google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
+            creation failed for any reason.
+    """
+
+    def __init__(self, enterprise_cert_file_path):
+        import certifi
+        from google.auth.transport import _custom_tls_signer
+
+        self.signer = _custom_tls_signer.CustomTlsSigner(enterprise_cert_file_path)
+        self.signer.load_libraries()
+
+        import urllib3.contrib.pyopenssl
+
+        urllib3.contrib.pyopenssl.inject_into_urllib3()
+
+        poolmanager = create_urllib3_context()
+        poolmanager.load_verify_locations(cafile=certifi.where())
+        self.signer.attach_to_ssl_context(poolmanager)
+        self._ctx_poolmanager = poolmanager
+
+        proxymanager = create_urllib3_context()
+        proxymanager.load_verify_locations(cafile=certifi.where())
+        self.signer.attach_to_ssl_context(proxymanager)
+        self._ctx_proxymanager = proxymanager
+
+        super(_MutualTlsOffloadAdapter, self).__init__()
+
+    def init_poolmanager(self, *args, **kwargs):
+        kwargs["ssl_context"] = self._ctx_poolmanager
+        super(_MutualTlsOffloadAdapter, self).init_poolmanager(*args, **kwargs)
+
+    def proxy_manager_for(self, *args, **kwargs):
+        kwargs["ssl_context"] = self._ctx_proxymanager
+        return super(_MutualTlsOffloadAdapter, self).proxy_manager_for(*args, **kwargs)
+
+
+class AuthorizedSession(requests.Session):
+    """A Requests Session class with credentials.
+
+    This class is used to perform requests to API endpoints that require
+    authorization::
+
+        from google.auth.transport.requests import AuthorizedSession
+
+        authed_session = AuthorizedSession(credentials)
+
+        response = authed_session.request(
+            'GET', 'https://www.googleapis.com/storage/v1/b')
+
+
+    The underlying :meth:`request` implementation handles adding the
+    credentials' headers to the request and refreshing credentials as needed.
+
+    This class also supports mutual TLS via :meth:`configure_mtls_channel`
+    method. In order to use this method, the `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+    environment variable must be explicitly set to ``true``, otherwise it does
+    nothing. Assume the environment is set to ``true``, the method behaves in the
+    following manner:
+
+    If client_cert_callback is provided, client certificate and private
+    key are loaded using the callback; if client_cert_callback is None,
+    application default SSL credentials will be used. Exceptions are raised if
+    there are problems with the certificate, private key, or the loading process,
+    so it should be called within a try/except block.
+
+    First we set the environment variable to ``true``, then create an :class:`AuthorizedSession`
+    instance and specify the endpoints::
+
+        regular_endpoint = 'https://pubsub.googleapis.com/v1/projects/{my_project_id}/topics'
+        mtls_endpoint = 'https://pubsub.mtls.googleapis.com/v1/projects/{my_project_id}/topics'
+
+        authed_session = AuthorizedSession(credentials)
+
+    Now we can pass a callback to :meth:`configure_mtls_channel`::
+
+        def my_cert_callback():
+            # some code to load client cert bytes and private key bytes, both in
+            # PEM format.
+            some_code_to_load_client_cert_and_key()
+            if loaded:
+                return cert, key
+            raise MyClientCertFailureException()
+
+        # Always call configure_mtls_channel within a try/except block.
+        try:
+            authed_session.configure_mtls_channel(my_cert_callback)
+        except:
+            # handle exceptions.
+
+        if authed_session.is_mtls:
+            response = authed_session.request('GET', mtls_endpoint)
+        else:
+            response = authed_session.request('GET', regular_endpoint)
+
+
+    You can alternatively use application default SSL credentials like this::
+
+        try:
+            authed_session.configure_mtls_channel()
+        except:
+            # handle exceptions.
+
+    Args:
+        credentials (google.auth.credentials.Credentials): The credentials to
+            add to the request.
+        refresh_status_codes (Sequence[int]): Which HTTP status codes indicate
+            that credentials should be refreshed and the request should be
+            retried.
+        max_refresh_attempts (int): The maximum number of times to attempt to
+            refresh the credentials and retry the request.
+        refresh_timeout (Optional[int]): The timeout value in seconds for
+            credential refresh HTTP requests.
+        auth_request (google.auth.transport.requests.Request):
+            (Optional) An instance of
+            :class:`~google.auth.transport.requests.Request` used when
+            refreshing credentials. If not passed,
+            an instance of :class:`~google.auth.transport.requests.Request`
+            is created.
+        default_host (Optional[str]): A host like "pubsub.googleapis.com".
+            This is used when a self-signed JWT is created from service
+            account credentials.
+    """
+
+    def __init__(
+        self,
+        credentials,
+        refresh_status_codes=transport.DEFAULT_REFRESH_STATUS_CODES,
+        max_refresh_attempts=transport.DEFAULT_MAX_REFRESH_ATTEMPTS,
+        refresh_timeout=None,
+        auth_request=None,
+        default_host=None,
+    ):
+        super(AuthorizedSession, self).__init__()
+        self.credentials = credentials
+        self._refresh_status_codes = refresh_status_codes
+        self._max_refresh_attempts = max_refresh_attempts
+        self._refresh_timeout = refresh_timeout
+        self._is_mtls = False
+        self._default_host = default_host
+
+        if auth_request is None:
+            self._auth_request_session = requests.Session()
+
+            # Using an adapter to make HTTP requests robust to network errors.
+            # This adapter retrys HTTP requests when network errors occur
+            # and the requests seems safely retryable.
+            retry_adapter = requests.adapters.HTTPAdapter(max_retries=3)
+            self._auth_request_session.mount("https://", retry_adapter)
+
+            # Do not pass `self` as the session here, as it can lead to
+            # infinite recursion.
+            auth_request = Request(self._auth_request_session)
+        else:
+            self._auth_request_session = None
+
+        # Request instance used by internal methods (for example,
+        # credentials.refresh).
+        self._auth_request = auth_request
+
+        # https://google.aip.dev/auth/4111
+        # Attempt to use self-signed JWTs when a service account is used.
+        if isinstance(self.credentials, service_account.Credentials):
+            self.credentials._create_self_signed_jwt(
+                "https://{}/".format(self._default_host) if self._default_host else None
+            )
+
+    def configure_mtls_channel(self, client_cert_callback=None):
+        """Configure the client certificate and key for SSL connection.
+
+        The function does nothing unless `GOOGLE_API_USE_CLIENT_CERTIFICATE` is
+        explicitly set to `true`. In this case if client certificate and key are
+        successfully obtained (from the given client_cert_callback or from application
+        default SSL credentials), a :class:`_MutualTlsAdapter` instance will be mounted
+        to "https://" prefix.
+
+        Args:
+            client_cert_callback (Optional[Callable[[], (bytes, bytes)]]):
+                The optional callback returns the client certificate and private
+                key bytes both in PEM format.
+                If the callback is None, application default SSL credentials
+                will be used.
+
+        Raises:
+            google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
+                creation failed for any reason.
+        """
+        use_client_cert = os.getenv(
+            environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false"
+        )
+        if use_client_cert != "true":
+            self._is_mtls = False
+            return
+
+        try:
+            import OpenSSL
+        except ImportError as caught_exc:
+            new_exc = exceptions.MutualTLSChannelError(caught_exc)
+            raise new_exc from caught_exc
+
+        try:
+            (
+                self._is_mtls,
+                cert,
+                key,
+            ) = google.auth.transport._mtls_helper.get_client_cert_and_key(
+                client_cert_callback
+            )
+
+            if self._is_mtls:
+                mtls_adapter = _MutualTlsAdapter(cert, key)
+                self.mount("https://", mtls_adapter)
+        except (
+            exceptions.ClientCertError,
+            ImportError,
+            OpenSSL.crypto.Error,
+        ) as caught_exc:
+            new_exc = exceptions.MutualTLSChannelError(caught_exc)
+            raise new_exc from caught_exc
+
+    def request(
+        self,
+        method,
+        url,
+        data=None,
+        headers=None,
+        max_allowed_time=None,
+        timeout=_DEFAULT_TIMEOUT,
+        **kwargs
+    ):
+        """Implementation of Requests' request.
+
+        Args:
+            timeout (Optional[Union[float, Tuple[float, float]]]):
+                The amount of time in seconds to wait for the server response
+                with each individual request. Can also be passed as a tuple
+                ``(connect_timeout, read_timeout)``. See :meth:`requests.Session.request`
+                documentation for details.
+            max_allowed_time (Optional[float]):
+                If the method runs longer than this, a ``Timeout`` exception is
+                automatically raised. Unlike the ``timeout`` parameter, this
+                value applies to the total method execution time, even if
+                multiple requests are made under the hood.
+
+                Mind that it is not guaranteed that the timeout error is raised
+                at ``max_allowed_time``. It might take longer, for example, if
+                an underlying request takes a lot of time, but the request
+                itself does not timeout, e.g. if a large file is being
+                transmitted. The timout error will be raised after such
+                request completes.
+        """
+        # pylint: disable=arguments-differ
+        # Requests has a ton of arguments to request, but only two
+        # (method, url) are required. We pass through all of the other
+        # arguments to super, so no need to exhaustively list them here.
+
+        # Use a kwarg for this instead of an attribute to maintain
+        # thread-safety.
+        _credential_refresh_attempt = kwargs.pop("_credential_refresh_attempt", 0)
+
+        # Make a copy of the headers. They will be modified by the credentials
+        # and we want to pass the original headers if we recurse.
+        request_headers = headers.copy() if headers is not None else {}
+
+        # Do not apply the timeout unconditionally in order to not override the
+        # _auth_request's default timeout.
+        auth_request = (
+            self._auth_request
+            if timeout is None
+            else functools.partial(self._auth_request, timeout=timeout)
+        )
+
+        remaining_time = max_allowed_time
+
+        with TimeoutGuard(remaining_time) as guard:
+            self.credentials.before_request(auth_request, method, url, request_headers)
+        remaining_time = guard.remaining_timeout
+
+        with TimeoutGuard(remaining_time) as guard:
+            response = super(AuthorizedSession, self).request(
+                method,
+                url,
+                data=data,
+                headers=request_headers,
+                timeout=timeout,
+                **kwargs
+            )
+        remaining_time = guard.remaining_timeout
+
+        # If the response indicated that the credentials needed to be
+        # refreshed, then refresh the credentials and re-attempt the
+        # request.
+        # A stored token may expire between the time it is retrieved and
+        # the time the request is made, so we may need to try twice.
+        if (
+            response.status_code in self._refresh_status_codes
+            and _credential_refresh_attempt < self._max_refresh_attempts
+        ):
+
+            _LOGGER.info(
+                "Refreshing credentials due to a %s response. Attempt %s/%s.",
+                response.status_code,
+                _credential_refresh_attempt + 1,
+                self._max_refresh_attempts,
+            )
+
+            # Do not apply the timeout unconditionally in order to not override the
+            # _auth_request's default timeout.
+            auth_request = (
+                self._auth_request
+                if timeout is None
+                else functools.partial(self._auth_request, timeout=timeout)
+            )
+
+            with TimeoutGuard(remaining_time) as guard:
+                self.credentials.refresh(auth_request)
+            remaining_time = guard.remaining_timeout
+
+            # Recurse. Pass in the original headers, not our modified set, but
+            # do pass the adjusted max allowed time (i.e. the remaining total time).
+            return self.request(
+                method,
+                url,
+                data=data,
+                headers=headers,
+                max_allowed_time=remaining_time,
+                timeout=timeout,
+                _credential_refresh_attempt=_credential_refresh_attempt + 1,
+                **kwargs
+            )
+
+        return response
+
+    @property
+    def is_mtls(self):
+        """Indicates if the created SSL channel is mutual TLS."""
+        return self._is_mtls
+
+    def close(self):
+        if self._auth_request_session is not None:
+            self._auth_request_session.close()
+        super(AuthorizedSession, self).close()
diff --git a/.venv/lib/python3.12/site-packages/google/auth/transport/urllib3.py b/.venv/lib/python3.12/site-packages/google/auth/transport/urllib3.py
new file mode 100644
index 00000000..63144f5f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/google/auth/transport/urllib3.py
@@ -0,0 +1,444 @@
+# Copyright 2016 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Transport adapter for urllib3."""
+
+from __future__ import absolute_import
+
+import logging
+import os
+import warnings
+
+# Certifi is Mozilla's certificate bundle. Urllib3 needs a certificate bundle
+# to verify HTTPS requests, and certifi is the recommended and most reliable
+# way to get a root certificate bundle. See
+# http://urllib3.readthedocs.io/en/latest/user-guide.html\
+#   #certificate-verification
+# For more details.
+try:
+    import certifi
+except ImportError:  # pragma: NO COVER
+    certifi = None  # type: ignore
+
+try:
+    import urllib3  # type: ignore
+    import urllib3.exceptions  # type: ignore
+except ImportError as caught_exc:  # pragma: NO COVER
+    raise ImportError(
+        "The urllib3 library is not installed from please install the "
+        "urllib3 package to use the urllib3 transport."
+    ) from caught_exc
+
+from packaging import version  # type: ignore
+
+from google.auth import environment_vars
+from google.auth import exceptions
+from google.auth import transport
+from google.oauth2 import service_account
+
+if version.parse(urllib3.__version__) >= version.parse("2.0.0"):  # pragma: NO COVER
+    RequestMethods = urllib3._request_methods.RequestMethods  # type: ignore
+else:  # pragma: NO COVER
+    RequestMethods = urllib3.request.RequestMethods  # type: ignore
+
+_LOGGER = logging.getLogger(__name__)
+
+
+class _Response(transport.Response):
+    """urllib3 transport response adapter.
+
+    Args:
+        response (urllib3.response.HTTPResponse): The raw urllib3 response.
+    """
+
+    def __init__(self, response):
+        self._response = response
+
+    @property
+    def status(self):
+        return self._response.status
+
+    @property
+    def headers(self):
+        return self._response.headers
+
+    @property
+    def data(self):
+        return self._response.data
+
+
+class Request(transport.Request):
+    """urllib3 request adapter.
+
+    This class is used internally for making requests using various transports
+    in a consistent way. If you use :class:`AuthorizedHttp` you do not need
+    to construct or use this class directly.
+
+    This class can be useful if you want to manually refresh a
+    :class:`~google.auth.credentials.Credentials` instance::
+
+        import google.auth.transport.urllib3
+        import urllib3
+
+        http = urllib3.PoolManager()
+        request = google.auth.transport.urllib3.Request(http)
+
+        credentials.refresh(request)
+
+    Args:
+        http (urllib3.request.RequestMethods): An instance of any urllib3
+            class that implements :class:`~urllib3.request.RequestMethods`,
+            usually :class:`urllib3.PoolManager`.
+
+    .. automethod:: __call__
+    """
+
+    def __init__(self, http):
+        self.http = http
+
+    def __call__(
+        self, url, method="GET", body=None, headers=None, timeout=None, **kwargs
+    ):
+        """Make an HTTP request using urllib3.
+
+        Args:
+            url (str): The URI to be requested.
+            method (str): The HTTP method to use for the request. Defaults
+                to 'GET'.
+            body (bytes): The payload / body in HTTP request.
+            headers (Mapping[str, str]): Request headers.
+            timeout (Optional[int]): The number of seconds to wait for a
+                response from the server. If not specified or if None, the
+                urllib3 default timeout will be used.
+            kwargs: Additional arguments passed throught to the underlying
+                urllib3 :meth:`urlopen` method.
+
+        Returns:
+            google.auth.transport.Response: The HTTP response.
+
+        Raises:
+            google.auth.exceptions.TransportError: If any exception occurred.
+        """
+        # urllib3 uses a sentinel default value for timeout, so only set it if
+        # specified.
+        if timeout is not None:
+            kwargs["timeout"] = timeout
+
+        try:
+            _LOGGER.debug("Making request: %s %s", method, url)
+            response = self.http.request(
+                method, url, body=body, headers=headers, **kwargs
+            )
+            return _Response(response)
+        except urllib3.exceptions.HTTPError as caught_exc:
+            new_exc = exceptions.TransportError(caught_exc)
+            raise new_exc from caught_exc
+
+
+def _make_default_http():
+    if certifi is not None:
+        return urllib3.PoolManager(cert_reqs="CERT_REQUIRED", ca_certs=certifi.where())
+    else:
+        return urllib3.PoolManager()
+
+
+def _make_mutual_tls_http(cert, key):
+    """Create a mutual TLS HTTP connection with the given client cert and key.
+    See https://github.com/urllib3/urllib3/issues/474#issuecomment-253168415
+
+    Args:
+        cert (bytes): client certificate in PEM format
+        key (bytes): client private key in PEM format
+
+    Returns:
+        urllib3.PoolManager: Mutual TLS HTTP connection.
+
+    Raises:
+        ImportError: If certifi or pyOpenSSL is not installed.
+        OpenSSL.crypto.Error: If the cert or key is invalid.
+    """
+    import certifi
+    from OpenSSL import crypto
+    import urllib3.contrib.pyopenssl  # type: ignore
+
+    urllib3.contrib.pyopenssl.inject_into_urllib3()
+    ctx = urllib3.util.ssl_.create_urllib3_context()
+    ctx.load_verify_locations(cafile=certifi.where())
+
+    pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key)
+    x509 = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
+
+    ctx._ctx.use_certificate(x509)
+    ctx._ctx.use_privatekey(pkey)
+
+    http = urllib3.PoolManager(ssl_context=ctx)
+    return http
+
+
+class AuthorizedHttp(RequestMethods):  # type: ignore
+    """A urllib3 HTTP class with credentials.
+
+    This class is used to perform requests to API endpoints that require
+    authorization::
+
+        from google.auth.transport.urllib3 import AuthorizedHttp
+
+        authed_http = AuthorizedHttp(credentials)
+
+        response = authed_http.request(
+            'GET', 'https://www.googleapis.com/storage/v1/b')
+
+    This class implements :class:`urllib3.request.RequestMethods` and can be
+    used just like any other :class:`urllib3.PoolManager`.
+
+    The underlying :meth:`urlopen` implementation handles adding the
+    credentials' headers to the request and refreshing credentials as needed.
+
+    This class also supports mutual TLS via :meth:`configure_mtls_channel`
+    method. In order to use this method, the `GOOGLE_API_USE_CLIENT_CERTIFICATE`
+    environment variable must be explicitly set to `true`, otherwise it does
+    nothing. Assume the environment is set to `true`, the method behaves in the
+    following manner:
+    If client_cert_callback is provided, client certificate and private
+    key are loaded using the callback; if client_cert_callback is None,
+    application default SSL credentials will be used. Exceptions are raised if
+    there are problems with the certificate, private key, or the loading process,
+    so it should be called within a try/except block.
+
+    First we set the environment variable to `true`, then create an :class:`AuthorizedHttp`
+    instance and specify the endpoints::
+
+        regular_endpoint = 'https://pubsub.googleapis.com/v1/projects/{my_project_id}/topics'
+        mtls_endpoint = 'https://pubsub.mtls.googleapis.com/v1/projects/{my_project_id}/topics'
+
+        authed_http = AuthorizedHttp(credentials)
+
+    Now we can pass a callback to :meth:`configure_mtls_channel`::
+
+        def my_cert_callback():
+            # some code to load client cert bytes and private key bytes, both in
+            # PEM format.
+            some_code_to_load_client_cert_and_key()
+            if loaded:
+                return cert, key
+            raise MyClientCertFailureException()
+
+        # Always call configure_mtls_channel within a try/except block.
+        try:
+            is_mtls = authed_http.configure_mtls_channel(my_cert_callback)
+        except:
+            # handle exceptions.
+
+        if is_mtls:
+            response = authed_http.request('GET', mtls_endpoint)
+        else:
+            response = authed_http.request('GET', regular_endpoint)
+
+    You can alternatively use application default SSL credentials like this::
+
+        try:
+            is_mtls = authed_http.configure_mtls_channel()
+        except:
+            # handle exceptions.
+
+    Args:
+        credentials (google.auth.credentials.Credentials): The credentials to
+            add to the request.
+        http (urllib3.PoolManager): The underlying HTTP object to
+            use to make requests. If not specified, a
+            :class:`urllib3.PoolManager` instance will be constructed with
+            sane defaults.
+        refresh_status_codes (Sequence[int]): Which HTTP status codes indicate
+            that credentials should be refreshed and the request should be
+            retried.
+        max_refresh_attempts (int): The maximum number of times to attempt to
+            refresh the credentials and retry the request.
+        default_host (Optional[str]): A host like "pubsub.googleapis.com".
+            This is used when a self-signed JWT is created from service
+            account credentials.
+    """
+
+    def __init__(
+        self,
+        credentials,
+        http=None,
+        refresh_status_codes=transport.DEFAULT_REFRESH_STATUS_CODES,
+        max_refresh_attempts=transport.DEFAULT_MAX_REFRESH_ATTEMPTS,
+        default_host=None,
+    ):
+        if http is None:
+            self.http = _make_default_http()
+            self._has_user_provided_http = False
+        else:
+            self.http = http
+            self._has_user_provided_http = True
+
+        self.credentials = credentials
+        self._refresh_status_codes = refresh_status_codes
+        self._max_refresh_attempts = max_refresh_attempts
+        self._default_host = default_host
+        # Request instance used by internal methods (for example,
+        # credentials.refresh).
+        self._request = Request(self.http)
+
+        # https://google.aip.dev/auth/4111
+        # Attempt to use self-signed JWTs when a service account is used.
+        if isinstance(self.credentials, service_account.Credentials):
+            self.credentials._create_self_signed_jwt(
+                "https://{}/".format(self._default_host) if self._default_host else None
+            )
+
+        super(AuthorizedHttp, self).__init__()
+
+    def configure_mtls_channel(self, client_cert_callback=None):
+        """Configures mutual TLS channel using the given client_cert_callback or
+        application default SSL credentials. The behavior is controlled by
+        `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable.
+        (1) If the environment variable value is `true`, the function returns True
+        if the channel is mutual TLS and False otherwise. The `http` provided
+        in the constructor will be overwritten.
+        (2) If the environment variable is not set or `false`, the function does
+        nothing and it always return False.
+
+        Args:
+            client_cert_callback (Optional[Callable[[], (bytes, bytes)]]):
+                The optional callback returns the client certificate and private
+                key bytes both in PEM format.
+                If the callback is None, application default SSL credentials
+                will be used.
+
+        Returns:
+            True if the channel is mutual TLS and False otherwise.
+
+        Raises:
+            google.auth.exceptions.MutualTLSChannelError: If mutual TLS channel
+                creation failed for any reason.
+        """
+        use_client_cert = os.getenv(
+            environment_vars.GOOGLE_API_USE_CLIENT_CERTIFICATE, "false"
+        )
+        if use_client_cert != "true":
+            return False
+
+        try:
+            import OpenSSL
+        except ImportError as caught_exc:
+            new_exc = exceptions.MutualTLSChannelError(caught_exc)
+            raise new_exc from caught_exc
+
+        try:
+            found_cert_key, cert, key = transport._mtls_helper.get_client_cert_and_key(
+                client_cert_callback
+            )
+
+            if found_cert_key:
+                self.http = _make_mutual_tls_http(cert, key)
+            else:
+                self.http = _make_default_http()
+        except (
+            exceptions.ClientCertError,
+            ImportError,
+            OpenSSL.crypto.Error,
+        ) as caught_exc:
+            new_exc = exceptions.MutualTLSChannelError(caught_exc)
+            raise new_exc from caught_exc
+
+        if self._has_user_provided_http:
+            self._has_user_provided_http = False
+            warnings.warn(
+                "`http` provided in the constructor is overwritten", UserWarning
+            )
+
+        return found_cert_key
+
+    def urlopen(self, method, url, body=None, headers=None, **kwargs):
+        """Implementation of urllib3's urlopen."""
+        # pylint: disable=arguments-differ
+        # We use kwargs to collect additional args that we don't need to
+        # introspect here. However, we do explicitly collect the two
+        # positional arguments.
+
+        # Use a kwarg for this instead of an attribute to maintain
+        # thread-safety.
+        _credential_refresh_attempt = kwargs.pop("_credential_refresh_attempt", 0)
+
+        if headers is None:
+            headers = self.headers
+
+        # Make a copy of the headers. They will be modified by the credentials
+        # and we want to pass the original headers if we recurse.
+        request_headers = headers.copy()
+
+        self.credentials.before_request(self._request, method, url, request_headers)
+
+        response = self.http.urlopen(
+            method, url, body=body, headers=request_headers, **kwargs
+        )
+
+        # If the response indicated that the credentials needed to be
+        # refreshed, then refresh the credentials and re-attempt the
+        # request.
+        # A stored token may expire between the time it is retrieved and
+        # the time the request is made, so we may need to try twice.
+        # The reason urllib3's retries aren't used is because they
+        # don't allow you to modify the request headers. :/
+        if (
+            response.status in self._refresh_status_codes
+            and _credential_refresh_attempt < self._max_refresh_attempts
+        ):
+
+            _LOGGER.info(
+                "Refreshing credentials due to a %s response. Attempt %s/%s.",
+                response.status,
+                _credential_refresh_attempt + 1,
+                self._max_refresh_attempts,
+            )
+
+            self.credentials.refresh(self._request)
+
+            # Recurse. Pass in the original headers, not our modified set.
+            return self.urlopen(
+                method,
+                url,
+                body=body,
+                headers=headers,
+                _credential_refresh_attempt=_credential_refresh_attempt + 1,
+                **kwargs
+            )
+
+        return response
+
+    # Proxy methods for compliance with the urllib3.PoolManager interface
+
+    def __enter__(self):
+        """Proxy to ``self.http``."""
+        return self.http.__enter__()
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        """Proxy to ``self.http``."""
+        return self.http.__exit__(exc_type, exc_val, exc_tb)
+
+    def __del__(self):
+        if hasattr(self, "http") and self.http is not None:
+            self.http.clear()
+
+    @property
+    def headers(self):
+        """Proxy to ``self.http``."""
+        return self.http.headers
+
+    @headers.setter
+    def headers(self, value):
+        """Proxy to ``self.http``."""
+        self.http.headers = value