Skip to main content
Agents are not anonymous chatbots. As soon as more than one person (or one company) uses a deployment, you need to know: whose conversation is this, and whose data may the agent see or act on? Identity lets one deployment serve thousands of users safely, with no data leakage between callers. Managed Deep Agents answers that question before every run. You declare a small contract once, and the runtime partitions threads, memory, and credentials so callers cannot see or affect each other. Identity is opt-in. Projects without identity.ts or identity.py compile and deploy unchanged. When you add a declaration, mda wires auth, scoping, and a frozen runtime.identity object into tools and middleware. This page assumes you have an existing Managed Deep Agents project and the mda CLI installed. If you are new to Managed Deep Agents, start with the overview and quickstart first.
Managed Deep Agents is in private beta, available on LangSmith Cloud in the US region only. Join the waitlist to request access.

Why identity matters for agents

Without identity, a Managed Deep Agent has one shared boundary for the whole deployment. That is fine for a personal prototype. It breaks as soon as real users show up: Deep Agents without identity make this a real problem: they keep durable memory, resume long-running threads, and call tools on the user’s behalf. Identity turns “who is calling?” into enforced isolation instead of hoping the prompt or the UI keeps people apart. A key benefit of identity is that downstream tool calls can act as the signed-in user rather than as a shared bot account. For example, with credentials: "actor", the agent calls GitHub as Alice, not as a single bot token shared across all users. For deployments with compliance requirements such as SOC 2, GDPR, or HIPAA, identity scoping provides the data segregation boundaries that auditors expect: each caller’s threads and memory are isolated, and runtime.identity gives you an audit trail of who triggered each run.
Adding identity to a project that previously had none does not delete existing threads or memory. Threads created before identity was enabled remain accessible at the agent scope. New threads are scoped by actor (or tenant) according to your declaration. To migrate old data, export it and re-create threads under the new scoping rules.

Understand three core concepts

Learn these three concepts before you write any identity config: A few important clarifications:
  • Actor is not the agent. It is the caller the run represents.
  • Tenant is not a LangSmith workspace. Single-tenant agents have no tenant.
  • Fail closed means the runtime rejects any request that is missing a required actor or tenant. It never falls back to shared memory or threads.
From actor (and optional tenant), Managed Deep Agents derives three outcomes:
  • Threads: who can open or resume a conversation
  • Memory: which durable Context Hub slice the run can see
  • Credentials: whose token the agent uses for downstream tool calls (the signed-in user, or one shared agent token)

Choose a preset

Presets encode the common product shapes so you do not invent scoping rules on day one. Start here, then override only what differs. The preset table uses these scope values: Credentials is often the first thing teams consider:
  • actor: downstream calls can act as the signed-in user (for example call GitHub as Alice).
  • agent: downstream calls use one shared bot or service token for everyone.
Managed Deep Agents ships with five product shapes out of the box, covering the most common deployment patterns. Choose a preset based on your product shape: All presets default to trusted_backend ingress and tenancy: "single", except multi-tenant-saas, which sets tenancy: "multi".
How to choose quickly:
  • One human per conversation who must not see anyone else’s data → private-assistant
  • SaaS with customer orgs → multi-tenant-saas
  • Shared channel bot → shared-bot
  • Internal company tool → internal-tool
  • Timer or webhook with no user → service

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 one-line preset:
That expands to this full contract:
Use the full form when you want every field visible, or when you are assembling a config that does not match a preset. You can also start from a preset and override only the fields that differ. The same define_identity / defineIdentity object serves as both a factory (full form) and a preset selector (.preset() method). For the full project layout, see the 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.

Ingress: identify the caller

Ingress is the mechanism the runtime uses to identify the actor (and tenant) for each request. Choose one HTTP mode: trusted_backend or validated_token. Your own API authenticates the user (session, OAuth, or similar), then proxies LangGraph requests with a shared ingress secret and reserved identity headers. The browser never sends the secret or raw identity-provider (IdP) tokens to Managed Deep Agents. This is the default ingress for all presets, and the recommended choice when you already have a backend in front of the agent. For the broader LangGraph auth model, see Add auth to your server. Required headers (case-insensitive): Use a preset that defaults to trusted-backend ingress:
Put MDA_INGRESS_SECRET in .env for mda dev and as a hosted deployment secret for mda deploy. In production, your backend authenticates the user, then attaches the identity headers (X-MDA-Ingress-Secret, X-MDA-Actor-Id, and X-MDA-Tenant-Id when applicable) when proxying agent traffic. Example shape for a backend proxy (pseudocode):
Never commit ingress secrets or IdP credentials. Only send MDA_INGRESS_SECRET from a trusted backend proxy, never from the browser.

Validated token (browser-direct)

