> ## Documentation Index
> Fetch the complete documentation index at: https://docs.langchain.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Add identity to Managed Deep Agents

> Declare who is calling, scope threads and memory, and use runtime.identity in Managed Deep Agents.

Identity tells Managed Deep Agents who each run is for and how to partition threads, memory, and credentials. It is opt-in: projects without `identity.ts` or `identity.py` compile and deploy unchanged. When you add an identity declaration, the CLI wires auth, store scoping, and a frozen `runtime.identity` envelope into tools and middleware.

<Note>
  Managed Deep Agents is in **private [beta](/langsmith/release-stages)**, available on [LangSmith Cloud](/langsmith/cloud) in the US region only. [Join the waitlist](https://www.langchain.com/langsmith-managed-deep-agents-waitlist) to request access.
</Note>

## What identity solves

Without identity, every caller shares the same thread and memory boundary. With identity, Managed Deep Agents answers two questions before the agent runs:

| Question               | Term                  | Example                                |
| ---------------------- | --------------------- | -------------------------------------- |
| Who is this run for?   | **Actor**             | `user_123`, a GitHub login, a guest id |
| Which customer or org? | **Tenant** (optional) | `acme`, a Slack workspace, a repo      |

From those answers, Managed Deep Agents scopes:

* **Threads** — who can open or resume a conversation
* **Memory** — which durable store namespace the run uses
* **Credentials** — whose token downstream calls carry (managed modes or your own resolver)

Identity is fail-closed: missing required actor or tenant values reject the request instead of falling back to shared state.

## Add an identity declaration

Create `identity.py` or `identity.ts` next to your agent entry and export a named `identity`. Most projects start from a preset.

<CodeGroup>
  ```python identity.py theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  from managed_deepagents import define_identity

  identity = define_identity.preset("private-assistant")
  ```

  ```ts identity.ts theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { defineIdentity } from "managed-deepagents";

  export const identity = defineIdentity.preset("private-assistant");
  ```
</CodeGroup>

For the full project layout, see the [CLI project file reference](/langsmith/managed-deep-agents-cli#project-file-reference).

When identity is present, `mda` generates the custom auth handler, injects it into the compiled LangGraph app, and only then enables reserved identity headers and token verification.

## Choose a preset

Presets expand to a full ingress, tenancy, and scoping config. Override any field when you need a different ingress or scope.

| Preset              | Best for                                          | Threads   | Memory   | Credentials |
| ------------------- | ------------------------------------------------- | --------- | -------- | ----------- |
| `private-assistant` | Personal agents where each user owns their data   | `actor`   | `actor`  | `actor`     |
| `multi-tenant-saas` | One deployment serving many customers             | `actor`   | `tenant` | `agent`     |
| `shared-bot`        | Channel bots (Slack, Discord) with shared threads | `channel` | `actor`  | `agent`     |
| `internal-tool`     | Internal apps with per-user threads               | `actor`   | `actor`  | `agent`     |
| `service`           | Cron/webhook-only agents with shared memory       | *(unset)* | `agent`  | `agent`     |

All presets default to `trusted_backend` ingress and `tenancy: "single"`, except `multi-tenant-saas` which sets `tenancy: "multi"`.

## Ingress: how Managed Deep Agents learns who is calling

Pick one HTTP ingress mode.

### Trusted backend

Your API authenticates the user, then proxies LangGraph requests with a shared ingress secret and reserved identity headers. The browser never sends the secret or raw IdP tokens to Managed Deep Agents.

Required headers (case-insensitive):

| Header                 | Required                | Purpose                                 |
| ---------------------- | ----------------------- | --------------------------------------- |
| `X-MDA-Ingress-Secret` | Yes                     | Shared secret from `MDA_INGRESS_SECRET` |
| `X-MDA-Actor-Id`       | Yes                     | Actor id for this run                   |
| `X-MDA-Tenant-Id`      | When `tenancy: "multi"` | Tenant id for this run                  |

<CodeGroup>
  ```python identity.py theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  from managed_deepagents import define_identity

  identity = define_identity.preset("internal-tool")
  ```

  ```ts identity.ts theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { defineIdentity } from "managed-deepagents";

  export const identity = defineIdentity.preset("internal-tool");
  ```
</CodeGroup>

Put `MDA_INGRESS_SECRET` in `.env` for `mda dev` and as a hosted deployment secret for `mda deploy`. Your production backend should perform OAuth or session auth, then attach the headers above when proxying agent traffic.

### Validated token (browser-direct)

The client sends `Authorization: Bearer <token>`. Managed Deep Agents verifies the token server-side (JWKS, OIDC discovery, opaque introspection, or guest tokens signed by Managed Deep Agents) and maps claims into the identity envelope.

<CodeGroup>
  ```python identity.py theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  from managed_deepagents import define_identity, providers

  identity = define_identity.preset(
      "internal-tool",
      {
          "ingress": {
              "http": {
                  "mode": "validated_token",
                  "providers": [
                      providers.supabase(project_ref="your-project-ref"),
                      providers.guest(ttl="24h", actor_prefix="guest:"),
                  ],
              }
          }
      },
  )
  ```

  ```ts identity.ts theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { defineIdentity, providers } from "managed-deepagents";

  export const identity = defineIdentity.preset("internal-tool", {
    ingress: {
      http: {
        mode: "validated_token",
        providers: [
          providers.supabase({ projectRef: "your-project-ref" }),
          providers.guest({ ttl: "24h", actorPrefix: "guest:" }),
        ],
      },
    },
  });
  ```
</CodeGroup>

Built-in provider helpers:

| Helper               | Verification                                       | Typical claim mapping            |
| -------------------- | -------------------------------------------------- | -------------------------------- |
| `providers.auth0`    | JWKS                                               | `sub` → actor, `org_id` → tenant |
| `providers.clerk`    | JWKS                                               | `sub` → actor                    |
| `providers.okta`     | JWKS                                               | `sub` → actor                    |
| `providers.cognito`  | JWKS                                               | `sub` → actor                    |
| `providers.entra`    | JWKS                                               | `oid` → actor                    |
| `providers.google`   | JWKS                                               | `sub` → actor, `email` → email   |
| `providers.supabase` | JWKS (default) or `/auth/v1/user` introspection    | `sub` → actor                    |
| `providers.oidc`     | OIDC discovery + JWKS                              | `sub` → actor                    |
| `providers.github`   | Opaque introspection via `GET /user`               | `login` → actor                  |
| `providers.guest`    | Guest tokens signed by Managed Deep Agents (HS256) | `sub` → actor                    |

In `validated_token` mode, your frontend signs the user in with the same IdP you configured, reads an access token (or ID token where applicable), and passes it to the LangGraph client as `Authorization: Bearer <token>`. Do not send refresh tokens or client secrets to the deployment.

| Provider | Where to get the token                                     | Docs                                                                                       |
| -------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| Auth0    | Access token after login (`getAccessTokenSilently`)        | [Auth0 SPA SDK](https://auth0.com/docs/libraries/auth0-spa-js)                             |
| Clerk    | Session JWT (`session.getToken()`)                         | [Clerk `getToken()`](https://clerk.com/docs/guides/development/making-requests)            |
| Okta     | Access token from the Okta Auth JS client                  | [Okta Auth JS](https://developer.okta.com/docs/guides/auth-js/main/)                       |
| Cognito  | ID or access token from Amplify Auth or the hosted UI flow | [Amplify Auth](https://docs.amplify.aws/react/build-a-backend/auth/)                       |
| Entra    | Access token from `@azure/msal-browser`                    | [MSAL.js](https://learn.microsoft.com/en-us/entra/identity-platform/msal-overview)         |
| Google   | ID token from Google Identity Services                     | [Sign in with Google](https://developers.google.com/identity/gsi/web/guides/overview)      |
| Supabase | `session.access_token` from `@supabase/supabase-js`        | [Supabase JavaScript auth](https://supabase.com/docs/reference/javascript/auth-getsession) |
| OIDC     | Access token from your IdP's OIDC client                   | Your IdP's OIDC documentation                                                              |
| GitHub   | OAuth user access token from your app's sign-in flow       | [GitHub OAuth apps](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps)        |
| Guest    | `token` from `POST /identity/guest`                        | [Claim a guest token](#claim-a-guest-token)                                                |

When more than one provider is configured, each entry needs an `id`. Managed Deep Agents routes JWT providers by token `iss` and fails closed when the issuer is unknown.

<Tip>
  For Supabase, pass `projectRef` (the subdomain before `.supabase.co`). Managed Deep Agents derives the JWKS URL. Use `introspect: true` only for legacy projects that still need `/auth/v1/user`, and set `SUPABASE_ANON_KEY` on the deployment.
</Tip>

## Guest tokens

Add `providers.guest(...)` when anonymous visitors should get a short-lived, actor-scoped session without signing in. Managed Deep Agents signs guest tokens with `MDA_GUEST_SIGNING_KEY` (HS256). Set the key in `.env` for `mda dev` and as a hosted deployment secret for `mda deploy`. Rotate it like any other signing secret.

With guest issuance enabled, the deployment exposes a public issuance route:

```http theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
POST /identity/guest
```

### Claim a guest token

To claim a token, send an empty `POST` to the deployment base URL with `Content-Type: application/json`. If the deployment requires a public app key (`LANGGRAPH_AUTH_SECRET`), also send `X-Auth-Key`.

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
curl -X POST "$LANGGRAPH_API_URL/identity/guest" \
  -H "Content-Type: application/json"
```

On success, the response body contains a signed JWT:

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

Decode the JWT to read the actor id from `sub` (for example, `guest:01932f4a-...` when `actor_prefix` is `guest:`) and the expiry from `exp`. Managed Deep Agents maps `sub` to `runtime.identity.actor.id` on subsequent requests.

### Use the guest token

Send the token on LangGraph and connector requests the same way you send IdP access tokens:

```http theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

<CodeGroup>
  ```typescript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  const response = await fetch(`${deploymentUrl}/identity/guest`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
  });
  const { token } = (await response.json()) as { token: string };

  const client = new Client({
    apiUrl: deploymentUrl,
    defaultHeaders: { Authorization: `Bearer ${token}` },
  });
  ```

  ```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import httpx
  from langgraph_sdk import get_client

  response = httpx.post(f"{deployment_url}/identity/guest")
  response.raise_for_status()
  token = response.json()["token"]

  client = get_client(
      url=deployment_url,
      headers={"Authorization": f"Bearer {token}"},
  )
  ```
</CodeGroup>

<Tip>
  For browser apps, proxy guest issuance through your own backend and store the token in an `httpOnly` cookie. That keeps the same guest actor across reloads until `exp` and lets you handle rate limits before calling the deployment.
</Tip>

Reclaim a token when the current one is expired or missing. While a token is still valid, reuse it so the guest keeps the same actor id, threads, and memory scope for the token lifetime.

## Use `runtime.identity` in tools and middleware

When identity is declared, authored tools and middleware receive a frozen `runtime.identity` object built from the trusted auth result. Client-supplied spoofable identity keys are stripped from `configurable`.

<CodeGroup>
  ```python tools/whoami.py theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  from langchain.tools import ToolRuntime, tool


  @tool
  def whoami(runtime: ToolRuntime) -> str:
      """Return the authenticated actor id for this run."""
      identity = getattr(runtime, "identity", None)
      if not identity:
          return "No authenticated caller on this run."
      return f"Signed in as {identity['actor']['id']}"
  ```

  ```ts tools/whoami.ts theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import { tool } from "langchain";
  import type { ManagedDeepAgentRuntime } from "managed-deepagents";
  import { z } from "zod";

  export const whoami = tool(
    async (_input, runtime: ManagedDeepAgentRuntime) => {
      const identity = runtime.identity;
      if (!identity) {
        return "No authenticated caller on this run.";
      }
      return `Signed in as ${identity.actor.id}`;
    },
    {
      name: "whoami",
      description: "Return the authenticated actor id for this run.",
      schema: z.object({}),
    },
  );
  ```
</CodeGroup>

The envelope shape:

```ts theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
runtime.identity = {
  actor: { type: "user" | "service", id: string, email?: string },
  tenant?: { id: string },
  source: {
    provider: "http" | "slack" | "schedule" | "cli" | "studio",
    threadId?: string,
  },
  claims?: Record<string, unknown>, // populated for validated_token ingress
};
```

## Scoping axes

Presets cover the common cases. To customize, set `scoping` explicitly:

| Axis          | Values                             | Meaning                                 |
| ------------- | ---------------------------------- | --------------------------------------- |
| `threads`     | `actor`, `channel`, `tenant`       | Who can open or resume the conversation |
| `memory`      | `actor`, `tenant`, `agent`, `none` | Durable store namespace prefix          |
| `credentials` | `agent`, `actor`, `none`, `custom` | Whose credentials downstream calls use  |

`tenancy: "single"` cannot use `"tenant"` on any axis. Store access fails closed (403) when required identity segments are missing.

### Custom downstream credentials

Set `scoping.credentials: "custom"` and provide either an in-process `resolve` function or a hosted token-exchange `endpoint`. Tools then call `runtime.credentials.for(target)` to mint per-actor headers. Secrets stay in memory and are never written to thread state or traces.

To expose LangSmith capabilities to browsers or other untrusted callers, add a [LangSmith connector](/langsmith/managed-deep-agents-connectors/langsmith). It requires identity so capability routes can resolve the caller and prove ownership before calling LangSmith server-side.

## Secrets checklist

| Secret                  | When required                                              |
| ----------------------- | ---------------------------------------------------------- |
| `MDA_INGRESS_SECRET`    | `trusted_backend` ingress                                  |
| `MDA_GUEST_SIGNING_KEY` | `providers.guest` issuance or verification                 |
| `SUPABASE_ANON_KEY`     | Supabase introspection mode (`introspect: true`)           |
| IdP / OAuth secrets     | Your own backend or frontend auth flow (never commit them) |

Put local values in `.env`. `mda deploy` forwards non-reserved `.env` values as hosted deployment secrets.

<Warning>
  Never commit ingress secrets, guest signing keys, or IdP credentials. Do not send `MDA_INGRESS_SECRET` from the browser — only from a trusted backend proxy.
</Warning>

## Test and deploy

Test the project locally with [`mda dev`](/langsmith/managed-deep-agents-cli#develop-locally), then deploy it with [`mda deploy`](/langsmith/managed-deep-agents-deploy). Open deployment traces in LangSmith to inspect model calls, tool calls, errors, and latency.

Identity misconfiguration usually surfaces as 401 (auth) or 403 (store/thread scope) during local Studio or first authenticated request. Confirm the matching secret is present and that trusted-backend proxies attach the reserved headers.

## Next steps

<CardGroup cols={2}>
  <Card title="Custom tools" icon="tool" href="/langsmith/managed-deep-agents-tools">
    Read `runtime.identity` from authored tools.
  </Card>

  <Card title="LangSmith connector" icon="chart-line" href="/langsmith/managed-deep-agents-connectors/langsmith">
    Expose constrained LangSmith capabilities to untrusted callers.
  </Card>

  <Card title="How it works" icon="settings" href="/langsmith/managed-deep-agents-how-it-works">
    See how compile and deploy wire auth into the runtime.
  </Card>

  <Card title="CLI reference" icon="terminal" href="/langsmith/managed-deep-agents-cli">
    Look up the `identity` project file and deploy flags.
  </Card>
</CardGroup>

***

<div className="source-links">
  <Callout icon="terminal-2">
    [Connect these docs](/use-these-docs) to Claude, VSCode, and more via MCP for real-time answers.
  </Callout>

  <Callout icon="edit">
    [Edit this page on GitHub](https://github.com/langchain-ai/docs/edit/main/src/langsmith/managed-deep-agents-identity.mdx) or [file an issue](https://github.com/langchain-ai/docs/issues/new/choose).
  </Callout>
</div>
