Skip to content

fix(adk): resolve OAuth persistence, ID token extraction, and auth flow crashes#535

Open
anubhav756 wants to merge 6 commits intoanubhav-adkfrom
anubhav-adk-auth
Open

fix(adk): resolve OAuth persistence, ID token extraction, and auth flow crashes#535
anubhav756 wants to merge 6 commits intoanubhav-adkfrom
anubhav-adk-auth

Conversation

@anubhav756
Copy link
Contributor

Overview

This PR addresses several authentication bugs within the toolbox-adk wrapper that were preventing successful OIDC flows, causing repeated login prompts, and crashing during tool execution.

Changes

1. ID Token Retention (Temporary Monkey Patch)

Problem

adk-python natively drops the id_token during OAuth2 exchange (update_credential_with_tokens), which is strictly required by the MCP Toolbox for USER_IDENTITY authentication.

Solution

Added a temporary monkey patch to hook into the adk-python credential update process and explicitly preserve tokens.get("id_token").

Note

Tracked by TODOs to remove once upstream PR google/adk-python#4402 is merged.

2. Credential Persistence Fix

Problem

Tools repeatedly prompted users to authenticate because the exchanged credentials were not being appropriately persisted across sessions (exchanged_auth_credential was left unpopulated/None).

Solution

Explicitly assigned the newly fetched user credentials to auth_config_adk.exchanged_auth_credential and synced them to storage using tool_context._invocation_context.credential_service.save_credential().

3. Safe Default OIDC Scopes

Problem

Passing an empty list of scopes triggered an AttributeError deep inside the adk-python auth_handler.py due to a falsy chain evaluation on empty dictionaries.

Solution

Added default OIDC fallback scopes (["openid", "profile", "email"]) for USER_IDENTITY flows when no explicit scopes are provided.

4. Auth Token Getter Deduplication

Problem

If a tool required the same authentication service across multiple parameters, the add_auth_token_getter logic would attempt to register it twice, causing a ValueError: already registered.

Solution

Collected needed_services into a deduplicated set and added a protective check before registration (if not hasattr(...) or s not in ...) to ensure idempotency.

Testing

  • Verified that submitting empty scopes successfully defaults to openid profile email and resolves without crashing adk-python.
  • Verified that the id_token is successfully propagated bounds and retrieved via getattr(creds.oauth2, "id_token", ...) during tool execution.
  • Verified that subsequent tool executions load the saved credentials seamlessly from the CredentialService without triggering continuous Google OAuth consent screens.

@anubhav756 anubhav756 self-assigned this Feb 6, 2026
@anubhav756 anubhav756 marked this pull request as ready for review February 6, 2026 22:25
@anubhav756 anubhav756 requested a review from a team as a code owner February 6, 2026 22:25
…ow crashes

This PR addresses several authentication bugs within the `toolbox-adk` wrapper that were preventing successful OIDC flows, causing repeated login prompts, and crashing during tool execution.

`adk-python` natively drops the `id_token` during OAuth2 exchange (`update_credential_with_tokens`), which is strictly required by the MCP Toolbox for `USER_IDENTITY` authentication.
 #### Solution
 Added a temporary monkey patch to hook into the `adk-python` credential update process and explicitly preserve `tokens.get("id_token")`.

 > [!NOTE]
 > Tracked by `TODO`s to remove once upstream PR google/adk-python#4402 is merged.

Tools repeatedly prompted users to authenticate because the exchanged credentials were not being appropriately persisted across sessions (`exchanged_auth_credential` was left unpopulated/None).
Explicitly assigned the newly fetched user credentials to `auth_config_adk.exchanged_auth_credential` and synced them to storage using `tool_context._invocation_context.credential_service.save_credential()`.

Passing an empty list of scopes triggered an `AttributeError` deep inside the `adk-python` `auth_handler.py` due to a falsy chain evaluation on empty dictionaries.
Added default OIDC fallback scopes (`["openid", "profile", "email"]`) for `USER_IDENTITY` flows when no explicit scopes are provided.

If a tool required the same authentication service across multiple parameters, the `add_auth_token_getter` logic would attempt to register it twice, causing a `ValueError: already registered`.
Collected `needed_services` into a deduplicated `set` and added a protective check before registration (`if not hasattr(...) or s not in ...`) to ensure idempotency.

- [x] Verified that submitting empty scopes successfully defaults to `openid profile email` and resolves without crashing `adk-python`.
- [x] Verified that the `id_token` is successfully propagated bounds and retrieved via `getattr(creds.oauth2, "id_token", ...)` during tool execution.
- [x] Verified that subsequent tool executions load the saved credentials seamlessly from the `CredentialService` without triggering continuous Google OAuth consent screens.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant