diff --git a/docs/_scripts/notebook_hooks.py b/docs/_scripts/notebook_hooks.py index 23c460e7a..c993b6d22 100644 --- a/docs/_scripts/notebook_hooks.py +++ b/docs/_scripts/notebook_hooks.py @@ -1,4 +1,5 @@ import logging +import os from typing import Any, Dict from mkdocs.structure.pages import Page @@ -8,6 +9,7 @@ logger = logging.getLogger(__name__) logging.basicConfig() logger.setLevel(logging.INFO) +DISABLED = os.getenv("DISABLE_NOTEBOOK_CONVERT") in ("1", "true", "True") class NotebookFile(File): @@ -16,6 +18,8 @@ def is_documentation_page(self): def on_files(files: Files, **kwargs: Dict[str, Any]): + if DISABLED: + return files new_files = Files([]) for file in files: if file.src_path.endswith(".ipynb"): @@ -32,6 +36,8 @@ def on_files(files: Files, **kwargs: Dict[str, Any]): def on_page_markdown(markdown: str, page: Page, **kwargs: Dict[str, Any]): + if DISABLED: + return markdown if page.file.src_path.endswith(".ipynb"): logger.info("Processing Jupyter notebook: %s", page.file.src_path) body = convert_notebook(page.file.abs_src_path) diff --git a/docs/docs/cloud/reference/cli.md b/docs/docs/cloud/reference/cli.md index 72599e7fc..1daff19ee 100644 --- a/docs/docs/cloud/reference/cli.md +++ b/docs/docs/cloud/reference/cli.md @@ -21,7 +21,7 @@ The LangGraph command line interface includes commands to build and run a LangGr [](){#langgraph.json} -## Configuration File +## Configuration File {#configuration-file} The LangGraph CLI requires a JSON configuration file with the following keys: diff --git a/docs/docs/concepts/auth.md b/docs/docs/concepts/auth.md index c14135c93..ce0617cb9 100644 --- a/docs/docs/concepts/auth.md +++ b/docs/docs/concepts/auth.md @@ -23,23 +23,24 @@ A typical authentication setup involves three main components: 1. **Authentication Provider** (Identity Provider/IdP) - - A dedicated service that manages user identities and credentials - - Examples: Auth0, Supabase Auth, Okta, or your own auth server - - Handles user registration, login, password resets, etc. - - Issues tokens (JWT, session tokens, etc.) after successful authentication + * A dedicated service that manages user identities and credentials + * Handles user registration, login, password resets, etc. + * Issues tokens (JWT, session tokens, etc.) after successful authentication + * Examples: Auth0, Supabase Auth, Okta, or your own auth server 2. **LangGraph Backend** (Resource Server) - - Your LangGraph application that contains business logic and protected resources - - Validates tokens with the auth provider - - Enforces access control based on user identity and permissions - - Never stores user credentials directly + * Your LangGraph application that contains business logic and protected resources + * Validates tokens with the auth provider + * Enforces access control based on user identity and permissions + * Doesn't store user credentials directly 3. **Client Application** (Frontend) - - Web app, mobile app, or API client - - Collects user credentials and sends to auth provider - - Receives tokens from auth provider - - Includes tokens in requests to LangGraph backend + + * Web app, mobile app, or API client + * Collects time-sensitive user credentials and sends to auth provider + * Receives tokens from auth provider + * Includes these tokens in requests to LangGraph backend Here's how these components typically interact: @@ -58,15 +59,15 @@ sequenceDiagram LG-->>Client: 7. Return resources ``` -Your `@auth.authenticate` handler in LangGraph handles steps 4-5, while your `@auth.on` handlers implement step 6. +Your [`@auth.authenticate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.authenticate) handler in LangGraph handles steps 4-5, while your [`@auth.on`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.on) handlers implement step 6. ## Authentication -Authentication in LangGraph runs as middleware on every request. Your `@auth.authenticate` handler receives request information and must: +Authentication in LangGraph runs as middleware on every request. Your [`@auth.authenticate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.authenticate) handler receives request information and should: 1. Validate the credentials 2. Return user information if valid -3. Raise an HTTP exception if invalid (or AssertionError) +3. Raise an HTTP exception or AssertionError if invalid ```python from langgraph_sdk import Auth @@ -98,12 +99,12 @@ async def authenticate(headers: dict) -> Auth.types.MinimalUserDict: The returned user information is available: -- To your authorization handlers via `ctx.user` +- To your authorization handlers via [`ctx.user`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.AuthContext) - In your application via `config["configuration"]["langgraph_auth_user"]` ## Authorization -After authentication, LangGraph calls your `@auth.on` handlers to control access to specific resources (e.g., threads, assistants, crons). These handlers can: +After authentication, LangGraph calls your [`@auth.on`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.on) handlers to control access to specific resources (e.g., threads, assistants, crons). These handlers can: 1. Add metadata to be saved during resource creation by mutating the `value["metadata"]` dictionary directly. 2. Filter resources by metadata during search/list or read operations by returning a [filter dictionary](#filter-operations). diff --git a/docs/docs/tutorials/auth/getting_started.md b/docs/docs/tutorials/auth/getting_started.md index 0679f304a..c8df6592d 100644 --- a/docs/docs/tutorials/auth/getting_started.md +++ b/docs/docs/tutorials/auth/getting_started.md @@ -31,6 +31,7 @@ If everything works, the server should start and open the studio in your browser > > This in-memory server is designed for development and testing. > For production use, please use LangGraph Cloud. + Now that we've seen the base LangGraph app, let's add authentication to it! In part 1, we will start with a hard-coded token for illustration purposes. We will get to a "production-ready" authentication scheme in part 3, after mastering the basics. @@ -49,9 +50,12 @@ VALID_TOKENS = { "user2-token": {"id": "user2", "name": "Bob"}, } +# The "Auth" object is a container that LangGraph will use to mark our authentication function auth = Auth() +# The `authenticate` decorator tells LangGraph to call this function as middleware +# for every request. This will determine whether the request is allowed or not @auth.authenticate async def get_current_user(authorization: str | None) -> Auth.types.MinimalUserDict: """Check if the user's token is valid.""" @@ -69,12 +73,12 @@ async def get_current_user(authorization: str | None) -> Auth.types.MinimalUserD } ``` -Notice that our authentication handler does two important things: +Notice that our [authentication](../../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.authenticate) handler does two important things: -1. Checks if a valid token is provided -2. Returns the user's identity +1. Checks if a valid token is provided in the request's [Authorization header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) +2. Returns the user's [identity](../../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.MinimalUserDict) -Now tell LangGraph to use our authentication by adding the following to the `langgraph.json` configuration: +Now tell LangGraph to use our authentication by adding the following to the [`langgraph.json`](../../cloud/reference/cli.md#configuration-file) configuration: ```json { @@ -137,14 +141,16 @@ print(response) ``` You should see that: + 1. Without a valid token, we can't access the bot 2. With a valid token, we can create threads and chat -Congratulations! You've built a chatbot that only lets "authorized" users access it. While this system doesn't (yet) implement a production-ready security scheme, we've learned the basic mechanics of how to control access to our bot. In the next tutorial, we'll learn how to give each user their own private conversations. +Congratulations! You've built a chatbot that only lets "authenticated" users access it. While this system doesn't (yet) implement a production-ready security scheme, we've learned the basic mechanics of how to control access to our bot. In the next tutorial, we'll learn how to give each user their own private conversations. ## What's Next? Now that you can control who accesses your bot, you might want to: -1. Move on to [Resource Authorization](resource_auth.md) to learn how to make conversations private -2. Read more about [authentication concepts](../../concepts/auth.md) -3. Check out the [API reference](../../cloud/reference/sdk/python_sdk_ref.md) for more authentication options \ No newline at end of file + +1. Continue the tutorial by going to [Making Conversations Private (Part 2/3)](resource_auth.md) to learn about resource authorization. +2. Read more about [authentication concepts](../../concepts/auth.md). +3. Check out the [API reference](../../cloud/reference/sdk/python_sdk_ref.md) for more authentication details. \ No newline at end of file diff --git a/libs/sdk-py/langgraph_sdk/auth/types.py b/libs/sdk-py/langgraph_sdk/auth/types.py index 100076dcc..2d00aed02 100644 --- a/libs/sdk-py/langgraph_sdk/auth/types.py +++ b/libs/sdk-py/langgraph_sdk/auth/types.py @@ -153,12 +153,20 @@ def identity(self) -> str: class MinimalUserDict(typing.TypedDict, total=False): - """The minimal user dictionary.""" + """The dictionary representation of a user.""" identity: typing_extensions.Required[str] + """The required unique identifier for the user.""" display_name: str + """The optional display name for the user.""" is_authenticated: bool + """Whether the user is authenticated. Defaults to True.""" permissions: Sequence[str] + """A list of permissions associated with the user. + + You can use these in your `@auth.on` authorization logic to determine + access permissions to different resources. + """ @typing.runtime_checkable