auth0-ai-langchain 0.2.0__tar.gz → 1.0.0b2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of auth0-ai-langchain might be problematic. Click here for more details.

Files changed (30) hide show
  1. auth0_ai_langchain-1.0.0b2/PKG-INFO +352 -0
  2. auth0_ai_langchain-1.0.0b2/README.md +329 -0
  3. {auth0_ai_langchain-0.2.0 → auth0_ai_langchain-1.0.0b2}/auth0_ai_langchain/FGARetriever.py +3 -3
  4. auth0_ai_langchain-1.0.0b2/auth0_ai_langchain/auth0_ai.py +113 -0
  5. auth0_ai_langchain-1.0.0b2/auth0_ai_langchain/ciba/__init__.py +3 -0
  6. auth0_ai_langchain-1.0.0b2/auth0_ai_langchain/ciba/ciba_authorizer.py +17 -0
  7. auth0_ai_langchain-1.0.0b2/auth0_ai_langchain/ciba/graph_resumer.py +154 -0
  8. auth0_ai_langchain-1.0.0b2/auth0_ai_langchain/federated_connections/__init__.py +10 -0
  9. auth0_ai_langchain-1.0.0b2/auth0_ai_langchain/federated_connections/federated_connection_authorizer.py +33 -0
  10. auth0_ai_langchain-1.0.0b2/auth0_ai_langchain/fga/__init__.py +4 -0
  11. auth0_ai_langchain-1.0.0b2/auth0_ai_langchain/utils/interrupt.py +30 -0
  12. auth0_ai_langchain-1.0.0b2/auth0_ai_langchain/utils/tool_wrapper.py +34 -0
  13. {auth0_ai_langchain-0.2.0 → auth0_ai_langchain-1.0.0b2}/pyproject.toml +7 -7
  14. auth0_ai_langchain-0.2.0/PKG-INFO +0 -221
  15. auth0_ai_langchain-0.2.0/README.md +0 -198
  16. auth0_ai_langchain-0.2.0/auth0_ai_langchain/auth0_ai.py +0 -43
  17. auth0_ai_langchain-0.2.0/auth0_ai_langchain/ciba/__init__.py +0 -0
  18. auth0_ai_langchain-0.2.0/auth0_ai_langchain/ciba/ciba_graph/ciba_graph.py +0 -109
  19. auth0_ai_langchain-0.2.0/auth0_ai_langchain/ciba/ciba_graph/initialize_ciba.py +0 -91
  20. auth0_ai_langchain-0.2.0/auth0_ai_langchain/ciba/ciba_graph/initialize_hitl.py +0 -50
  21. auth0_ai_langchain-0.2.0/auth0_ai_langchain/ciba/ciba_graph/types.py +0 -115
  22. auth0_ai_langchain-0.2.0/auth0_ai_langchain/ciba/ciba_graph/utils.py +0 -17
  23. auth0_ai_langchain-0.2.0/auth0_ai_langchain/ciba/ciba_poller_graph.py +0 -105
  24. auth0_ai_langchain-0.2.0/auth0_ai_langchain/ciba/types.py +0 -8
  25. auth0_ai_langchain-0.2.0/auth0_ai_langchain/federated_connections/__init__.py +0 -4
  26. auth0_ai_langchain-0.2.0/auth0_ai_langchain/federated_connections/federated_connection_authorizer.py +0 -52
  27. auth0_ai_langchain-0.2.0/auth0_ai_langchain/fga/fga_authorizer.py +0 -3
  28. auth0_ai_langchain-0.2.0/auth0_ai_langchain/utils/interrupt.py +0 -13
  29. {auth0_ai_langchain-0.2.0 → auth0_ai_langchain-1.0.0b2}/LICENSE +0 -0
  30. {auth0_ai_langchain-0.2.0 → auth0_ai_langchain-1.0.0b2}/auth0_ai_langchain/__init__.py +0 -0
