Get to know Cadenya
We’re developers who love to build. We set out to create a yes-code platform that makes building agents feel like the best parts of building software.
An AI agent acts on behalf of the signed-in user by calling your API with a token issued for that user, not with a shared service key. The standard way to get that token is OAuth 2.0 token exchange (RFC 8693): your backend trades the user’s token for a new one scoped to the API, and with delegation the new token’s act claim names the agent, so the audit trail shows the agent acting as the user.
So pick the exchange your identity provider already speaks. Keycloak and Spring Authorization Server handle RFC 8693 if you self-host, Okta and Auth0 write the act claim for you, Microsoft Entra runs its own on-behalf-of flow, and MCP clients in a company can use the enterprise-managed authorization extension. Cadenya then carries the exchanged token into the agent’s tool calls, with nothing to host, and a coding agent can set it up with no account, in a temporary workspace you claim later. What it offers is at the end.
Every price and limit below comes from each vendor’s own pages, checked on October 13, 2026.
RFC 8693 token exchange support side by side
| Keycloak | Spring Authorization Server | Okta | Auth0 | Microsoft Entra ID | Cadenya | |
|---|---|---|---|---|---|---|
| The exchange | Standard token exchange (V2), supported since 26.2.0 and on by default | The token-exchange grant since 1.3, now part of Spring Security 7 | On-Behalf-Of Token Exchange on custom authorization servers | On-Behalf-Of Token Exchange (RFC 8693), plus Custom Token Exchange through an Action | Its own on-behalf-of flow: a jwt-bearer grant with requested_token_use=on_behalf_of | None of its own: your backend does the exchange and hands Cadenya the token |
Delegation and the act claim | may_act and act through the Token Exchange Delegation feature, which you switch on | A composite token for the “delegation” use case | act names the service app, and earlier actors nest under act.act | act “tracks the complete delegation chain" | "Referred to as delegation in OAuth” | Your API logs sub and act, and Cadenya’s event log records each toolCalled |
| For agents and MCP | Identity chaining across domains: Standard Token Exchange V2 plus the JWT Authorization Grant | Not listed in the feature list | Cross App Access (ID-JAG) on custom authorization servers | ”MCP servers that need to call first-party APIs on the user’s behalf”, plus Token Vault | Agent ID: blueprints and agent identities use on-behalf-of | A hosted agent loop that puts {{ secrets.USER_TOKEN }} in a tool set header on each call |
| How you run it | Self-hosted, Apache 2.0, latest 26.8.0 | A library in your Spring app, Apache 2.0 | Hosted | Hosted. Custom Token Exchange needs a Professional or Enterprise plan | Hosted | Hosted, nothing to run. SDKs under Apache-2.0, at 1.9.0 |
OAuth 2.0 token exchange (RFC 8693): on-behalf-of delegation vs impersonation
RFC 8693 is a Standards Track RFC from January 2020. It adds one grant type, urn:ietf:params:oauth:grant-type:token-exchange, and two ways for a token to carry someone else’s identity.
Impersonation hides the agent. Delegation names it. With impersonation, the RFC says “A is B within the context of the rights authorized by the token.” With delegation, “any actions taken are being taken by A representing B. In a sense, A is an agent for B.” (The RFC wrote “agent” in 2020, long before anyone meant an LLM by it.)
The request carries both parties. The subject_token is the user, “the party on behalf of whom the token is being requested”, and the actor_token is the agent, “the party to whom the access rights of the issued token are being delegated.” Leave out the actor and you get impersonation, since the RFC says “delegation is impossible with only a subject_token and no actor_token.”
Which one should an agent use? Delegation, whenever your API cares who clicked. Keycloak’s docs put it well: with a delegated token, the downstream service “sees both names, and can log or restrict what the app does on her behalf.”
The act claim: an audit trail for an agent acting as the user
The act claim is how a JWT says delegation happened. Here’s the RFC’s own example, where the token is about the user and act names the current actor:
{
"aud":"https://consumer.example.com",
"iss":"https://issuer.example.com",
"exp":1443904177,
"nbf":1443904077,
"sub":"user@example.com",
"act":
{
"sub":"admin@example.com"
}
}
Chains nest. “The outermost “act” claim represents the current actor while nested “act” claims represent prior actors,” and those nested claims “serve as a history trail.” So a chat app that calls an agent that calls your API can show all three hops in one token.
Only the top level and the current actor count for access control. The RFC is strict here: prior actors “are informational only and are not to be considered in access control decisions.” Log the whole chain, but authorize on sub and the outermost act.
There’s also may_act, a claim in the user’s token that says who is allowed to act for them. Keycloak uses it to let a user pre-authorize an actor.
AI agents have their own Internet-Draft too. draft-oauth-ai-agents-on-behalf-of-user, revision 02 from two WSO2 authors, adds a requested_actor parameter to the authorization request and an actor_token to the code exchange. The token it describes identifies the user in sub, the client in azp or client_id, and the agent in act.
MCP enterprise-managed authorization: ID-JAG token exchange
The MCP spec’s current revision is 2026-07-28. Its security rules say the token an MCP server receives isn’t the token it sends upstream: “The access token used at the upstream API is a separate token, issued by the upstream authorization server.” The OpenAPI and MCP page covers how generated MCP servers get that token. Token exchange is one standard way to mint it.
The enterprise-managed authorization extension (io.modelcontextprotocol/enterprise-managed-authorization) moves the decision to the company’s identity provider. It builds on the Identity Assertion JWT Authorization Grant (ID-JAG), an OAuth working group draft at revision 04 that combines RFC 8693 and RFC 7523 and is “informally referred to as Cross-App Access (XAA).”
It takes two hops. First, the MCP client trades the user’s ID token for an ID-JAG at the identity provider, using RFC 8693:
POST /oauth2/token HTTP/1.1
Host: acme.idp.example
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&requested_token_type=urn:ietf:params:oauth:token-type:id-jag
&audience=https://auth.chat.example/
&resource=https://mcp.chat.example/
&scope=chat.read+chat.history
&subject_token=eyJraWQiOiJzMTZ0cVNtODhwREo4VGZCXzdrSEtQ...
&subject_token_type=urn:ietf:params:oauth:token-type:id_token
The identity provider checks its policy and decides “if the MCP Client should be granted access to act on behalf of the user for the target MCP Server and scopes.” Then the client sends the ID-JAG to the MCP server’s authorization server with the urn:ietf:params:oauth:grant-type:jwt-bearer grant, and the access token it gets back “MUST be audience-restricted to the MCP Server.”
The user never sees a consent screen for the MCP server. The extension says it plainly: “Do not redirect the user to the MCP Authorization Server’s authorization endpoint.” Extensions are opt-in, so both the client and the server have to declare it.
Keycloak standard token exchange, Spring Authorization Server and Doorkeeper
If you run your own authorization server, here’s where each one stands.
Keycloak shipped standard token exchange in 26.2.0 (“we added support for the Standard token exchange!”), and the docs call V2 “the fully supported token exchange implementation that is enabled by default.” You still turn on the Standard token exchange switch for each client that sends exchange requests. The subject token “must be urn:ietf:params:oauth:token-type:access_token.” Delegation with may_act and act lives in a separate feature, started with --features=token-exchange-delegation.
Spring Authorization Server added the token exchange grant in 1.3, with OAuth2TokenExchangeCompositeAuthenticationToken representing “the principal in a composite token (e.g. the “delegation” use case).” The project has since moved: “The 1.5.x branch is the last generation of Spring Authorization Server,” and new features land in Spring Security from 7.0. The Spring Security 7.1.1 docs list urn:ietf:params:oauth:grant-type:token-exchange among the token endpoint’s grant types.
Doorkeeper, the Rails OAuth provider, lists RFC 6749 flows, revocation, introspection, PKCE and RFC 8707 among its supported features, and RFC 8693 isn’t in that list. But it “can recognize and process any custom grant type through its grant flow registry,” including URN grant types, so you can register the token exchange grant and write the strategy yourself.
Okta, Auth0 and Microsoft Entra on-behalf-of token exchange for AI agents
Okta runs On-Behalf-Of Token Exchange on custom authorization servers, “between other custom authorization servers under the same Okta tenant” too. The exchanged token keeps the user in sub, and “The actor claim ( act ) identifies the service app that requested the token exchange.” For agents and MCP, Okta’s Cross App Access implements ID-JAG, and Okta’s MCP server docs say custom authorization servers support it with “No additional protocol configuration required.”
Auth0 has two exchanges. On-Behalf-Of Token Exchange follows RFC 8693, and Auth0 lists “MCP servers that need to call first-party APIs on the user’s behalf” as a use case. Custom Token Exchange runs an Action you write, for subject or actor tokens in your own format, and it lists “Delegated authorization: A principal (such as a service, AI agent, or support agent) acts on behalf of a user.” For third-party APIs, Auth0 points to Token Vault, which “stores the access and refresh tokens for each connected account.”
Microsoft Entra ID calls its flow on-behalf-of, and it’s “Referred to as delegation in OAuth.” But the request isn’t an RFC 8693 request. It uses the jwt-bearer grant type with requested_token_use “set to on_behalf_of.” Entra Agent ID builds on it: agent identity blueprints “must receive a user token from a client application and then perform an OBO token exchange.”
Running on AWS? The AgentCore alternatives page covers AgentCore. And for Slack’s user token vs bot token split, see the Slack AI agents page.
What does Cadenya add to RFC 8693 token exchange?
Token exchange gives you a token that says “this agent, acting for this user.” Something still has to hold that token and attach it to every tool call the agent makes. Cadenya is that agent loop, hosted, with the user’s token carried into each call. Here’s what that covers:
- Nothing else to run. Your backend does the exchange with Keycloak, Spring, Okta, Auth0 or Entra, then hands the token to Cadenya. Cadenya calls the model and the tools, so there’s no token-forwarding proxy or agent server for you to host.
- SDKs under Apache-2.0, shipped often. TypeScript, Python, Ruby and Go, all at 1.9.0 under Apache-2.0. The TypeScript SDK has shipped 113 versions since April 2026, and a plain HTTP API covers any other language.
- Edits never change a running objective. An objective keeps its variation’s configuration snapshot even when you edit the variation, so the edit you ship today applies to new objectives while running ones keep the configuration they started with.
- A price in one line. Free for 1,000 loops a month, $49 a month for 50,000, then $0.0015 a loop. A loop is one LLM request, and there are no seats.
- The user’s token on each tool call. Put
{{ secrets.USER_TOKEN }}in a tool set header. An objective secret wins over a tool set or workspace secret with the same name, and Cadenya’s docs name this exact case: “a JWT minted to act on behalf of a user.” - The browser never picks the identity. Your backend mints a widget session with the tenant, the subject and the user’s token, and “Cadenya derives the workspace, Agent, tenant, subject, secrets, and pinned parameters from the Widget Session instead of trusting values sent by the browser.” Your Cadenya API key stays on your server.
- IDs the model can’t change. A pinned parameter, such as an account ID, “is removed from the tool schema the LLM sees, and its value is always overwritten server-side.” So the model can’t swap in another account’s ID.
- Revocation that reaches the agent. Revoking a widget session “stops its outstanding tokens from authenticating and removes its secrets.” Secrets are encrypted at rest and never returned by any API.
- An audit trail on both sides. Your API logs the
subandactfrom the exchanged token. Cadenya’s event log records eachtoolCalledwith “its tool, configuration, and arguments,” and you can filter objectives by the tenant and subject you assert. A tool marked for approval pauses ontoolApprovalRequested, and your backend approves or denies it bytoolCallId. - Your identity provider and your model, unchanged. A secret is a named value, so the token can come from any provider on this page. The model is a setting on a variation, on your own provider keys.
How objectives work shows objective secrets in a tool header, and the free plan needs no card.
No account yet? A coding agent can create a temporary workspace with cadenya workspaces create --temporary, run its first objectives there, and hand you a link to claim it, as auth.md explains. To create an account, sign up at app.cadenya.com/signup, then copy your API key from the API keys page at app.cadenya.com/account/apiKeys.
Grow wherever AI goes next.
Start shipping agents that are equipped to evolve.