End-user identity and credentials
End-user identity and credentials
When you build a multi-tenant product on Runtype, the calls to Runtype are made by your backend with your API key, but the person on the other end is one of your end users. End-user identity lets Runtype recognize that person so an agent can scope memory, records, and secrets to them, and act on their behalf.
This guide covers two related capabilities: proving who an end user is (Identity Exchange), and letting an end user connect their own third-party account so an agent can use it (credential registration).
End-user identity is for multi-tenant products where individual end users need their own scoped data or their own connected accounts. If every execution runs as your organization, you do not need any of this. Your API key already scopes everything to your account.
How it fits together
Three pieces work as a chain:
- Prove the end user. Your app sends Runtype a proof of who the end user is. Runtype verifies it and projects a durable end-user identity.
- Scope to the end user. That identity scopes the agent’s memory, records, and secrets, so one end user never sees another’s data.
- Connect their accounts. An end user attaches their own GitHub (and, over time, other) account. The token is stored against their identity and resolved for them at execution time.
You can adopt the pieces independently. Scoping works with a plain end-user id today; verified proofs and credential registration build on top.
Proving an end user’s identity
Runtype verifies end users two ways. Both produce the same durable end-user identity, so the rest of the platform does not care which you use.
Identity Exchange (bring your own IdP)
Identity Exchange is a token broker. You register your identity provider once as an integration, then pass a short-lived token from that provider on each request. Runtype verifies the token against your provider’s public keys and maps the verified subject to an end user.
Register an integration with your issuer’s details. Runtype mints the integration id, which is the isolation boundary between one provider and another.
The descriptor is validated when you create it:
Only one active integration may pin a given issuer. A second one is rejected so a token can never match two integrations ambiguously.
Runtype-hosted identity
If you do not run your own identity provider, Runtype can host end-user sign-in for you. Your end users sign in through a Runtype-hosted page branded to your product, and Runtype issues them a token you present the same way as any other proof. This path needs no integration setup on your side. Contact Runtype to enable it for your account.
Passing a proof on a request
Once an integration exists, attach the end user’s token to a dispatch or chat request as identityProof. provider is a hint that names the integration you expect; token is the proof itself.
When the proof verifies, the verified end user replaces any tenant or end-user fields in the request body. Body-asserted identity is never trusted for browser-embedded callers, so the proof is the only thing that grants a verified end-user scope.
Treat the token like a secret. Send a freshly minted, short-lived token per request. Runtype never logs, stores, or echoes it. Do not put a long-lived token in client-side code.
Verified-proof upgrades are rolling out for multi-tenant deployments. If a request presents a proof before the upgrade is enabled for your account, the proof is ignored. A strategy-less resource keeps its existing scoping behavior. An end-user-isolated agent called from a browser or client-token surface instead fails closed with 403 because no verified end user reaches the tenancy gate; it never silently runs unscoped. A trusted backend using a management API key can continue to pass endUser directly. Contact Runtype before enabling the strategy for an embedded surface.
Scoping an agent to the verified end user
A verified proof establishes identity, but it does not change an agent’s data scope by itself. Set the saved agent’s Tenancy Strategy to end-user-isolated when you create or update it:
This preset requires a verified end user and fails closed when one is missing. For an admitted execution, Runtype applies the same end-user scope to memory, records, and secret resolution. Keep the strategy on the saved agent definition; do not accept it from an end-user-controlled dispatch body.
Connecting an end user’s third-party account
Credential registration lets an end user attach their own third-party account (GitHub first) so an agent can act as them, using their permissions. The connect step verifies the end user, then hands their browser to the provider’s consent screen; the callback stores the resulting token against that end user.
The flow has two legs.
Start the connection
Your backend calls the connect endpoint with the end user’s proof. It returns a URL to send the end user to.
The response includes an authorizeUrl. Redirect the end user’s browser there.
Complete the connection
GitHub sends the end user back to the callback URL with an authorization code. Runtype exchanges it for a token, stores that token scoped to the end user, and redirects the browser to the redirectAfter URL you supplied at connect. You do not build the callback; it is a Runtype endpoint.
The end user now has a stored, per-user credential. Reconnecting later replaces the stored token in place.
Connecting a provider requires the provider’s OAuth app to be configured on your deployment. Until it is, the connect endpoint returns 501 Not Configured. Contact Runtype to provision a connector.
Using the stored credential
The token is stored under a stable key scoped to the end user. A GitHub token is stored as GITHUB_TOKEN. Reference it in a tool config the same way you reference any secret:
When an agent with the end-user-isolated Tenancy Strategy runs for that end user (identified by a verified proof), {{secret:GITHUB_TOKEN}} resolves to their token. A different end user resolves to their own, and an end user who has not connected an account has no token to resolve. The key is constant across end users; the isolation comes from the end-user scope, not the name.
Memory-only scoping without a proof
Even before you wire up proofs, a trusted backend using a management API key can partition an agent’s memory per end user. Set the agent’s memory profileTemplate to {{_endUser.id}} and pass the end-user id at dispatch. This legacy setup scopes memory only. It does not scope records or secret resolution, so do not use it to isolate connected credentials. Use a verified proof with the end-user-isolated Tenancy Strategy for that. See Creating and configuring agents for the memory scoping options.