Skip to content

feat(toolbox-langchain): Support per-invocation auth via RunnableConfig #291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: anubhav-state-li
Choose a base branch
from

Conversation

anubhav756
Copy link
Contributor

@anubhav756 anubhav756 commented Jun 19, 2025

Summary

This PR introduces a major enhancement to the toolbox-langchain package by adding support for dynamic, per-invocation authentication. This is achieved by reading auth_token_getters from LangChain's standard RunnableConfig, enabling ToolboxTool to be used safely and effectively in multi-user environments like LangGraph.

Motivation

Currently, authentication tokens can only be provided to a ToolboxTool at initialization time, either via ToolboxClient.load_tool/load_toolset or by calling tool.add_auth_token_getters() on the tool instance. This static binding of credentials poses a significant challenge in modern agentic frameworks like LangGraph.

Challenge

In LangGraph, a single graph containing tool instances is often created once and then shared across multiple users and requests. It is insecure and impractical to configure these shared tool instances with any single user's credentials. The required credentials must be provided dynamically, on a per-request basis.

Proposed Solution

This PR solves this problem by introducing a third, invocation-time method for providing auth. It leverages LangChain's idiomatic RunnableConfig as the vehicle for passing request-specific authentication, making toolbox-langchain fully compatible with multi-tenant and shared-use patterns.

Description of Changes