Use this when the browser talks to the deployment directly and you do not want a proxy that asserts actor headers. The client sends Authorization: Bearer <token>. Managed Deep Agents verifies the token server-side and maps claims (fields inside the token, such as user id) into runtime.identity. Verification can use:
  • JWKS: public keys your IdP publishes so the runtime can verify signed JWTs
  • OIDC discovery: standard metadata that points the runtime at those keys
  • Opaque introspection: call the IdP to ask whether a non-JWT token is still valid
  • Guest tokens: short-lived tokens signed by Managed Deep Agents for anonymous visitors
Override a preset to enable validated-token ingress. The following example combines Supabase sign-in with optional guest access:
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. When you configure more than one provider, give each entry a unique id. The runtime routes JWT providers by token iss (issuer) and returns 401 when the issuer does not match any configured provider. For provider-specific options and client examples, see Provider setup guides. To let anonymous visitors use the agent with no external identity provider, configure guest tokens as the only provider. Each visitor gets a short-lived, Managed Deep Agents-signed token and a distinct guest actor, so the private-assistant preset still scopes threads and memory per visitor.
When a guest provider is configured, the deployment exposes a public POST /identity/guest route that mints a guest token. The client calls it once, then sends the returned token as Authorization: Bearer <token> on later requests. The response body is {"token": "<token>"}.

Secrets checklist

Put local values in .env. mda deploy forwards non-reserved .env values as hosted deployment secrets. Provider-specific secrets (for example Supabase introspection) are listed in Provider setup guides.
Never commit ingress secrets, guest signing keys, or IdP credentials. Only send MDA_INGRESS_SECRET from a trusted backend proxy, never from the browser.

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. The identity object looks like this:
Annotate the injected runtime parameter as ManagedDeepAgentRuntime so you get typed access to identity (and optional credentials). Use it whenever a tool or middleware hook needs to know who triggered the run, for personalization, audit logs, or branching on verified claims, without trusting anything from the request body.
The same type works in middleware hooks:
Prefer runtime.identity over client-supplied configurable keys for actor or tenant ids. For other per-run values such as feature flags, use normal LangChain runtime context.

Customize scoping

Presets cover the common cases. To customize, set scoping explicitly: If tenancy is "single", do not set any scoping axis to "tenant", there is no tenant to scope by. If a request is missing the actor or tenant id that scoping needs, Managed Deep Agents rejects it with 403 instead of falling back to shared data. For how memory paths remount under each scope, see Scope memory with identity.

Custom downstream credentials

Use scoping.credentials: "custom" when your application can securely obtain a per-actor credential for a downstream target. Provide a resolve function; tools then call runtime.credentials.for(target) to obtain the headers for that request. Resolved credentials are kept in memory and are never written to thread state or traces.
The token that proves a caller’s identity is not automatically a credential for downstream APIs. For example, a Supabase access token lets Managed Deep Agents identify the caller, but it is not a GitHub API token. Your backend or credential service must hold (and, when needed, refresh) the caller’s separately authorized GitHub credential.
The following shape lets a user sign in through Supabase and open GitHub pull requests as themselves. After the user has separately authorized GitHub, your application stores the GitHub grant keyed by the Supabase user id. getGitHubAccessToken is application code: it looks up and refreshes that grant in your server-side credential store.
identity.ts
In a GitHub tool, request the headers with await runtime.credentials.for({ kind: "connection", name: "github", intent: "write" }) and pass them to your GitHub client. To expose LangSmith capabilities to browsers or other untrusted callers, add a LangSmith connector. It requires identity so capability routes can resolve the caller and prove ownership before calling LangSmith server-side.

Provider setup guides

These guides cover the built-in providers for validated token ingress. Use one provider, or combine them as in the example in that section.
Anonymous visitors get a short-lived, actor-scoped session without signing in. Managed Deep Agents signs guest tokens with MDA_GUEST_SIGNING_KEY (HS256) and maps sub → actor.Guest is usually combined with another IdP, as in the validated token example.Set MDA_GUEST_SIGNING_KEY in .env for mda dev and as a hosted deployment secret for mda deploy.

Claim a guest token

With guest issuance enabled, the deployment exposes POST /identity/guest. Send an empty POST with Content-Type: application/json. If the deployment requires a public app key (LANGGRAPH_AUTH_SECRET), also send X-Auth-Key.
On success:

Use the guest token

Send the token the same way you send IdP access tokens:
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.
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.

Test and deploy

Test the project locally with mda dev, then deploy it with mda 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 the first authenticated request. Confirm the matching secret is present and that trusted-backend proxies attach the reserved headers.

Next steps

Memory

See how identity remounts per-actor or per-tenant memory.

Custom tools

Read runtime.identity from authored tools.

Evals

Supply identity.json fixtures for Harbor tasks when identity is declared.

Schedules

Run cron agents, including the service preset shape.

LangSmith connector

Expose constrained LangSmith capabilities to untrusted callers.

Channels

Receive Slack Events with shared-bot or Connect-with-Slack linking.

How it works

See how compile and deploy wire auth into the runtime.

CLI reference

Look up project files and identity wiring in mda.