44import warnings
55from typing import Callable, Dict, Optional, Sequence, Tuple
66
7+ import google.api_core
78from google.api_core import grpc_helpers # type: ignore
89{% - if service .has_lro %}
910from google.api_core import operations_v1 # type: ignore
@@ -12,6 +13,8 @@ from google.api_core import gapic_v1 # type: ignore
1213from google import auth # type: ignore
1314from google.auth import credentials # type: ignore
1415from google.auth.transport.grpc import SslCredentials # type: ignore
16+ import packaging.version
17+ import pkg_resources
1518
1619import grpc # type: ignore
1720
@@ -27,6 +30,17 @@ from google.iam.v1 import policy_pb2 as policy # type: ignore
2730{% endfilter %}
2831from .base import {{ service.name }}Transport, DEFAULT_CLIENT_INFO
2932
33+ try:
34+ # google.auth.__version__ was added in 1.26.0
35+ _GOOGLE_AUTH_VERSION = auth.__version__
36+ except AttributeError:
37+ try: # try pkg_resources if it is available
38+ _GOOGLE_AUTH_VERSION = pkg_resources.get_distribution("google-auth").version
39+ except pkg_resources.DistributionNotFound: # pragma: NO COVER
40+ _GOOGLE_AUTH_VERSION = None
41+
42+ _API_CORE_VERSION = google.api_core.__version__
43+
3044
3145class {{ service.name }}GrpcTransport({{ service.name }}Transport):
3246 """gRPC backend transport for {{ service.name }}.
@@ -101,6 +115,22 @@ class {{ service.name }}GrpcTransport({{ service.name }}Transport):
101115 google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials``
102116 and ``credentials_file`` are passed.
103117 """
118+
119+ # If a custom API endpoint is set, set scopes to ensure the auth
120+ # library does not used the self-signed JWT flow for service
121+ # accounts
122+ if host.split(":")[0] != self.DEFAULT_HOST and not scopes:
123+ scopes = self.AUTH_SCOPES
124+
125+ # TODO(busunkim): Remove this if/else once google-auth >= 1.25.0 is required
126+ if _GOOGLE_AUTH_VERSION and (
127+ packaging.version.parse(_GOOGLE_AUTH_VERSION)
128+ >= packaging.version.parse("1.25.0")
129+ ):
130+ scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES}
131+ else:
132+ scopes_kwargs = {"scopes": scopes or self.AUTH_SCOPES}
133+
104134 self._ssl_channel_credentials = ssl_channel_credentials
105135
106136 if api_mtls_endpoint:
@@ -120,7 +150,7 @@ class {{ service.name }}GrpcTransport({{ service.name }}Transport):
120150 host = api_mtls_endpoint if ":" in api_mtls_endpoint else api_mtls_endpoint + ":443"
121151
122152 if credentials is None:
123- credentials, _ = auth.default(scopes=self.AUTH_SCOPES , quota_project_id=quota_project_id)
153+ credentials, _ = auth.default(**scopes_kwargs , quota_project_id=quota_project_id)
124154
125155 # Create SSL credentials with client_cert_source or application
126156 # default SSL credentials.
@@ -138,7 +168,7 @@ class {{ service.name }}GrpcTransport({{ service.name }}Transport):
138168 credentials=credentials,
139169 credentials_file=credentials_file,
140170 ssl_credentials=ssl_credentials,
141- scopes=scopes or self.AUTH_SCOPES ,
171+ scopes=scopes,
142172 quota_project_id=quota_project_id,
143173 options=[
144174 ("grpc.max_send_message_length", -1),
@@ -150,7 +180,7 @@ class {{ service.name }}GrpcTransport({{ service.name }}Transport):
150180 host = host if ":" in host else host + ":443"
151181
152182 if credentials is None:
153- credentials, _ = auth.default(scopes=self.AUTH_SCOPES , quota_project_id=quota_project_id)
183+ credentials, _ = auth.default(**scopes_kwargs , quota_project_id=quota_project_id)
154184
155185 if client_cert_source_for_mtls and not ssl_channel_credentials:
156186 cert, key = client_cert_source_for_mtls()
@@ -164,7 +194,7 @@ class {{ service.name }}GrpcTransport({{ service.name }}Transport):
164194 credentials=credentials,
165195 credentials_file=credentials_file,
166196 ssl_credentials=self._ssl_channel_credentials,
167- scopes=scopes or self.AUTH_SCOPES ,
197+ scopes=scopes,
168198 quota_project_id=quota_project_id,
169199 options=[
170200 ("grpc.max_send_message_length", -1),
@@ -182,7 +212,7 @@ class {{ service.name }}GrpcTransport({{ service.name }}Transport):
182212 host=host,
183213 credentials=credentials,
184214 credentials_file=credentials_file,
185- scopes=scopes or self.AUTH_SCOPES ,
215+ scopes=scopes,
186216 quota_project_id=quota_project_id,
187217 client_info=client_info,
188218 )
@@ -220,7 +250,19 @@ class {{ service.name }}GrpcTransport({{ service.name }}Transport):
220250 google.api_core.exceptions.DuplicateCredentialArgs: If both ``credentials``
221251 and ``credentials_file`` are passed.
222252 """
223- scopes = scopes or cls.AUTH_SCOPES
253+ self_signed_jwt_kwargs = {}
254+
255+ # TODO(busunkim): Remove this if/else once google-api-core >= 1.26.0 is required
256+ if _API_CORE_VERSION and (
257+ packaging.version.parse(_API_CORE_VERSION)
258+ >= packaging.version.parse("1.26.0")
259+ ):
260+ self_signed_jwt_kwargs["default_scopes"] = cls.AUTH_SCOPES
261+ self_signed_jwt_kwargs["scopes"] = scopes
262+ self_signed_jwt_kwargs["default_host"] = cls.DEFAULT_HOST
263+ else:
264+ self_signed_jwt_kwargs["scopes"] = scopes or cls.AUTH_SCOPES
265+
224266 return grpc_helpers.create_channel(
225267 host,
226268 credentials=credentials,
0 commit comments