Skip to content

Commit 0c0e751

Browse files
committed
feat(toolbox-adk): add factory methods for ADK auth objects
Adds factories to convert ADK AuthConfig and AuthCredential objects into Toolbox CredentialConfig.
1 parent b60d9b4 commit 0c0e751

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed

packages/toolbox-adk/src/toolbox_adk/credentials.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
from typing import Any, Dict, List, Optional
1818

1919
from google.auth import credentials as google_creds
20+
from google.adk.auth.auth_credential import AuthCredential, AuthCredentialTypes
21+
from google.adk.auth.auth_tool import AuthConfig, AuthScheme
2022

2123

2224
class CredentialType(Enum):
@@ -106,3 +108,73 @@ def manual_creds(credentials: Any) -> CredentialConfig:
106108
type=CredentialType.MANUAL_CREDS,
107109
credentials=credentials,
108110
)
111+
112+
@staticmethod
113+
def from_adk_auth_config(auth_config: "AuthConfig") -> CredentialConfig:
114+
"""
115+
Creates a CredentialConfig from an ADK AuthConfig object.
116+
117+
Args:
118+
auth_config: The ADK AuthConfig object.
119+
120+
Returns:
121+
CredentialConfig: The corresponding credential configuration.
122+
"""
123+
if auth_config.raw_auth_credential is None:
124+
raise ValueError("AuthConfig must have a raw_auth_credential.")
125+
126+
return CredentialStrategy.from_adk_credentials(
127+
auth_config.auth_scheme, auth_config.raw_auth_credential
128+
)
129+
130+
@staticmethod
131+
def from_adk_credentials(
132+
auth_scheme: "AuthScheme", auth_credential: "AuthCredential"
133+
) -> CredentialConfig:
134+
"""
135+
Creates a CredentialConfig from ADK AuthScheme and AuthCredential objects.
136+
137+
Args:
138+
auth_scheme: The ADK AuthScheme (e.g. OAuth2, HTTP, etc).
139+
auth_credential: The ADK AuthCredential (containing secrets/tokens).
140+
141+
Returns:
142+
CredentialConfig: The corresponding credential configuration.
143+
144+
Raises:
145+
ValueError: If the credential type is not supported.
146+
"""
147+
# Handle OAuth2
148+
if (
149+
auth_credential.auth_type == AuthCredentialTypes.OAUTH2
150+
and auth_credential.oauth2
151+
):
152+
# Try to get scopes from scheme if not in credential, though usually
153+
# we rely on the credential object for the full config in ADK
154+
# strict mode implies we should look at the credential.
155+
return CredentialStrategy.user_identity(
156+
client_id=auth_credential.oauth2.client_id,
157+
client_secret=auth_credential.oauth2.client_secret,
158+
scopes=auth_credential.oauth2.scopes,
159+
)
160+
161+
# Handle HTTP Bearer
162+
if (
163+
auth_credential.auth_type == AuthCredentialTypes.HTTP
164+
and auth_credential.http
165+
):
166+
# auth_credential.http is HttpAuth, verifying scheme is Bearer
167+
# and extracting token from nested credentials object
168+
scheme_type = (auth_credential.http.scheme or "").lower()
169+
if (
170+
scheme_type == "bearer"
171+
and auth_credential.http.credentials
172+
and auth_credential.http.credentials.token
173+
):
174+
return CredentialStrategy.manual_token(
175+
token=auth_credential.http.credentials.token, scheme="Bearer"
176+
)
177+
178+
raise ValueError(
179+
f"Unsupported ADK credential type: {auth_credential.auth_type}"
180+
)

packages/toolbox-adk/tests/unit/test_credentials.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,71 @@ def test_manual_creds(self):
5656
config = CredentialStrategy.manual_creds(fake_creds)
5757
assert config.type == CredentialType.MANUAL_CREDS
5858
assert config.credentials == fake_creds
59+
60+
def test_from_adk_credentials_oauth2(self):
61+
from google.adk.auth.auth_credential import (
62+
AuthCredential,
63+
AuthCredentialTypes,
64+
OAuth2Auth,
65+
)
66+
from fastapi.openapi.models import OAuth2, OAuthFlows
67+
68+
# Mock objects
69+
oauth2_auth = OAuth2Auth(
70+
client_id="cid", client_secret="csec", scopes=["s1"]
71+
)
72+
cred = AuthCredential(
73+
auth_type=AuthCredentialTypes.OAUTH2, oauth2=oauth2_auth
74+
)
75+
# Scheme is required for type hinting but not used for OAuth2 in this impl
76+
scheme = OAuth2(flows=OAuthFlows())
77+
78+
config = CredentialStrategy.from_adk_credentials(scheme, cred)
79+
assert config.type == CredentialType.USER_IDENTITY
80+
assert config.client_id == "cid"
81+
assert config.client_secret == "csec"
82+
assert config.scopes == ["s1"]
83+
84+
def test_from_adk_credentials_http_bearer(self):
85+
from google.adk.auth.auth_credential import (
86+
AuthCredential,
87+
AuthCredentialTypes,
88+
HttpCredentials,
89+
HttpAuth,
90+
)
91+
from fastapi.openapi.models import HTTPBearer
92+
93+
http_creds = HttpCredentials(token="xyz")
94+
http_auth = HttpAuth(scheme="Bearer", credentials=http_creds)
95+
cred = AuthCredential(
96+
auth_type=AuthCredentialTypes.HTTP, http=http_auth
97+
)
98+
scheme = HTTPBearer()
99+
100+
config = CredentialStrategy.from_adk_credentials(scheme, cred)
101+
assert config.type == CredentialType.MANUAL_TOKEN
102+
assert config.token == "xyz"
103+
assert config.scheme == "Bearer"
104+
105+
def test_from_adk_auth_config(self):
106+
from google.adk.auth.auth_tool import AuthConfig
107+
from google.adk.auth.auth_credential import (
108+
AuthCredential,
109+
AuthCredentialTypes,
110+
OAuth2Auth,
111+
)
112+
from fastapi.openapi.models import OAuth2, OAuthFlows
113+
114+
oauth2_auth = OAuth2Auth(
115+
client_id="cid2", client_secret="csec2", scopes=["s2"]
116+
)
117+
cred = AuthCredential(
118+
auth_type=AuthCredentialTypes.OAUTH2, oauth2=oauth2_auth
119+
)
120+
scheme = OAuth2(flows=OAuthFlows())
121+
auth_config = AuthConfig(auth_scheme=scheme, raw_auth_credential=cred)
122+
123+
config = CredentialStrategy.from_adk_auth_config(auth_config)
124+
assert config.type == CredentialType.USER_IDENTITY
125+
assert config.client_id == "cid2"
126+

0 commit comments

Comments
 (0)