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 user-scoped credentials, 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 user (or organization) 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:
- User is not the agent. It is the caller the run represents, and it can be a person or a service (
user.kind). - Organization is not a LangSmith workspace. Single-organization agents have no organization. Users can also carry a read-only
groupslist (every group the caller’s token asserts) for authorization checks inside tools; isolation still keys on the single-valued organization. - Fail closed means the runtime rejects any request that is missing a required user or organization. It never falls back to shared memory or threads.
- 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 scope
scope is the isolation boundary for the deployment. One value covers the common product shapes; per-axis overrides handle the exceptions.
The scope values:
Credentials is often the first thing teams consider:
user: 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.
All declarations default to
backend auth (your backend asserts the caller) and optional organizations, except scope: "organization", which requires an organization on every request.
Add an identity declaration
Createidentity.py or identity.ts next to your agent entry and export a named identity. Most projects need no options at all — defineIdentity() gives every caller private threads, memory, and credentials behind your backend’s auth:
scope accepts either one boundary ("user", "organization", "agent", "none") or per-axis overrides such as { default: "user", threads: "conversation" }.
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.
Auth: identify the caller
auth is the mechanism the runtime uses to identify the user (and organization) for each request. Choose one HTTP mode: "backend" or a validated-token provider list.
Backend (recommended default)
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, 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):
The default declaration already uses backend auth, so there is nothing to set:
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-User-Id, and X-MDA-Organization-Id when applicable) when proxying agent traffic.
Example shape for a backend proxy (pseudocode):
Validated token (browser-direct)
Use this when the browser talks to the deployment directly and you do not want a proxy that asserts user headers. The client sendsAuthorization: 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
auth to enable validated-token ingress. The following example combines Supabase sign-in with optional guest access:
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.
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.
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:
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.
runtime.identity over client-supplied configurable keys for user or organization ids. For other per-run values such as feature flags, use normal LangChain runtime context.
Customize scoping
The common shapes cover most cases. To customize, setscope per axis:
Do not set any scoping axis to
"organization" when organizations are optional, there may be no organization to scope by. If a request is missing the user or organization 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.
Downstream credentials
Declarecredentials when downstream calls need more than an agent-wide token. credentials accepts one resolver or a map keyed by target name, so one deployment can integrate several platforms. Providing any resolver puts the credentials axis into custom mode; 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.
credentials.github resolver chains token sources per intent. When the chain reads "user" tokens, Connect-with-GitHub OAuth routes mount automatically—there is nothing else to declare:
await runtime.credentials.for({ kind: "connection", name: "github", intent: "write" }) and pass them to your GitHub client.
For other platforms, supply a resolve function yourself. The following shape lets a user open pull requests as themselves after your application has stored their GitHub grant. getGitHubAccessToken is application code: it looks up and refreshes that grant in your server-side credential store.
identity.ts
Connect-with-X routes
Connect-with-X binds an MDA user to an external account via OAuth—either to link a channel identity (Slack) or to populate a per-user credential vault (GitHub). Routes are inferred from the rest of the declaration on user-scoped deployments:- Connect-with-GitHub mounts when a credential chain reads
"user"tokens. - Connect-with-Slack mounts when a Slack channel is declared.
connect only to add providers the inference cannot see, such as a custom OAuth provider:
Provider setup guides
Theauth namespace ships providers for the common identity providers:
Each factory returns a plain provider object, so spread it to override the claim mapping (
user, organization, groups, email) when the token’s claims do not match the defaults. The tabs below cover the providers that need extra setup. Use one provider, or combine them as in the validated token example.
- Guest tokens
- Supabase
- GitHub
Anonymous visitors get a short-lived, user-scoped session without signing in. Managed Deep Agents signs guest tokens with On success: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 user id, threads, and memory scope for the token lifetime.
MDA_GUEST_SIGNING_KEY (HS256) and maps sub → user.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 exposesPOST /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.Use the guest token
Send the token the same way you send IdP access tokens:Test and deploy
Test the project locally withmda 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 backend proxies attach the reserved headers.
Next steps
Memory
See how identity remounts per-user or per-organization 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
agent scope shape.LangSmith connector
Expose constrained LangSmith capabilities to untrusted callers.
Channels
Receive Slack Events with a 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.Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