@@ -0,0 +1,352 @@
1
+ Metadata-Version: 2.3
2
+ Name: auth0-ai-langchain
3
+ Version: 1.0.0b2
4
+ Summary: This package is an SDK for building secure AI-powered applications using Auth0, Okta FGA and LangChain.
5
+ License: Apache-2.0
6
+ Author: Auth0
7
+ Author-email: support@auth0.com
8
+ Requires-Python: >=3.11,<4.0
9
+ Classifier: License :: OSI Approved :: Apache Software License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Requires-Dist: auth0-ai (>=1.0.0b2,<2.0.0)
15
+ Requires-Dist: langchain (>=0.3.25,<0.4.0)
16
+ Requires-Dist: langchain-core (>=0.3.59,<0.4.0)
17
+ Requires-Dist: langgraph (>=0.4.3,<0.5.0)
18
+ Requires-Dist: langgraph-sdk (>=0.1.66,<0.2.0)
19
+ Requires-Dist: openfga-sdk (>=0.9.4,<0.10.0)
20
+ Project-URL: Homepage, https://auth0.com
21
+ Description-Content-Type: text/markdown
22
+
23
+ # Auth0 AI for LangChain
24
+
25
+ `auth0-ai-langchain` is an SDK for building secure AI-powered applications using [Auth0](https://www.auth0.ai/), [Okta FGA](https://docs.fga.dev/) and [LangChain](https://python.langchain.com/docs/tutorials/).
26
+
27
+ ![Release](https://img.shields.io/pypi/v/auth0-ai-langchain) ![Downloads](https://img.shields.io/pypi/dw/auth0-ai-langchain) [![License](https://img.shields.io/:license-APACHE%202.0-blue.svg?style=flat)](https://opensource.org/license/apache-2-0)
28
+
29
+ ## Installation
30
+
31
+ > ⚠️ **WARNING**: `auth0-ai-langchain` is currently under development and it is not intended to be used in production, and therefore has no official support.
32
+
33
+ ```bash
34
+ pip install auth0-ai-langchain
35
+ ```
36
+
37
+ ## Async User Confirmation
38
+
39
+ `Auth0AI` uses CIBA (Client-Initiated Backchannel Authentication) to handle user confirmation asynchronously. This is useful when you need to confirm a user action before proceeding with a tool execution.
40
+
41
+ Full Example of [Async User Confirmation](https://github.com/auth0-lab/auth0-ai-python/tree/main/examples/async-user-confirmation/langchain-examples).
42
+
43
+ 1. Define a tool with the proper authorizer specifying a function to resolve the user id:
44
+
45
+ ```python
46
+ from auth0_ai_langchain.auth0_ai import Auth0AI
47
+ from auth0_ai_langchain.ciba import get_ciba_credentials
48
+ from langchain_core.runnables import ensure_config
49
+ from langchain_core.tools import StructuredTool
50
+
51
+ # If not provided, Auth0 settings will be read from env variables: `AUTH0_DOMAIN`, `AUTH0_CLIENT_ID`, and `AUTH0_CLIENT_SECRET`
52
+ auth0_ai = Auth0AI()
53
+
54
+ with_async_user_confirmation = auth0_ai.with_async_user_confirmation(
55
+ scopes=["stock:trade"],
56
+ audience=os.getenv("AUDIENCE"),
57
+ binding_message=lambda ticker, qty: f"Authorize the purchase of {qty} {ticker}",
58
+ user_id=lambda *_, **__: ensure_config().get("configurable", {}).get("user_id"),
59
+ # Optional:
60
+ # store=InMemoryStore()
61
+ )
62
+
63
+ def tool_function(ticker: str, qty: int) -> str:
64
+ credentials = get_ciba_credentials()
65
+ headers = {
66
+ "Authorization": f"{credentials["token_type"]} {credentials["access_token"]}",
67
+ # ...
68
+ }
69
+ # Call API
70
+
71
+ trade_tool = with_async_user_confirmation(
72
+ StructuredTool(
73
+ name="trade_tool",
74
+ description="Use this function to trade a stock",
75
+ func=trade_tool_function,
76
+ # ...
77
+ )
78
+ )
79
+ ```
80
+
81
+ 2. Handle interruptions properly. For example, if user is not enrolled to MFA, it will throw an interruption. See [Handling Interrupts](#handling-interrupts) section.
82
+
83
+ ### CIBA with RAR (Rich Authorization Requests)
84
+ `Auth0AI` supports RAR (Rich Authorization Requests) for CIBA. This allows you to provide additional authorization parameters to be displayed during the user confirmation request.
85
+
86
+ When defining the tool authorizer, you can specify the `authorization_details` parameter to include detailed information about the authorization being requested:
87
+
88
+ ```python
89
+ with_async_user_confirmation = auth0_ai.with_async_user_confirmation(
90
+ scopes=["stock:trade"],
91
+ audience=os.getenv("AUDIENCE"),
92
+ binding_message=lambda ticker, qty: f"Authorize the purchase of {qty} {ticker}",
93
+ authorization_details=lambda ticker, qty: [
94
+ {
95
+ "type": "trade_authorization",
96
+ "qty": qty,
97
+ "ticker": ticker,
98
+ "action": "buy"
99
+ }
100
+ ],
101
+ user_id=lambda *_, **__: ensure_config().get("configurable", {}).get("user_id"),
102
+ # Optional:
103
+ # store=InMemoryStore()
104
+ )
105
+ ```
106
+
107
+ To use RAR with CIBA, you need to [set up authorization details](https://auth0.com/docs/get-started/apis/configure-rich-authorization-requests) in your Auth0 tenant. This includes defining the authorization request parameters and their types. Additionally, the [Guardian SDK](https://auth0.com/docs/secure/multi-factor-authentication/auth0-guardian) is required to handle these authorization details in your authorizer app.
108
+
109
+ For more information on setting up RAR with CIBA, refer to:
110
+ - [Configure Rich Authorization Requests (RAR)](https://auth0.com/docs/get-started/apis/configure-rich-authorization-requests)
111
+ - [User Authorization with CIBA](https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/user-authorization-with-ciba)
112
+
113
+ ## Authorization for Tools
114
+
115
+ The `FGAAuthorizer` can leverage Okta FGA to authorize tools executions. The `FGAAuthorizer.create` function can be used to create an authorizer that checks permissions before executing the tool.
116
+
117
+ Full example of [Authorization for Tools](https://github.com/auth0-lab/auth0-ai-python/tree/main/examples/authorization-for-tools/langchain-examples).
118
+
119
+ 1. Create an instance of FGA Authorizer:
120
+
121
+ ```python
122
+ from auth0_ai_langchain.fga import FGAAuthorizer
123
+
124
+ # If not provided, FGA settings will be read from env variables: `FGA_STORE_ID`, `FGA_CLIENT_ID`, `FGA_CLIENT_SECRET`, etc.
125
+ fga = FGAAuthorizer.create()
126
+ ```
127
+
128
+ 2. Define the FGA query (`build_query`) and, optionally, the `on_unauthorized` handler:
129
+
130
+ ```python
131
+ from langchain_core.runnables import ensure_config
132
+
133
+ async def build_fga_query(tool_input):
134
+ user_id = ensure_config().get("configurable",{}).get("user_id")
135
+ return {
136
+ "user": f"user:{user_id}",
137
+ "object": f"asset:{tool_input["ticker"]}",
138
+ "relation": "can_buy",
139
+ "context": {"current_time": datetime.now(timezone.utc).isoformat()}
140
+ }
141
+
142
+ def on_unauthorized(tool_input):
143
+ return f"The user is not allowed to buy {tool_input["qty"]} shares of {tool_input["ticker"]}."
144
+
145
+ use_fga = fga(
146
+ build_query=build_fga_query,
147
+ on_unauthorized=on_unauthorized,
148
+ )
149
+ ```
150
+
151
+ **Note**: The parameters given to the `build_query` and `on_unauthorized` functions are the same as those provided to the tool function.
152
+
153
+ 3. Wrap the tool:
154
+
155
+ ```python
156
+ from langchain_core.tools import StructuredTool
157
+
158
+ async def buy_tool_function(ticker: str, qty: int) -> str:
159
+ # TODO: implement buy operation
160
+ return f"Purchased {qty} shares of {ticker}"
161
+
162
+ func=use_fga(buy_tool_function)
163
+
164
+ buy_tool = StructuredTool(
165
+ func=func,
166
+ coroutine=func,
167
+ name="buy",
168
+ description="Use this function to buy stocks",
169
+ )
170
+ ```
171
+
172
+ ## Calling APIs On User's Behalf
173
+
174
+ The `Auth0AI.with_federated_connection` function exchanges user's refresh token taken, by default, from the runnable configuration (`config.configurable._credentials.refresh_token`) for a Federated Connection API token.
175
+
176
+ Full Example of [Calling APIs On User's Behalf](https://github.com/auth0-lab/auth0-ai-python/tree/main/examples/calling-apis/langchain-examples).
177
+
178
+ 1. Define a tool with the proper authorizer:
179
+
180
+ ```python
181
+ from auth0_ai_langchain.auth0_ai import Auth0AI
182
+ from auth0_ai_langchain.federated_connections import get_credentials_for_connection
183
+ from langchain_core.tools import StructuredTool
184
+
185
+ # If not provided, Auth0 settings will be read from env variables: `AUTH0_DOMAIN`, `AUTH0_CLIENT_ID`, and `AUTH0_CLIENT_SECRET`
186
+ auth0_ai = Auth0AI()
187
+
188
+ with_google_calendar_access = auth0_ai.with_federated_connection(
189
+ connection="google-oauth2",
190
+ scopes=["https://www.googleapis.com/auth/calendar.freebusy"],
191
+ # Optional:
192
+ # refresh_token=lambda *_, **__: ensure_config().get("configurable", {}).get("_credentials", {}).get("refresh_token"),
193
+ # store=InMemoryStore(),
194
+ )
195
+
196
+ def tool_function(date: datetime):
197
+ credentials = get_credentials_for_connection()
198
+ # Call Google API using credentials["access_token"]
199
+
200
+ check_calendar_tool = with_google_calendar_access(
201
+ StructuredTool(
202
+ name="check_user_calendar",
203
+ description="Use this function to check if the user is available on a certain date and time",
204
+ func=tool_function,
205
+ # ...
206
+ )
207
+ )
208
+ ```
209
+
210
+ 2. Add a node to your graph for your tools:
211
+
212
+ ```python
213
+ workflow = (
214
+ StateGraph(State)
215
+ .add_node(
216
+ "tools",
217
+ ToolNode(
218
+ [
219
+ check_calendar_tool,
220
+ # ...
221
+ ],
222
+ # The error handler should be disabled to allow interruptions to be triggered from within tools.
223
+ handle_tool_errors=False
224
+ )
225
+ )
226
+ # ...
227
+ )
228
+ ```
229
+
230
+ 3. Handle interruptions properly. For example, if the tool does not have access to user's Google Calendar, it will throw an interruption. See [Handling Interrupts](#handling-interrupts) section.
231
+
232
+ ## RAG with FGA
233
+
234
+ The `FGARetriever` can be used to filter documents based on access control checks defined in Okta FGA. This retriever performs batch checks on retrieved documents, returning only the ones that pass the specified access criteria.
235
+
236
+ Full Example of [RAG Application](https://github.com/auth0-lab/auth0-ai-python/tree/main/examples/authorization-for-rag/langchain-examples).
237
+
238
+ Create a retriever instance using the `FGARetriever` class.
239
+
240
+ ```python
241
+ from langchain.vectorstores import VectorStoreIndex
242
+ from langchain.schema import Document
243
+ from auth0_ai_langchain import FGARetriever
244
+ from openfga_sdk.client.models import ClientCheckRequest
245
+ from openfga_sdk import ClientConfiguration
246
+ from openfga_sdk.credentials import CredentialConfiguration, Credentials
247
+
248
+ # Define some docs:
249
+ documents = [
250
+ Document(page_content="This is a public doc", metadata={"doc_id": "public-doc"}),
251
+ Document(page_content="This is a private doc", metadata={"doc_id": "private-doc"}),
252
+ ]
253
+
254
+ # Create a vector store:
255
+ vector_store = VectorStoreIndex.from_documents(documents)
256
+
257
+ # Create a retriever:
258
+ base_retriever = vector_store.as_retriever()
259
+
260
+ # Create the FGA retriever wrapper.
261
+ # If not provided, FGA settings will be read from env variables: `FGA_STORE_ID`, `FGA_CLIENT_ID`, `FGA_CLIENT_SECRET`, etc.
262
+ retriever = FGARetriever(
263
+ base_retriever,
264
+ build_query=lambda node: ClientCheckRequest(
265
+ user=f'user:{user}',
266
+ object=f'doc:{node.metadata["doc_id"]}',
267
+ relation="viewer",
268
+ )
269
+ )
270
+
271
+ # Create a query engine:
272
+ query_engine = RetrieverQueryEngine.from_args(
273
+ retriever=retriever,
274
+ llm=OpenAI()
275
+ )
276
+
277
+ # Query:
278
+ response = query_engine.query("What is the forecast for ZEKO?")
279
+
280
+ print(response)
281
+ ```
282
+
283
+ ## Handling Interrupts
284
+
285
+ `Auth0AI` uses interrupts extensively and will never block a graph. Whenever an authorizer requires user interaction, the graph throws a `GraphInterrupt` exception with data that allows the client to resume the flow.
286
+
287
+ It is important to disable error handling in your tools node as follows:
288
+
289
+ ```python
290
+ .add_node(
291
+ "tools",
292
+ ToolNode(
293
+ [
294
+ # your authorizer-wrapped tools
295
+ ],
296
+ # Error handler should be disabled in order to trigger interruptions from within tools.
297
+ handle_tool_errors=False
298
+ )
299
+ )
300
+ ```
301
+
302
+ From the client side of the graph you get the interrupts:
303
+
304
+ ```python
305
+ from auth0_ai_langchain.utils.interrupt import get_auth0_interrupts
306
+
307
+ # Get the langgraph thread:
308
+ thread = await client.threads.get(thread_id)
309
+
310
+ # Filter the auth0 interrupts:
311
+ auth0_interrupts = get_auth0_interrupts(thread)
312
+ ```
313
+
314
+ Then you can resume the thread by doing this:
315
+
316
+ ```python
317
+ await client.runs.wait(thread_id, assistant_id)
318
+ ```
319
+
320
+ For the specific case of **CIBA (Client-Initiated Backchannel Authorization)** you might attach a `GraphResumer` instance that watches for interrupted threads in the `"Authorization Pending"` state and attempts to resume them automatically, respecting Auth0's polling interval.
321
+
322
+ ```python
323
+ import os
324
+ from auth0_ai_langchain.ciba import GraphResumer
325
+ from langgraph_sdk import get_client
326
+
327
+ resumer = GraphResumer(
328
+ lang_graph=get_client(url=os.getenv("LANGGRAPH_API_URL")),
329
+ # optionally, you can filter by a specific graph:
330
+ filters={"graph_id": "conditional-trade"},
331
+ )
332
+
333
+ resumer \
334
+ .on_resume(lambda thread: print(f"Attempting to resume thread {thread['thread_id']} from interruption {thread['interruption_id']}")) \
335
+ .on_error(lambda err: print(f"Error in GraphResumer: {str(err)}"))
336
+
337
+ resumer.start()
338
+ ```
339
+
340
+ ---
341
+
342
+ <p align="center">
343
+ <picture>
344
+ <source media="(prefers-color-scheme: light)" srcset="https://cdn.auth0.com/website/sdks/logos/auth0_light_mode.png" width="150">
345
+ <source media="(prefers-color-scheme: dark)" srcset="https://cdn.auth0.com/website/sdks/logos/auth0_dark_mode.png" width="150">
346
+ <img alt="Auth0 Logo" src="https://cdn.auth0.com/website/sdks/logos/auth0_light_mode.png" width="150">
347
+ </picture>
348
+ </p>
349
+ <p align="center">Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout <a href="https://auth0.com/why-auth0">Why Auth0?</a></p>
350
+ <p align="center">
351
+ This project is licensed under the Apache 2.0 license. See the <a href="https://github.com/auth0-lab/auth0-ai-python/blob/main/LICENSE"> LICENSE</a> file for more info.</p>
352
+
@@ -0,0 +1,329 @@
1
+ # Auth0 AI for LangChain
2
+
3
+ `auth0-ai-langchain` is an SDK for building secure AI-powered applications using [Auth0](https://www.auth0.ai/), [Okta FGA](https://docs.fga.dev/) and [LangChain](https://python.langchain.com/docs/tutorials/).
4
+
5
+ ![Release](https://img.shields.io/pypi/v/auth0-ai-langchain) ![Downloads](https://img.shields.io/pypi/dw/auth0-ai-langchain) [![License](https://img.shields.io/:license-APACHE%202.0-blue.svg?style=flat)](https://opensource.org/license/apache-2-0)
6
+
7
+ ## Installation
8
+
9
+ > ⚠️ **WARNING**: `auth0-ai-langchain` is currently under development and it is not intended to be used in production, and therefore has no official support.
10
+
11
+ ```bash
12
+ pip install auth0-ai-langchain
13
+ ```
14
+
15
+ ## Async User Confirmation
16
+
17
+ `Auth0AI` uses CIBA (Client-Initiated Backchannel Authentication) to handle user confirmation asynchronously. This is useful when you need to confirm a user action before proceeding with a tool execution.
18
+
19
+ Full Example of [Async User Confirmation](https://github.com/auth0-lab/auth0-ai-python/tree/main/examples/async-user-confirmation/langchain-examples).
20
+
21
+ 1. Define a tool with the proper authorizer specifying a function to resolve the user id:
22
+
23
+ ```python
24
+ from auth0_ai_langchain.auth0_ai import Auth0AI
25
+ from auth0_ai_langchain.ciba import get_ciba_credentials
26
+ from langchain_core.runnables import ensure_config
27
+ from langchain_core.tools import StructuredTool
28
+
29
+ # If not provided, Auth0 settings will be read from env variables: `AUTH0_DOMAIN`, `AUTH0_CLIENT_ID`, and `AUTH0_CLIENT_SECRET`
30
+ auth0_ai = Auth0AI()
31
+
32
+ with_async_user_confirmation = auth0_ai.with_async_user_confirmation(
33
+ scopes=["stock:trade"],
34
+ audience=os.getenv("AUDIENCE"),
35
+ binding_message=lambda ticker, qty: f"Authorize the purchase of {qty} {ticker}",
36
+ user_id=lambda *_, **__: ensure_config().get("configurable", {}).get("user_id"),
37
+ # Optional:
38
+ # store=InMemoryStore()
39
+ )
40
+
41
+ def tool_function(ticker: str, qty: int) -> str:
42
+ credentials = get_ciba_credentials()
43
+ headers = {
44
+ "Authorization": f"{credentials["token_type"]} {credentials["access_token"]}",
45
+ # ...
46
+ }
47
+ # Call API
48
+
49
+ trade_tool = with_async_user_confirmation(
50
+ StructuredTool(
51
+ name="trade_tool",
52
+ description="Use this function to trade a stock",
53
+ func=trade_tool_function,
54
+ # ...
55
+ )
56
+ )
57
+ ```
58
+
59
+ 2. Handle interruptions properly. For example, if user is not enrolled to MFA, it will throw an interruption. See [Handling Interrupts](#handling-interrupts) section.
60
+
61
+ ### CIBA with RAR (Rich Authorization Requests)
62
+ `Auth0AI` supports RAR (Rich Authorization Requests) for CIBA. This allows you to provide additional authorization parameters to be displayed during the user confirmation request.
63
+
64
+ When defining the tool authorizer, you can specify the `authorization_details` parameter to include detailed information about the authorization being requested:
65
+
66
+ ```python
67
+ with_async_user_confirmation = auth0_ai.with_async_user_confirmation(
68
+ scopes=["stock:trade"],
69
+ audience=os.getenv("AUDIENCE"),
70
+ binding_message=lambda ticker, qty: f"Authorize the purchase of {qty} {ticker}",
71
+ authorization_details=lambda ticker, qty: [
72
+ {
73
+ "type": "trade_authorization",
74
+ "qty": qty,
75
+ "ticker": ticker,
76
+ "action": "buy"
77
+ }
78
+ ],
79
+ user_id=lambda *_, **__: ensure_config().get("configurable", {}).get("user_id"),
80
+ # Optional:
81
+ # store=InMemoryStore()
82
+ )
83
+ ```
84
+
85
+ To use RAR with CIBA, you need to [set up authorization details](https://auth0.com/docs/get-started/apis/configure-rich-authorization-requests) in your Auth0 tenant. This includes defining the authorization request parameters and their types. Additionally, the [Guardian SDK](https://auth0.com/docs/secure/multi-factor-authentication/auth0-guardian) is required to handle these authorization details in your authorizer app.
86
+
87
+ For more information on setting up RAR with CIBA, refer to:
88
+ - [Configure Rich Authorization Requests (RAR)](https://auth0.com/docs/get-started/apis/configure-rich-authorization-requests)
89
+ - [User Authorization with CIBA](https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/user-authorization-with-ciba)
90
+
91
+ ## Authorization for Tools
92
+
93
+ The `FGAAuthorizer` can leverage Okta FGA to authorize tools executions. The `FGAAuthorizer.create` function can be used to create an authorizer that checks permissions before executing the tool.
94
+
95
+ Full example of [Authorization for Tools](https://github.com/auth0-lab/auth0-ai-python/tree/main/examples/authorization-for-tools/langchain-examples).
96
+
97
+ 1. Create an instance of FGA Authorizer:
98
+
99
+ ```python
100
+ from auth0_ai_langchain.fga import FGAAuthorizer
101
+
102
+ # If not provided, FGA settings will be read from env variables: `FGA_STORE_ID`, `FGA_CLIENT_ID`, `FGA_CLIENT_SECRET`, etc.
103
+ fga = FGAAuthorizer.create()
104
+ ```
105
+
106
+ 2. Define the FGA query (`build_query`) and, optionally, the `on_unauthorized` handler:
107
+
108
+ ```python
109
+ from langchain_core.runnables import ensure_config
110
+
111
+ async def build_fga_query(tool_input):
112
+ user_id = ensure_config().get("configurable",{}).get("user_id")
113
+ return {
114
+ "user": f"user:{user_id}",
115
+ "object": f"asset:{tool_input["ticker"]}",
116
+ "relation": "can_buy",
117
+ "context": {"current_time": datetime.now(timezone.utc).isoformat()}
118
+ }
119
+
120
+ def on_unauthorized(tool_input):
121
+ return f"The user is not allowed to buy {tool_input["qty"]} shares of {tool_input["ticker"]}."
122
+
123
+ use_fga = fga(
124
+ build_query=build_fga_query,
125
+ on_unauthorized=on_unauthorized,
126
+ )
127
+ ```
128
+
129
+ **Note**: The parameters given to the `build_query` and `on_unauthorized` functions are the same as those provided to the tool function.
130
+
131
+ 3. Wrap the tool:
132
+
133
+ ```python
134
+ from langchain_core.tools import StructuredTool
135
+
136
+ async def buy_tool_function(ticker: str, qty: int) -> str:
137
+ # TODO: implement buy operation
138
+ return f"Purchased {qty} shares of {ticker}"
139
+
140
+ func=use_fga(buy_tool_function)
141
+
142
+ buy_tool = StructuredTool(
143
+ func=func,
144
+ coroutine=func,
145
+ name="buy",
146
+ description="Use this function to buy stocks",
147
+ )
148
+ ```
149
+
150
+ ## Calling APIs On User's Behalf
151
+
152
+ The `Auth0AI.with_federated_connection` function exchanges user's refresh token taken, by default, from the runnable configuration (`config.configurable._credentials.refresh_token`) for a Federated Connection API token.
153
+
154
+ Full Example of [Calling APIs On User's Behalf](https://github.com/auth0-lab/auth0-ai-python/tree/main/examples/calling-apis/langchain-examples).
155
+
156
+ 1. Define a tool with the proper authorizer:
157
+
158
+ ```python
159
+ from auth0_ai_langchain.auth0_ai import Auth0AI
160
+ from auth0_ai_langchain.federated_connections import get_credentials_for_connection
161
+ from langchain_core.tools import StructuredTool
162
+
163
+ # If not provided, Auth0 settings will be read from env variables: `AUTH0_DOMAIN`, `AUTH0_CLIENT_ID`, and `AUTH0_CLIENT_SECRET`
164
+ auth0_ai = Auth0AI()
165
+
166
+ with_google_calendar_access = auth0_ai.with_federated_connection(
167
+ connection="google-oauth2",
168
+ scopes=["https://www.googleapis.com/auth/calendar.freebusy"],
169
+ # Optional:
170
+ # refresh_token=lambda *_, **__: ensure_config().get("configurable", {}).get("_credentials", {}).get("refresh_token"),
171
+ # store=InMemoryStore(),
172
+ )
173
+
174
+ def tool_function(date: datetime):
175
+ credentials = get_credentials_for_connection()
176
+ # Call Google API using credentials["access_token"]
177
+
178
+ check_calendar_tool = with_google_calendar_access(
179
+ StructuredTool(
180
+ name="check_user_calendar",
181
+ description="Use this function to check if the user is available on a certain date and time",
182
+ func=tool_function,
183
+ # ...
184
+ )
185
+ )
186
+ ```
187
+
188
+ 2. Add a node to your graph for your tools:
189
+
190
+ ```python
191
+ workflow = (
192
+ StateGraph(State)
193
+ .add_node(
194
+ "tools",
195
+ ToolNode(
196
+ [
197
+ check_calendar_tool,
198
+ # ...
199
+ ],
200
+ # The error handler should be disabled to allow interruptions to be triggered from within tools.
201
+ handle_tool_errors=False
202
+ )
203
+ )
204
+ # ...
205
+ )
206
+ ```
207
+
208
+ 3. Handle interruptions properly. For example, if the tool does not have access to user's Google Calendar, it will throw an interruption. See [Handling Interrupts](#handling-interrupts) section.
209
+
210
+ ## RAG with FGA
211
+
212
+ The `FGARetriever` can be used to filter documents based on access control checks defined in Okta FGA. This retriever performs batch checks on retrieved documents, returning only the ones that pass the specified access criteria.
213
+
214
+ Full Example of [RAG Application](https://github.com/auth0-lab/auth0-ai-python/tree/main/examples/authorization-for-rag/langchain-examples).
215
+
216
+ Create a retriever instance using the `FGARetriever` class.
217
+
218
+ ```python
219
+ from langchain.vectorstores import VectorStoreIndex
220
+ from langchain.schema import Document
221
+ from auth0_ai_langchain import FGARetriever
222
+ from openfga_sdk.client.models import ClientCheckRequest
223
+ from openfga_sdk import ClientConfiguration
224
+ from openfga_sdk.credentials import CredentialConfiguration, Credentials
225
+
226
+ # Define some docs:
227
+ documents = [
228
+ Document(page_content="This is a public doc", metadata={"doc_id": "public-doc"}),
229
+ Document(page_content="This is a private doc", metadata={"doc_id": "private-doc"}),
230
+ ]
231
+
232
+ # Create a vector store:
233
+ vector_store = VectorStoreIndex.from_documents(documents)
234
+
235
+ # Create a retriever:
236
+ base_retriever = vector_store.as_retriever()
237
+
238
+ # Create the FGA retriever wrapper.
239
+ # If not provided, FGA settings will be read from env variables: `FGA_STORE_ID`, `FGA_CLIENT_ID`, `FGA_CLIENT_SECRET`, etc.
240
+ retriever = FGARetriever(
241
+ base_retriever,
242
+ build_query=lambda node: ClientCheckRequest(
243
+ user=f'user:{user}',
244
+ object=f'doc:{node.metadata["doc_id"]}',
245
+ relation="viewer",
246
+ )
247
+ )
248
+
249
+ # Create a query engine:
250
+ query_engine = RetrieverQueryEngine.from_args(
251
+ retriever=retriever,
252
+ llm=OpenAI()
253
+ )
254
+
255
+ # Query:
256
+ response = query_engine.query("What is the forecast for ZEKO?")
257
+
258
+ print(response)
259
+ ```
260
+
261
+ ## Handling Interrupts
262
+
263
+ `Auth0AI` uses interrupts extensively and will never block a graph. Whenever an authorizer requires user interaction, the graph throws a `GraphInterrupt` exception with data that allows the client to resume the flow.
264
+
265
+ It is important to disable error handling in your tools node as follows:
266
+
267
+ ```python
268
+ .add_node(
269
+ "tools",
270
+ ToolNode(
271
+ [
272
+ # your authorizer-wrapped tools
273
+ ],
274
+ # Error handler should be disabled in order to trigger interruptions from within tools.
275
+ handle_tool_errors=False
276
+ )
277
+ )
278
+ ```
279
+
280
+ From the client side of the graph you get the interrupts:
281
+
282
+ ```python
283
+ from auth0_ai_langchain.utils.interrupt import get_auth0_interrupts
284
+
285
+ # Get the langgraph thread:
286
+ thread = await client.threads.get(thread_id)
287
+
288
+ # Filter the auth0 interrupts:
289
+ auth0_interrupts = get_auth0_interrupts(thread)
290
+ ```
291
+
292
+ Then you can resume the thread by doing this:
293
+
294
+ ```python
295
+ await client.runs.wait(thread_id, assistant_id)
296
+ ```
297
+
298
+ For the specific case of **CIBA (Client-Initiated Backchannel Authorization)** you might attach a `GraphResumer` instance that watches for interrupted threads in the `"Authorization Pending"` state and attempts to resume them automatically, respecting Auth0's polling interval.
299
+
300
+ ```python
301
+ import os
302
+ from auth0_ai_langchain.ciba import GraphResumer
303
+ from langgraph_sdk import get_client
304
+
305
+ resumer = GraphResumer(
306
+ lang_graph=get_client(url=os.getenv("LANGGRAPH_API_URL")),
307
+ # optionally, you can filter by a specific graph:
308
+ filters={"graph_id": "conditional-trade"},
309
+ )
310
+
311
+ resumer \
312
+ .on_resume(lambda thread: print(f"Attempting to resume thread {thread['thread_id']} from interruption {thread['interruption_id']}")) \
313
+ .on_error(lambda err: print(f"Error in GraphResumer: {str(err)}"))
314
+
315
+ resumer.start()
316
+ ```
317
+
318
+ ---
319
+
320
+ <p align="center">
321
+ <picture>
322
+ <source media="(prefers-color-scheme: light)" srcset="https://cdn.auth0.com/website/sdks/logos/auth0_light_mode.png" width="150">
323
+ <source media="(prefers-color-scheme: dark)" srcset="https://cdn.auth0.com/website/sdks/logos/auth0_dark_mode.png" width="150">
324
+ <img alt="Auth0 Logo" src="https://cdn.auth0.com/website/sdks/logos/auth0_light_mode.png" width="150">
325
+ </picture>
326
+ </p>
327
+ <p align="center">Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout <a href="https://auth0.com/why-auth0">Why Auth0?</a></p>
328
+ <p align="center">
329
+ This project is licensed under the Apache 2.0 license. See the <a href="https://github.com/auth0-lab/auth0-ai-python/blob/main/LICENSE"> LICENSE</a> file for more info.</p>