arithmetic1728: > This looks good. Do you have the bandwith in the next few weeks to add this to the generators? We'll have to coordinate releasing api-core and updating the client library dependencies.

Yes, I am working on it right now.
diff --git a/google/api_core/client_options.py b/google/api_core/client_options.py
index 137043f..7cb49c6 100644
--- a/google/api_core/client_options.py
+++ b/google/api_core/client_options.py
@@ -24,7 +24,12 @@ You can pass a client options object to a client.
     from google.api_core.client_options import ClientOptions
     from google.cloud.vision_v1 import ImageAnnotatorClient
 
-    options = ClientOptions(api_endpoint="foo.googleapis.com")
+    def get_client_cert():
+        # code to load client certificate and private key.
+        return client_cert_bytes, client_private_key_bytes
+
+    options = ClientOptions(api_endpoint="foo.googleapis.com",
+        client_cert_source=get_client_cert)
 
     client = ImageAnnotatorClient(client_options=options)
 
@@ -34,7 +39,11 @@ You can also pass a dictionary.
 
     from google.cloud.vision_v1 import ImageAnnotatorClient
 
-    client = ImageAnnotatorClient(client_options={"api_endpoint": "foo.googleapis.com"})
+    client = ImageAnnotatorClient(
+        client_options={
+            "api_endpoint": "foo.googleapis.com",
+            "client_cert_source" : get_client_cert
+        })
 
 
 """
@@ -45,10 +54,14 @@ class ClientOptions(object):
 
     Args:
         api_endpoint (str): The desired API endpoint, e.g., compute.googleapis.com
+        client_cert_source (Callable[[], (bytes, bytes)]): An optional callback
+            which returns client certificate bytes and private key bytes both in
+            PEM format.
     """
 
-    def __init__(self, api_endpoint=None):
+    def __init__(self, api_endpoint=None, client_cert_source=None):
         self.api_endpoint = api_endpoint
+        self.client_cert_source = client_cert_source
 
     def __repr__(self):
         return "ClientOptions: " + repr(self.__dict__)
diff --git a/noxfile.py b/noxfile.py
index 249ace7..dfb1257 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -112,7 +112,7 @@ def docs(session):
 
     session.install(".", "grpcio >= 1.8.2", "grpcio-gcp >= 0.2.2")
     session.install("-e", ".")
-    session.install("sphinx", "alabaster", "recommonmark")
+    session.install("sphinx < 3.0", "alabaster", "recommonmark")
 
     shutil.rmtree(os.path.join("docs", "_build"), ignore_errors=True)
     session.run(
diff --git a/setup.py b/setup.py
index 820d5f4..30f83a6 100644
--- a/setup.py
+++ b/setup.py
@@ -31,7 +31,7 @@ release_status = "Development Status :: 5 - Production/Stable"
 dependencies = [
     "googleapis-common-protos >= 1.6.0, < 2.0dev",
     "protobuf >= 3.4.0",
-    "google-auth >= 0.4.0, < 2.0dev",
+    "google-auth >= 1.14.0, < 2.0dev",
     "requests >= 2.18.0, < 3.0.0dev",
     "setuptools >= 34.0.0",
     "six >= 1.10.0",

add client_cert_source to ClientOptions
google-api-go-client uses `WithClientCertSource` in `ClientOptions` to provide client cert/key, we need to add a `client_cert_source` to `ClientOptions` in python as well.
diff --git a/tests/unit/test_client_options.py b/tests/unit/test_client_options.py
index 952adfc..7f17544 100644
--- a/tests/unit/test_client_options.py
+++ b/tests/unit/test_client_options.py
@@ -17,26 +17,46 @@ import pytest
 from google.api_core import client_options
 
 
+def get_client_cert():
+    return b"cert", b"key"
+
+
 def test_constructor():
-    options = client_options.ClientOptions(api_endpoint="foo.googleapis.com")
+
+    options = client_options.ClientOptions(
+        api_endpoint="foo.googleapis.com", client_cert_source=get_client_cert
+    )
 
     assert options.api_endpoint == "foo.googleapis.com"
+    assert options.client_cert_source() == (b"cert", b"key")
 
 
 def test_from_dict():
-    options = client_options.from_dict({"api_endpoint": "foo.googleapis.com"})
+    options = client_options.from_dict(
+        {"api_endpoint": "foo.googleapis.com", "client_cert_source": get_client_cert}
+    )
 
     assert options.api_endpoint == "foo.googleapis.com"
+    # assert options.client_cert_source == get_client_cert
+    assert options.client_cert_source() == (b"cert", b"key")
 
 
 def test_from_dict_bad_argument():
     with pytest.raises(ValueError):
         client_options.from_dict(
-            {"api_endpoint": "foo.googleapis.com", "bad_arg": "1234"}
+            {
+                "api_endpoint": "foo.googleapis.com",
+                "bad_arg": "1234",
+                "client_cert_source": get_client_cert,
+            }
         )
 
 
 def test_repr():
     options = client_options.ClientOptions(api_endpoint="foo.googleapis.com")
 
-    assert repr(options) == "ClientOptions: {'api_endpoint': 'foo.googleapis.com'}"
+    assert (
+        repr(options)
+        == "ClientOptions: {'api_endpoint': 'foo.googleapis.com', 'client_cert_source': None}"
+        or "ClientOptions: {'client_cert_source': None, 'api_endpoint': 'foo.googleapis.com'}"
+    )

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-xdist pytest-mock pytest-asyncio
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
cachetools==4.2.4
certifi==2025.1.31
charset-normalizer==3.4.1
coverage==7.8.0
exceptiongroup==1.2.2
execnet==2.1.1
-e git+https://github.com/googleapis/python-api-core.git@0c2c556e149b0b6696b515f3cdbd10a698b4e30b#egg=google_api_core
google-auth==1.35.0
googleapis-common-protos==1.69.2
idna==3.10
iniconfig==2.1.0
packaging==24.2
pluggy==1.5.0
protobuf==6.30.2
pyasn1==0.6.1
pyasn1_modules==0.4.2
pytest==8.3.5
pytest-asyncio==0.26.0
pytest-cov==6.0.0
pytest-mock==3.14.0
pytest-xdist==3.6.1
pytz==2025.2
requests==2.32.3
rsa==4.9
six==1.17.0
tomli==2.2.1
typing_extensions==4.13.0
urllib3==2.3.0

name: python-api-core
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - cachetools==4.2.4
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - coverage==7.8.0
      - exceptiongroup==1.2.2
      - execnet==2.1.1
      - google-auth==1.35.0
      - googleapis-common-protos==1.69.2
      - idna==3.10
      - iniconfig==2.1.0
      - packaging==24.2
      - pluggy==1.5.0
      - protobuf==6.30.2
      - pyasn1==0.6.1
      - pyasn1-modules==0.4.2
      - pytest==8.3.5
      - pytest-asyncio==0.26.0
      - pytest-cov==6.0.0
      - pytest-mock==3.14.0
      - pytest-xdist==3.6.1
      - pytz==2025.2
      - requests==2.32.3
      - rsa==4.9
      - six==1.17.0
      - tomli==2.2.1
      - typing-extensions==4.13.0
      - urllib3==2.3.0
prefix: /opt/conda/envs/python-api-core

tests/unit/test_client_options.py::test_constructor tests/unit/test_client_options.py::test_from_dict
tests/unit/test_client_options.py::test_from_dict_bad_argument tests/unit/test_client_options.py::test_repr
google/api_core/client_options.py noxfile.py setup.py
google/api_core/client_options.py noxfile.py setup.py