The core of this change lies in how the ToolboxTool handles an invocation:

  • The tool's invocation method (_arun/_run) is updated to accept the config: RunnableConfig argument, which is standard in the LangChain.
  • The tool inspects the config for a specific key: config["configurable"]["auth_token_getters"].
  • If auth_token_getters are found in the config, the tool:
    a. Introspects its own authentication and authorization requirements (using the properties exposed in fix(toolbox-core): Expose authorization token requirements on ToolboxTool #294).
    b. Creates a temporary, in-memory copy of the underlying proxied ToolboxTool. This is critical, as it ensures the original shared tool instance is never mutated.
  • The auth_token_getters from the config are applied to this new, temporary copy of the tool using its add_auth_token_getters method.
  • The actual tool execution is performed using this temporary, request-specific authenticated tool instance.

This mechanism provides a thread-safe and secure way to handle user-specific credentials without affecting the shared state of the primary tool in the graph.

Usage Example

from langchain_core.runnables import RunnableConfig

# Define the per-invocation configuration with the user's token getter
config = RunnableConfig(
    configurable={
        "auth_token_getters": {
            "my-google-auth": lambda: "<TOKEN>"
        }
    }
)

...

result = await agent_executor.ainvoke(
    {"input": "Search for rows by my user ID"},
    config=config
)

@anubhav756
Copy link
Contributor Author

/gcbrun

@anubhav756 anubhav756 force-pushed the anubhav-self-auth-tools branch from 336b8d5 to 0f50eb0 Compare June 19, 2025 14:32
@anubhav756 anubhav756 marked this pull request as ready for review June 19, 2025 14:43
@anubhav756 anubhav756 requested a review from a team as a code owner June 19, 2025 14:43
@anubhav756 anubhav756 changed the title feat(toolbox-langchain): Implement self-authenticated tools feat(toolbox-langchain): Support per-invocation auth via RunnableConfig Jun 19, 2025
@twishabansal
Copy link
Contributor

In LangGraph, a single graph containing tool instances is often created once and then shared across multiple users and requests. It is insecure and impractical to configure these shared tool instances with any single user's credentials.

In this case, we expect users to use dynamic methods for fetching tokens like getGoogleIdToken.
Does the user need to hardcode any credentials?

@anubhav756 anubhav756 force-pushed the anubhav-self-auth-tools branch from e1fd6d1 to 22aa329 Compare June 23, 2025 17:44
@anubhav756
Copy link
Contributor Author

In LangGraph, a single graph containing tool instances is often created once and then shared across multiple users and requests. It is insecure and impractical to configure these shared tool instances with any single user's credentials.

In this case, we expect users to use dynamic methods for fetching tokens like getGoogleIdToken. Does the user need to hardcode any credentials?

Not necessarily in such a function like this one. For instance the app dev could fetch the user ID token from the frontend through a login button, and the app ID could be injected as an env var. Does that make sense?

@anubhav756 anubhav756 requested a review from twishabansal June 23, 2025 18:04
@anubhav756 anubhav756 force-pushed the anubhav-self-auth-tools branch from 09410c4 to f41566a Compare June 24, 2025 12:43
@anubhav756 anubhav756 force-pushed the anubhav-self-auth-tools branch 2 times, most recently from 57fd562 to 4e53bc0 Compare July 2, 2025 20:01
anubhav756 added a commit to GoogleCloudPlatform/genai-databases-retrieval-app that referenced this pull request Jul 3, 2025
* Remove client session management from the orchestration class
  * This is now managed by Toolbox SDK internally
* Simplify prompt creation
  * This is handled by the respective tools
* Tools descriptions, params, annotations, etc. are loaded from Toolbox
  * These are added through `bind_tools` from LangGraph
* This enables removal of the custom response message creation (which
was added as a `TODO`)
* Add logged in user's token to the `RunnableConfig`
* This is necessary so that the tools that require authentication can
read the user's token if available
* Simplify tools helper file by removing tools and helpers since those
are now handled by Toolbox SDK internally
* Add a Toolbox URL to connect to through integration tests
* Removes `ToolMessage` while inserting ticket.
  * This was causing an issue with `langchain-google-vertexai`

  ```
google.api_core.exceptions.InvalidArgument: 400 Please ensure that the
number of function response parts should be equal to number of function
call parts of the function call turn.
  ```
* Remove unused human and AI messages post book ticket flow.

## Diagram

![image](https://github.com/user-attachments/assets/46af0a74-3395-45a8-8ff4-f5466b034f17)

> [!IMPORTANT]
> This PR depends on a couple of features from Toolbox SDK:
> * Support for optional parameters
([#290](googleapis/mcp-toolbox-sdk-python#290))
> * Self-authenticated tools via `RunnableConfig`
([#291](googleapis/mcp-toolbox-sdk-python#291))

> [!NOTE]
> The failure in the integration test is expected. This PR is part of a
series of changes, and the corresponding fix for this test is in a
subsequent PR.
> ### Reasoning
> We've intentionally split the work into smaller, focused PRs to make
the review process more manageable and efficient.
> ### Merge Plan
> All related PRs will be merged into the `toolbox-main` branch first.
We will ensure all tests are passing on `toolbox-main` before merging
the entire feature set into `main`.
@anubhav756 anubhav756 force-pushed the anubhav-self-auth-tools branch from 4e53bc0 to 76c6fa4 Compare July 11, 2025 05:06
@anubhav756 anubhav756 force-pushed the anubhav-self-auth-tools branch from 76c6fa4 to 5607a2c Compare July 21, 2025 07:13
@anubhav756 anubhav756 force-pushed the anubhav-state-li branch 2 times, most recently from 35f5cf7 to dac36c5 Compare July 21, 2025 07:16
@anubhav756 anubhav756 force-pushed the anubhav-self-auth-tools branch from 5607a2c to 6f8cbfc Compare July 21, 2025 07:16
anubhav756 added a commit to GoogleCloudPlatform/genai-databases-retrieval-app that referenced this pull request Jul 23, 2025
This PR updates the existing workflow to replace the prebuilt tool node
with a new custom tool node. This new node is designed to intelligently
handle tool auth by reading auth headers from the provided
`RunnableConfig` by LangGraph.

The custom node inspects the auth requirements of the underlying core
tool within the `ToolboxTool`. If the tool requires authentication, the
node dynamically creates an authenticated copy of the tool by attaching
the necessary auth token getters using the `add_auth_token_getter` API.
This authenticated tool instance is then used for the call and
subsequently discarded. This same auth handling logic has also been
applied to the node responsible for ticket insertion.

> [!NOTE]
> The functionality introduced in these custom nodes will be abstracted
into the `ToolboxTool` itself in an upcoming release of the
`toolbox-langchain`
[#291](googleapis/mcp-toolbox-sdk-python#291).
This will simplify the workflow in the future by handling authentication
directly within the tool.
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.

2 participants