adk-python icon indicating copy to clipboard operation
adk-python copied to clipboard

Agentspace authorization access tokens no longer available in ToolContext.state["temp:*]

Open babeal opened this issue 2 months ago • 15 comments

Describe the bug

When ADK is deployed on AgentEngine and registered as an Agent in Agentspace with an authorizer, the OAUTH access token the agent needs to communicate with an external service is passed as temp:<authorizer-id> to the agent. And before ADK 1.17.0, we were able to read these variables in the before_tool_callback method using the tool_context.state dict. But as of ADK Python v1.17.0, the tokens are no longer found within the state variable causing integrations to break.

I think this bug was introduced into the InMemorySessionService._create_session_impl() with the addition of the extract state deltas and the explicit removal of temp variables from state. So when create_session is called and state is passed in with the authorization keys under the temp: prefix, they are not added to state.

To Reproduce

Steps to reproduce the behavior:

  1. Use ADK 1.17.0
  2. Create a simple agent with a before_tool_callback method that reads temp:<authorization_id> variables from state.
  3. Deploy using agent engine with default AdkApp
  4. Create OAUTH Client and register client and scopes to an authorizer
  5. Register Agent with Agentspace with authorizer.

Expected behavior

OAuth credentials read from request.authorizations within the AdkApp should be accessible within ToolContext.state

Desktop (please complete the following information):

  • OS: Linux (reproduced on Agent Engine)
  • Python version: 3.13+
  • ADK version: 1.17.0

Model Information:

  • Are you using LiteLLM: No
  • Which model is being used: gemini-2.5-flash

Additional context

Impact

  • Severity: High - Breaks Agentspace + Authorizer authorization for ADK agents deployed onto Agent Engine using the default AdkApp
  • Affected versions: v1.17.0 only
  • Working version: v1.16.0

babeal avatar Oct 24 '25 16:10 babeal

Might be related to https://github.com/google/adk-python/issues/3047

Taking a look as well

lindongli avatar Oct 28 '25 23:10 lindongli

@lindongli In 1.17 temp variables were removed from session state all together. They seem to have moved to the CredentialService where credentials are injected into ToolContext before the tool gets them. However, this has broken Gemini Enterprise with authorizer integration as the AdkApp explicitly passes the authorization access tokens as initial state to the create session method. This will have to be worked out internally.

babeal avatar Oct 28 '25 23:10 babeal

Confirmed this is a regression in v1.17.0. The issue is in _session_util.py line 47 where extract_state_delta() explicitly filters out temp: prefixed variables with elif not key.startswith(State.TEMP_PREFIX). When AdkApp passes authorizer OAuth tokens as temp:<authorizer-id> in create_session state, they're excluded before reaching session state, breaking before_tool_callback access. The simple fix is changing line 47 to else: to include all non-app/non-user keys (including temp:) in session state, restoring v1.16.0 behavior while maintaining backward compatibility.

surajksharma07 avatar Nov 02 '25 19:11 surajksharma07

Thanks for reporting this issue! As discussed internally, temp: states are supposed to be only available in memory temporarily. We need a more robust way for the Agentspace authorization use case. Changing this to a feature request now.

xuanyang15 avatar Nov 04 '25 05:11 xuanyang15

+1 Facing this problem in v.1.17

Would appreciate to have a code sample for AgentSpace aka Gemini Enterprise authorization in Google ADK

kushalbhabra avatar Nov 06 '25 06:11 kushalbhabra

Tested with v1.18 and preview AdkApp - and there the access token is available in state, just without the temp: prefix

i.e. access token can be retrieved by

access_token = callback_context.state.get({auth_id})

Should be available even on latest AdkApp

johadahl avatar Nov 10 '25 15:11 johadahl

Yea it seems that there is a temporary fix. If adk >= 1.17 then aiplatform must be => 1.126.0.

babeal avatar Nov 10 '25 23:11 babeal

@johadahl , I am trying to access the user email via the access_token. As I want to use that user email onto the next agents. Any insight on this, how can I access that ?

rghv-cwx avatar Nov 11 '25 12:11 rghv-cwx

@rghv-cwx To get user email from the access token, use Google's userinfo endpoint. In your before_tool_callback or tool:

import httpx

async def get_user_email(access_token: str) -> str:
    async with httpx.AsyncClient() as client:
        resp = await client.get(
            "https://www.googleapis.com/oauth2/v3/userinfo",
            headers={"Authorization": f"Bearer {access_token}"}
        )
        return resp.json().get("email")

To pass to sub-agents, store it in session state: callback_context.state["user_email"] = email - sub-agents can then read it from their own context.state.

surajksharma07 avatar Nov 22 '25 11:11 surajksharma07

@surajksharma07 , Thank you for this. I am majorly facing issue in getting the access token while deploying it to agent engine and then on gemini enterprise.

I am not sure what i am doing wrong, could you possible provide any reference or/ implementation code for that?

rghv-cwx avatar Nov 22 '25 12:11 rghv-cwx

@rghv-cwx Here's a working example for Agent Engine + Gemini Enterprise (requires ADK >= 1.17 and aiplatform >= 1.126.0):

from google.adk.agents import LlmAgent

def before_tool_callback(callback_context, tool):
    # auth_id is your authorizer ID from Agentspace config (without temp: prefix)
    auth_id = "your-authorizer-id"
    access_token = callback_context.state.get(auth_id)
    if access_token:
        # Use token for API calls or store for sub-agents
        callback_context.state["access_token"] = access_token
    return None

root_agent = LlmAgent(
    name="my_agent",
    model="gemini-2.5-flash",
    before_tool_callback=before_tool_callback,
    tools=[...]
)

Make sure your authorizer is properly configured in Agentspace and the agent is registered with it. The auth_id should match exactly what you set up in your Agentspace authorizer configuration.

surajksharma07 avatar Nov 22 '25 14:11 surajksharma07

Thanks! @surajksharma07 for the solution. I have also written a small blog covering this implementation, in case this is helpful to anyone seeking to solve a similar use case:

https://medium.com/@raghav.chaturvedi_75760/building-secure-adk-agents-on-gemini-enterprise-using-user-identity-for-dynamic-filtering-49c84e798ae8

rghv-cwx avatar Dec 02 '25 09:12 rghv-cwx

@rghv-cwx Thanks for sharing your blog post.

That's a great resource for the community - the step-by-step guide with dynamic filtering using user identity is exactly what others implementing Agentspace authorization will need.

Appreciate you documenting this implementation pattern for ADK + Gemini Enterprise users.

surajksharma07 avatar Dec 02 '25 10:12 surajksharma07

@surajksharma07 Absolutely, Please let me know In case there is an ADK or Gemini Enterprise publication as well where I can publish this, so that developers are easily able to find this.

rghv-cwx avatar Dec 02 '25 10:12 rghv-cwx

@rghv-cwx Here are a few channels where your implementation guide would be valuable:

  1. ADK GitHub Discussions - Post in the google/adk-python Discussions under "Show and tell" to share with the community
  2. Google Cloud Community - Submit to Google Cloud Community tutorials for official visibility
  3. Contributing Examples - Consider submitting a PR to add this as a sample in the adk-python/contributing/samples/ directory (similar to the oauth_calendar_agent example)

The ADK team often references community contributions in release notes and documentation. Feel free to link your Medium post in a GitHub

Discussion - that's where many developers look for real-world implementation patterns.

Thanks!

surajksharma07 avatar Dec 02 '25 10:12 surajksharma07