Skip to content

Commit 6ccb837

Browse files
google-genai-botcopybara-github
authored andcommitted
fix: Use official SDK for credential finalization in GCP auth sample
PiperOrigin-RevId: 960164313
1 parent 93f57f4 commit 6ccb837

2 files changed

Lines changed: 49 additions & 51 deletions

File tree

contributing/samples/integrations/gcp_auth/agent.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,21 @@
3535
SPOTIFY_3LO_AUTH_PROVIDER_ID = os.environ.get("SPOTIFY_3LO_AUTH_PROVIDER_ID")
3636

3737
MAPS_API_AUTH_PROVIDER = (
38-
f"projects/{PROJECT_ID}/locations/{LOCATION}/connectors/"
38+
f"projects/{PROJECT_ID}/locations/{LOCATION}/authProviders/"
3939
f"{MAPS_API_AUTH_PROVIDER_ID}"
4040
)
4141
SPOTIFY_2LO_AUTH_PROVIDER = (
42-
f"projects/{PROJECT_ID}/locations/{LOCATION}/connectors/"
42+
f"projects/{PROJECT_ID}/locations/{LOCATION}/authProviders/"
4343
f"{SPOTIFY_2LO_AUTH_PROVIDER_ID}"
4444
)
4545
SPOTIFY_3LO_AUTH_PROVIDER = (
46-
f"projects/{PROJECT_ID}/locations/{LOCATION}/connectors/"
46+
f"projects/{PROJECT_ID}/locations/{LOCATION}/authProviders/"
4747
f"{SPOTIFY_3LO_AUTH_PROVIDER_ID}"
4848
)
4949

5050
MAPS_MCP_ENDPOINT = "https://mapstools.googleapis.com/mcp"
5151
CONTINUE_URI = "http://localhost:8080/commit"
52-
MODEL = "gemini-2.5-flash"
52+
MODEL = "gemini/gemini-3.5-flash"
5353

5454

5555
async def spotify_search_track(

contributing/samples/integrations/gcp_auth/client/main.py

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
"""A FastAPI client for interacting with ADK remote agents and handling GCP authentication."""
1616

17+
import asyncio
1718
import base64
1819
import importlib
1920
import json
@@ -32,19 +33,16 @@
3233
from fastapi.staticfiles import StaticFiles
3334
from google.adk.auth import AuthConfig
3435
from google.adk.runners import InMemoryRunner
36+
from google.api_core.client_options import ClientOptions
3537
import google.auth
3638
import google.auth.transport.requests
39+
from google.cloud.agentidentitycredentials_v1 import AuthProviderCredentialsServiceClient
40+
from google.cloud.agentidentitycredentials_v1 import FinalizeCredentialsRequest
3741
from google.genai import types
38-
import httpx
3942
from pydantic import BaseModel
4043
import uvicorn
4144
import vertexai
4245

43-
TARGET_HOST = (
44-
os.environ.get("IAM_CONNECTOR_CREDENTIALS_TARGET_HOST")
45-
or "iamconnectorcredentials.googleapis.com"
46-
)
47-
4846
# Add agent project directory to path to allow importing local agents
4947
AGENT_PROJECT_DIR = os.environ.get("AGENT_PROJECT_DIR") or os.path.dirname(
5048
os.path.dirname(os.path.abspath(__file__))
@@ -375,6 +373,10 @@ async def validate_user_id(request: Request):
375373
auth_provider_name = request.query_params.get(
376374
"connector_name"
377375
) or request.query_params.get("auth_provider_name")
376+
if auth_provider_name:
377+
auth_provider_name = auth_provider_name.replace(
378+
"/connectors/", "/authProviders/"
379+
)
378380

379381
print(
380382
f"Callback received: user_id_validation_state={user_id_validation_state},"
@@ -408,51 +410,47 @@ async def validate_user_id(request: Request):
408410
}
409411

410412
try:
411-
url = (
412-
f"https://{TARGET_HOST}/v1alpha/{auth_provider_name}"
413-
"/credentials:finalize"
413+
state_bytes = base64.urlsafe_b64decode(
414+
user_id_validation_state + "=" * (-len(user_id_validation_state) % 4)
414415
)
415-
headers = {
416-
"Content-Type": "application/json",
417-
}
418-
payload = {
419-
"userId": user_id,
420-
"userIdValidationState": user_id_validation_state,
421-
"consentNonce": consent_nonce,
422-
}
423416

424-
print(f"Calling FinalizeCredentials via HTTP POST to: {url}")
425-
print(f"Headers: {headers}")
426-
print(f"Payload: {payload}")
427-
428-
async with httpx.AsyncClient() as client:
429-
response = await client.post(url, json=payload, headers=headers)
430-
431-
print(f"HTTP Response Status: {response.status_code}")
432-
print(f"HTTP Response Body: {response.text}")
433-
434-
if response.status_code == 200:
435-
# Return a simple HTML page to indicate OAuth success
436-
html_content = """
437-
<!DOCTYPE html>
438-
<html>
439-
<head>
440-
<title>Authorization Successful</title>
441-
</head>
442-
<body>
443-
<p>Authorization successful! You can close this window.</p>
444-
</body>
445-
</html>
446-
"""
447-
return HTMLResponse(content=html_content)
448-
else:
449-
return {
450-
"status": "error",
451-
"message": f"HTTP Error {response.status_code}: {response.text}",
452-
}
417+
client_options = None
418+
if host := os.environ.get("AGENT_IDENTITY_CREDENTIALS_TARGET_HOST"):
419+
client_options = ClientOptions(api_endpoint=host)
420+
421+
client = AuthProviderCredentialsServiceClient(
422+
client_options=client_options, transport="rest"
423+
)
424+
425+
finalize_request = FinalizeCredentialsRequest(
426+
auth_provider=auth_provider_name,
427+
user_id=user_id,
428+
user_id_validation_state=state_bytes,
429+
consent_nonce=consent_nonce,
430+
)
431+
432+
print(
433+
"Calling FinalizeCredentials via AuthProviderCredentialsServiceClient"
434+
f" for auth_provider: {auth_provider_name}"
435+
)
436+
await asyncio.to_thread(client.finalize_credentials, finalize_request)
437+
438+
# Return a simple HTML page to indicate OAuth success
439+
html_content = """
440+
<!DOCTYPE html>
441+
<html>
442+
<head>
443+
<title>Authorization Successful</title>
444+
</head>
445+
<body>
446+
<p>Authorization successful! You can close this window.</p>
447+
</body>
448+
</html>
449+
"""
450+
return HTMLResponse(content=html_content)
453451

454452
except Exception as e:
455-
print(f"Error calling FinalizeCredentials via HTTP: {e}")
453+
print(f"Error finalizing credentials: {e}")
456454
return {
457455
"status": "error",
458456
"message": f"Failed to finalize credentials: {str(e)}",

0 commit comments

Comments
 (0)