Skip to content

Commit 59c654f

Browse files
committed
feat(apigee): add userinfo.email scope for tokeninfo user identification
ApigeeLlm now explicitly requests the userinfo.email OAuth scope alongside cloud-platform when creating credentials. This enables Apigee Gateway to identify callers via Google's tokeninfo API when using Service Account key authentication. Fixes #4721
1 parent a61ccf3 commit 59c654f

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

src/google/adk/models/apigee_llm.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from typing import Optional
3030
from typing import TYPE_CHECKING
3131

32+
import google.auth
3233
from google.adk import version as adk_version
3334
from google.genai import types
3435
import httpx
@@ -52,6 +53,11 @@
5253
_PROJECT_ENV_VARIABLE_NAME = 'GOOGLE_CLOUD_PROJECT'
5354
_LOCATION_ENV_VARIABLE_NAME = 'GOOGLE_CLOUD_LOCATION'
5455

56+
_APIGEE_SCOPES = [
57+
'https://www.googleapis.com/auth/cloud-platform',
58+
'https://www.googleapis.com/auth/userinfo.email',
59+
]
60+
5561
_CUSTOM_METADATA_FIELDS = (
5662
'id',
5763
'created',
@@ -232,13 +238,16 @@ def api_client(self) -> Client:
232238
**kwargs_for_http_options,
233239
)
234240

241+
credentials, _ = google.auth.default(scopes=_APIGEE_SCOPES)
242+
235243
kwargs_for_client = {}
236244
kwargs_for_client['vertexai'] = self._isvertexai
237245
if self._isvertexai:
238246
kwargs_for_client['project'] = self._project
239247
kwargs_for_client['location'] = self._location
240248

241249
return Client(
250+
credentials=credentials,
242251
http_options=http_options,
243252
**kwargs_for_client,
244253
)

tests/unittests/models/test_apigee_llm.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from unittest import mock
1919
from unittest.mock import AsyncMock
2020

21+
from google.adk.models.apigee_llm import _APIGEE_SCOPES
2122
from google.adk.models.apigee_llm import ApigeeLlm
2223
from google.adk.models.apigee_llm import CompletionsHTTPClient
2324
from google.adk.models.llm_request import LlmRequest
@@ -627,3 +628,42 @@ async def test_api_key_injection_openai(model):
627628
)
628629
client = apigee_llm._completions_http_client
629630
assert client._headers['Authorization'] == 'Bearer sk-test-key'
631+
632+
633+
@pytest.mark.asyncio
634+
@mock.patch('google.genai.Client')
635+
@mock.patch('google.adk.models.apigee_llm.google.auth.default')
636+
async def test_api_client_requests_userinfo_email_scope(
637+
mock_auth_default, mock_client_constructor, llm_request
638+
):
639+
"""Tests that api_client requests userinfo.email scope for Apigee Gateway tokeninfo."""
640+
mock_credentials = mock.Mock()
641+
mock_auth_default.return_value = (mock_credentials, 'test-project')
642+
643+
mock_client_instance = mock.Mock()
644+
mock_client_instance.aio.models.generate_content = AsyncMock(
645+
return_value=types.GenerateContentResponse(
646+
candidates=[
647+
types.Candidate(
648+
content=Content(
649+
parts=[Part.from_text(text='Test response')],
650+
role='model',
651+
)
652+
)
653+
]
654+
)
655+
)
656+
mock_client_constructor.return_value = mock_client_instance
657+
658+
apigee_llm = ApigeeLlm(
659+
model=APIGEE_GEMINI_MODEL_ID,
660+
proxy_url=PROXY_URL,
661+
)
662+
_ = [resp async for resp in apigee_llm.generate_content_async(llm_request)]
663+
664+
mock_auth_default.assert_called_once_with(scopes=_APIGEE_SCOPES)
665+
assert 'https://www.googleapis.com/auth/userinfo.email' in _APIGEE_SCOPES
666+
assert 'https://www.googleapis.com/auth/cloud-platform' in _APIGEE_SCOPES
667+
668+
_, kwargs = mock_client_constructor.call_args
669+
assert kwargs['credentials'] is mock_credentials

0 commit comments

Comments
 (0)