diff --git a/docs/docs/concepts/auth.md b/docs/docs/concepts/auth.md index 142c64124..ae7a1eb17 100644 --- a/docs/docs/concepts/auth.md +++ b/docs/docs/concepts/auth.md @@ -383,24 +383,24 @@ If a more specific handler is registered, the more general handler will not be c Here are all the supported action handlers: -| Resource | Handler | Description | -|----------|---------|-------------| -| **Threads** | `@auth.on.threads.create` | Thread creation | -| | `@auth.on.threads.read` | Thread retrieval | -| | `@auth.on.threads.update` | Thread updates | -| | `@auth.on.threads.delete` | Thread deletion | -| | `@auth.on.threads.search` | Listing threads | -| | `@auth.on.threads.create_run` | Creating or updating a run | -| **Assistants** | `@auth.on.assistants.create` | Assistant creation | -| | `@auth.on.assistants.read` | Assistant retrieval | -| | `@auth.on.assistants.update` | Assistant updates | -| | `@auth.on.assistants.delete` | Assistant deletion | -| | `@auth.on.assistants.search` | Listing assistants | -| **Crons** | `@auth.on.crons.create` | Cron job creation | -| | `@auth.on.crons.read` | Cron job retrieval | -| | `@auth.on.crons.update` | Cron job updates | -| | `@auth.on.crons.delete` | Cron job deletion | -| | `@auth.on.crons.search` | Listing cron jobs | +| Resource | Handler | Description | Value Type | +|----------|---------|-------------|------------| +| **Threads** | `@auth.on.threads.create` | Thread creation | [`ThreadsCreate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.ThreadsCreate) | +| | `@auth.on.threads.read` | Thread retrieval | [`ThreadsRead`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.ThreadsRead) | +| | `@auth.on.threads.update` | Thread updates | [`ThreadsUpdate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.ThreadsUpdate) | +| | `@auth.on.threads.delete` | Thread deletion | [`ThreadsDelete`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.ThreadsDelete) | +| | `@auth.on.threads.search` | Listing threads | [`ThreadsSearch`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.ThreadsSearch) | +| | `@auth.on.threads.create_run` | Creating or updating a run | [`RunsCreate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.RunsCreate) | +| **Assistants** | `@auth.on.assistants.create` | Assistant creation | [`AssistantsCreate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.AssistantsCreate) | +| | `@auth.on.assistants.read` | Assistant retrieval | [`AssistantsRead`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.AssistantsRead) | +| | `@auth.on.assistants.update` | Assistant updates | [`AssistantsUpdate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.AssistantsUpdate) | +| | `@auth.on.assistants.delete` | Assistant deletion | [`AssistantsDelete`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.AssistantsDelete) | +| | `@auth.on.assistants.search` | Listing assistants | [`AssistantsSearch`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.AssistantsSearch) | +| **Crons** | `@auth.on.crons.create` | Cron job creation | [`CronsCreate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.CronsCreate) | +| | `@auth.on.crons.read` | Cron job retrieval | [`CronsRead`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.CronsRead) | +| | `@auth.on.crons.update` | Cron job updates | [`CronsUpdate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.CronsUpdate) | +| | `@auth.on.crons.delete` | Cron job deletion | [`CronsDelete`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.CronsDelete) | +| | `@auth.on.crons.search` | Listing cron jobs | [`CronsSearch`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.CronsSearch) | ???+ note "About Runs" Runs are scoped to their parent thread for access control. This means permissions are typically inherited from the thread, reflecting the conversational nature of the data model. All run operations (reading, listing) except creation are controlled by the thread's handlers. diff --git a/docs/docs/tutorials/auth/resource_auth.md b/docs/docs/tutorials/auth/resource_auth.md index e62b88f60..ae1d08da4 100644 --- a/docs/docs/tutorials/auth/resource_auth.md +++ b/docs/docs/tutorials/auth/resource_auth.md @@ -68,7 +68,51 @@ async def add_owner( value: dict, # The resource being created/accessed ): """Make resources private to their creator.""" - # Add owner when creating resources + # Examples: + # ctx: AuthContext( + # permissions=[], + # user=ProxyUser( + # identity='user1', + # is_authenticated=True, + # display_name='user1' + # ), + # resource='threads', + # action='create_run' + # ) + # value: + # { + # 'thread_id': UUID('1e1b2733-303f-4dcd-9620-02d370287d72'), + # 'assistant_id': UUID('fe096781-5601-53d2-b2f6-0d3403f7e9ca'), + # 'run_id': UUID('1efbe268-1627-66d4-aa8d-b956b0f02a41'), + # 'status': 'pending', + # 'metadata': {}, + # 'prevent_insert_if_inflight': True, + # 'multitask_strategy': 'reject', + # 'if_not_exists': 'reject', + # 'after_seconds': 0, + # 'kwargs': { + # 'input': {'messages': [{'role': 'user', 'content': 'Hello!'}]}, + # 'command': None, + # 'config': { + # 'configurable': { + # 'langgraph_auth_user': ... Your user object... + # 'langgraph_auth_user_id': 'user1' + # } + # }, + # 'stream_mode': ['values'], + # 'interrupt_before': None, + # 'interrupt_after': None, + # 'webhook': None, + # 'feedback_keys': None, + # 'temporary': False, + # 'subgraphs': False + # } + # } + + # Do 2 things: + # 1. Add the user's ID to the resource's metadata. Each LangGraph resource has a `metadata` dict that persists with the resource. + # this metadata is useful for filtering in read and update operations + # 2. Return a filter that lets users only see their own resources filters = {"owner": ctx.user.identity} metadata = value.setdefault("metadata", {}) metadata.update(filters) @@ -182,11 +226,15 @@ async def on_thread_create( 1. Sets metadata on the thread being created to track ownership 2. Returns a filter that ensures only the creator can access it """ + # Example value: + # {'thread_id': UUID('99b045bc-b90b-41a8-b882-dabc541cf740'), 'metadata': {}, 'if_exists': 'raise'} + # Add owner metadata to the thread being created # This metadata is stored with the thread and persists metadata = value.setdefault("metadata", {}) metadata["owner"] = ctx.user.identity + # Return filter to restrict access to just the creator return {"owner": ctx.user.identity} @@ -210,6 +258,14 @@ async def on_assistants( ): # For illustration purposes, we will deny all requests # that touch the assistants resource + # Example value: + # { + # 'assistant_id': UUID('63ba56c3-b074-4212-96e2-cc333bbc4eb4'), + # 'graph_id': 'agent', + # 'config': {}, + # 'metadata': {}, + # 'name': 'Untitled' + # } raise Auth.exceptions.HTTPException( status_code=403, detail="User lacks the required permissions.",