8000 refactor: Adapt service account credential exchanger to base credenti… · suryaprabhakar/adk-python@0a96253 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0a96253

Browse files
seanzhougooglecopybara-github
authored andcommitted
refactor: Adapt service account credential exchanger to base credential exchanger interface
PiperOrigin-RevId: 772710438
1 parent f9fa784 commit 0a96253

File tree

4 files changed

+203
-86
lines changed

4 files changed

+203
-86
lines changed

src/google/adk/auth/exchanger/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,9 @@
1515
"""Credential exchanger module."""
1616

1717
from .base_credential_exchanger import BaseCredentialExchanger
18-
from .credential_exchanger_registry import CredentialExchangerRegistry
1918
from .service_account_credential_exchanger import ServiceAccountCredentialExchanger
2019

2120
__all__ = [
2221
"BaseCredentialExchanger",
23-
"CredentialExchangerRegistry",
2422
"ServiceAccountCredentialExchanger",
2523
]

src/google/adk/auth/service_account_credential_exchanger.py renamed to src/google/adk/auth/exchanger/service_account_credential_exchanger.py

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,64 +16,79 @@
1616

1717
from __future__ import annotations
1818

19+
from typing import Optional
20+
1921
import google.auth
2022
from google.auth.transport.requests import Request
2123
from google.oauth2 import service_account
24+
from typing_extensions import override
2225

23-
from ..utils.feature_decorator import experimental
24-
from .auth_credential import AuthCredential
25-
from .auth_credential import AuthCredentialTypes
26-
from .auth_credential import HttpAuth
27-
from .auth_credential import HttpCredentials
26+
from ...utils.feature_decorator import experimental
27+
from ..auth_credential import AuthCredential
28+
from ..auth_credential import AuthCredentialTypes
29+
from ..auth_schemes import AuthScheme
30+
from .base_credential_exchanger import BaseCredentialExchanger
2831

2932

3033
@experimental
31-
class ServiceAccountCredentialExchanger:
34+
class ServiceAccountCredentialExchanger(BaseCredentialExchanger):
3235
"""Exchanges Google Service Account credentials for an access token.
3336
3437
Uses the default service credential if `use_default_credential = True`.
3538
Otherwise, uses the service account credential provided in the auth
3639
credential.
3740
"""
3841

39-
def __init__(self, credential: AuthCredential):
40-
if credential.auth_type != AuthCredentialTypes.SERVICE_ACCOUNT:
41-
raise ValueError("Credential is not a service account credential.")
42-
self._credential = credential
43-
44-
def exchange(self) -> AuthCredential:
42+
@override
43+
async def exchange(
44+
self,
45+
auth_credential: AuthCredential,
46+
auth_scheme: Optional[AuthScheme] = None,
47+
) -> AuthCredential:
4548
"""Exchanges the service account auth credential for an access token.
4649
4750
If the AuthCredential contains a service account credential, it will be used
4851
to exchange for an access token. Otherwise, if use_default_credential is True,
4952
the default application credential will be used for exchanging an access token.
5053
54+
Args:
55+
auth_scheme: The authentication scheme.
56+
auth_credential: The credential to exchange.
57+
5158
Returns:
52-
An AuthCredential in HTTP Bearer format, containing the access token.
59+
An AuthCredential in OAUTH2 format, containing the exchanged credential JSON.
5360
5461
Raises:
5562
ValueError: If service account credentials are missing or invalid.
5663
Exception: If credential exchange or refresh fails.
5764
"""
65+
if auth_credential is None:
66+
raise ValueError("Credential cannot be None.")
67+
68+
if auth_credential.auth_type != AuthCredentialTypes.SERVICE_ACCOUNT:
69+
raise ValueError("Credential is not a service account credential.")
70+
71+
if auth_credential.service_account is None:
72+
raise ValueError(
73+
"Service account credentials are missing. Please provide them."
74+
)
75+
5876
if (
59-
self._credential is None
60-
or self._credential.service_account is None
61-
or (
62-
self._credential.service_account.service_account_credential is None
63-
and not self._credential.service_account.use_default_credential
64-
)
77+
auth_credential.service_account.service_account_credential is None
78+
and not auth_credential.service_account.use_default_credential
6579
):
6680
raise ValueError(
67-
"Service account credentials are missing. Please provide them, or set"
68-
" `use_default_credential = True` to use application default"
69-
" credential in a hosted service like Google Cloud Run."
81+
"Service account credentials are invalid. Please set the"
82+
" service_account_credential field or set `use_default_credential ="
83+
" True` to use application default credential in a hosted service"
84+
" like Google Cloud Run."
7085
)
7186

7287
try:
73-
if self._credential.service_account.use_default_credential:
88+
if auth_credential.service_account.use_default_credential:
7489
credentials, _ = google.auth.default()
7590
else:
76-
config = self._credential.service_account
91+
config = auth_credential.service_account
7792
credentials = service_account.Credentials.from_service_account_info(
7893
config.service_account_credential.model_dump(), scopes=config.scopes
7994
)
@@ -82,11 +97,8 @@ def exchange(self) -> AuthCredential:
8297
credentials.refresh(Request())
8398

8499
return AuthCredential(
85-
auth_type=AuthCredentialTypes.HTTP,
86-
http=HttpAuth(
87-
scheme="bearer",
88-
credentials=HttpCredentials(token=credentials.token),
89-
),
100+
auth_type=AuthCredentialTypes.OAUTH2,
101+
google_oauth2_json=credentials.to_json(),
90102
)
91103
except Exception as e:
92104
raise ValueError(f"Failed to exchange service account token: {e}") from e
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Tests for credential exchanger."""

0 commit comments

Comments
 (0)
0