Implement tool-level authorization by combining per-user authentication context with conditional tool filtering, either through middleware that strips unauthorized tools from the agent's toolset or through in-tool runtime checks that validate user permissions before execution.
Implementing tool-level authorization in LangChain/LangGraph involves two complementary strategies: you can either filter the toolset available to the agent at invocation time (so the agent never sees tools the user is not allowed to use), or you can pass user context into the tools and let each tool validate permissions at runtime. The recommended approach combines both: use context filtering to reduce the agent's decision space, and add in-tool authorization checks as a second line of defense to ensure security even if the agent attempts an unauthorized call.
The foundation of per-user authorization is passing user identity and permissions into your tools. LangChain provides the RunnableConfig object, which flows through the entire execution chain. You can attach user information to config.configurable and access it inside any tool function.
This pattern ensures that every tool call carries the user's identity. The tool itself checks the user's role or permissions before executing sensitive operations, returning an error message if the user is unauthorized. The LLM can then interpret this error and respond appropriately to the user.
For better efficiency and to prevent the agent from even attempting to use restricted tools, you can filter the toolset dynamically when building your agent. This approach reduces the agent's decision space and prevents wasted LLM calls on tools that would be denied anyway.
For LangGraph applications deployed on LangSmith, you can implement fine-grained resource authorization using the @auth.on decorator. This allows you to control access to specific resources like threads and assistants, scoping operations to the authenticated user.
Here's how a complete production flow integrates authentication and tool-level authorization, drawing from the Auth0 Zoo AI example. The pattern combines user authentication (via OAuth2) with per-tool permission checks.
In-Tool Checks: Most direct method—each tool inspects user role/permissions via RunnableConfig. Returns error messages for unauthorized users.
Pre-Filtering: Restrict toolset when creating the agent. Prevents agent from even seeing restricted tools. Most efficient.
LangGraph Resource Auth: Use @auth.on handlers for thread and store-level authorization. Best for multi-tenant apps.
OAuth 2.0 Delegation: Use Auth Code Flow + OBO Token Flow for agent actions on behalf of users. Essential for third-party APIs.
Fine-Grained Authorization (FGA): For complex permission relationships, consider OpenFGA/Auth0 FGA to model user-document relationships.
The recommended production pattern combines pre-filtering for efficiency and in-tool checks for security. Always assume the agent might attempt to call a restricted tool—never rely solely on pre-filtering as your only authorization mechanism, since the agent's behavior is non-deterministic and could theoretically attempt to reference a tool even if it's not provided.