Keycloak 26.8 Token Exchange Delegation for AI Agents

Guilliano Molaire Guilliano Molaire 15 min read

Keycloak 26.8 promotes token exchange delegation from experimental to preview and adds client delegation, which lets a user consent to a specific client, such as an AI agent, acting on their behalf. The user’s token gets a may_act claim naming the agent, the agent exchanges it for a short-lived access token that carries an act claim, and Fine-Grained Admin Permissions V2 decides which agents may be delegated to at all. The feature is disabled by default and is enabled with --features=token-exchange-delegation,parameterized-scopes.

The Keycloak 26.8.0 release notes, published with the 26.8.0 tag on 1 October 2026, frame the problem directly: AI agents and automation tools “need limited, consent-based access to act on behalf of a user without requiring administrator privileges or exposing sensitive credentials.” This post covers what 26.8 actually ships for that, how the flow runs end to end, what the security model guarantees, and what to change if you tried the experimental version in 26.7. If you want the basics of RFC 8693 first, our explainer on how Keycloak token exchange works covers standard (V2) and legacy (V1) exchange.

What problem does Keycloak token exchange delegation solve for AI agents?

It gives an agent a token that says “this agent, acting for this user” instead of a token that just says “this user”. The Keycloak token exchange guide at 26.8.0 uses a calendar example: with impersonation, the calendar service cannot tell whether Alice or the app made a booking, while with delegation it sees both names and can log or restrict what the app does.

Before 26.8, teams building agents usually picked one of two shortcuts, and both have costs. The first is to hand the agent the user’s own access token. The token exchange guide lists four drawbacks of that approach: there is no audience control, because nothing binds the token to the one service the agent needs; there is no scope restriction, because the token carries everything the user can do; there is no audit trail, because a misbehaving agent looks exactly like the user; and the user is never asked whether the agent may act for them at all.

The second shortcut is to give the agent a service account with broad permissions, sometimes including Admin REST API roles so it can look up or act on users. That works, but a leaked agent credential then gives an attacker the same reach as an administrator account. We covered the service account approach and its limits in authenticating AI agents with Keycloak and in our piece on non-human identity for AI agents.

Delegation sits between the two. The delegated token is issued with the audience and scopes of the actor client rather than the user’s original app, the act claim records who is really making the call, and the user explicitly approves the arrangement on a consent screen.

What does Keycloak 26.8 add to token exchange?

Keycloak 26.8 renames the existing admin delegation scope to delegation:user, adds a new delegation:client scope for applications, moves authorization to FGAP V2, and adds a client policy executor to police the claim. Per the 26.8.0 release notes, the delegation:user and delegation:client client scopes are auto-created as Optional scopes in all realms, and delegation authorization is controlled exclusively through Fine-Grained Admin Permissions V2.

Here is the full list of moving parts, as the release notes and token exchange guide describe them:

  • Two parameterized scopes. Parameterized scopes (formerly called dynamic scopes, promoted from experimental to preview in 26.8) let a client pass a value inside the scope name. delegation:client:<client_id> names a client application as the actor, and delegation:user:<username> names a user, typically an administrator, as the actor.
  • The may_act claim. When the user consents and the permission check passes, the user’s token gets a may_act object holding the actor’s sub and, for client delegation, its client_id.
  • The act claim. The token the actor receives from the exchange carries an act object built from may_act, so resource servers can see both the data owner and the caller.
  • FGAP V2 permissions. A new delegate scope on the Users resource type and a delegate-members scope on the Groups resource type decide which actors may be delegated to, and for which users.
  • A may-act client policy executor. It re-validates any may_act claim found in a token response, whatever produced it.
  • Hardening of standard exchange. Standard token exchange now rejects subject tokens carrying delegation claims, so a delegated token cannot be passed through the ordinary exchange path to drop its delegation claims.

The release notes also say delegation audit events now include the client identity, and that client delegation “does not grant Admin API access even if the client holds service account credentials, ensuring that a leaked delegation token cannot escalate privileges.”

How does a delegated Keycloak token exchange flow work?

The flow has two halves: a consented login that mints may_act, then an exchange in which the agent presents both the user’s token and its own. The token exchange guide at 26.8.0 says the exchange step is the same for admin and client delegation, and only the contents of may_act differ.

For client delegation with an agent client called actor-app, the sequence runs like this:

  1. The application the user signs in to requests scope=openid delegation:client:actor-app. That client must have Consent required switched on.
  2. Keycloak checks that actor-app exists, is enabled, has a service account, and that the service account holds the delegate permission for this user through FGAP V2.
  3. The user sees a consent screen for the delegation and approves it.
  4. The issued token contains may_act with the actor’s service account user ID and client ID, and actor-app is added to its aud automatically.
  5. The user’s token reaches actor-app, which gets its own access token with the client_credentials grant.
  6. actor-app calls the token endpoint with the user’s token as subject_token and its own as actor_token.
  7. Keycloak returns a delegated access token, with no refresh token, whose audience and scopes come from actor-app‘s configuration.

The may_act claim in step 4 looks like this, adapted from the guide:

{
  "sub": "0fa1e5d4-3c2b-4a19-8765-0123456789ab",
  "may_act": {
    "sub": "9b8c7d6e-5f4a-4b2c-9d0e-fedcba987654",
    "client_id": "actor-app"
  },
  "scope": "openid delegation:client:actor-app"
}

And the delegated token from step 7 carries the actor in act, while sub stays the user:

{
  "sub": "0fa1e5d4-3c2b-4a19-8765-0123456789ab",
  "act": {
    "sub": "9b8c7d6e-5f4a-4b2c-9d0e-fedcba987654",
    "client_id": "actor-app"
  }
}

A downstream API that reads sub knows whose data is involved, and one that reads act knows which agent is calling. That is the property that lets you write a policy such as “this agent may read a user’s calendar but never delete events”, because the API can finally tell the two apart.

How is delegation different from service-account agents and admin impersonation?

Delegation keeps the user as the subject and records the agent as the actor, which neither alternative does. The token exchange guide’s comparison table for 26.8.0 lists delegation per RFC 8693 as preview support in standard token exchange V2 and not supported at all in legacy V1.

Model Whose identity is sub Who is recorded as the caller User consent Admin API exposure
Service-account-only agent The agent’s service account The agent None Whatever roles the service account holds
Admin impersonation The impersonated user act claim (always present from 26.8) None The impersonated user’s own permissions; the impersonator needs the impersonation role or an FGAP impersonate permission
Client delegation (26.8 preview) The user act claim with the agent’s client_id Required, per login session None granted by delegation

A service-account-only agent is still the right model when the agent works on its own behalf, for example a nightly job that reconciles records with no user in the loop. It becomes awkward the moment the agent needs to act on a specific user’s data, because the downstream API either trusts the agent with everyone’s data or has to accept a user identifier the agent asserts by itself.

Impersonation also changed in 26.8, and the change is useful context. The release notes say tokens issued from impersonation sessions now include the act claim in both access tokens and ID tokens, the claim “is always present and cannot be disabled”, and token lifecycle events such as CODE_TO_TOKEN and REFRESH_TOKEN now carry impersonator and impersonator_id details. The upgrading guide adds that the introspection endpoint’s act.sub is now the impersonator’s user ID rather than their username, with a new preferred_username field for consumers that need the name. If you run a support impersonation workflow like the one in secure user impersonation for support teams, check any resource server that parsed act.sub from introspection as a username.

The difference that remains is intent and consent. Impersonation is an administrator stepping into a user’s session, while delegation is a user pre-authorizing a named actor, scoped to that actor’s configuration.

What security guarantees does the delegated token carry?

The delegated token is deliberately narrow: access token only, issued in a transient session, with audience and scopes taken from the actor client. According to the token exchange guide at 26.8.0, it carries no refresh token and no session identifier, so an agent that needs to keep working must go back through the exchange.

The guarantees worth knowing, all from the 26.8.0 guide and release notes:

  • No Admin API access from client delegation. The actor client needs no admin roles, and the release notes state that client delegation does not grant Admin API access even when the client has service account credentials.
  • Consent is per login session. The delegation scopes always require consent, and the guide says that consent “is never stored permanently, so the user approves the delegation on every login session.”
  • Narrowed audience and scopes. The aud claim and scopes of the delegated token are resolved from the actor client’s client scopes and role mappings, not copied from the subject token.
  • No bypass through standard exchange. Without an actor_token, the request is handled as standard token exchange, which rejects any subject token carrying may_act or act.
  • Strict actor matching. The exchange fails if the actor token resolves to the same user as the subject, if may_act is missing or not an object, if may_act.iss is not this realm, if may_act.sub is not the actor, or if may_act.client_id does not match the actor and the requesting client.

The guide also notes a limit that is easy to miss: Keycloak validates only sub, client_id and iss inside may_act, and every other claim is copied unchanged into act. If you add a mapper that puts, say, a description of the agent into may_act, treat it as a label for logs and humans, never as an input to an authorization decision.

The other gap the guide calls out is that a may_act claim could reach a token by a route that skipped consent and the permission check, such as a hardcoded claim mapper set directly on a client. The may-act client policy executor closes that gap by re-checking the issuer, the actor user, the delegate permission and the consent on every token response that carries may_act. It also has a Reject any may_act claim option for clients that must never take part in delegation, which is a sensible default for anything that is not part of your agent flow.

Revocation is the last thing to plan for. The same guide says revoking an original access token does not revoke access tokens exchanged from it, so administrators should keep access tokens short-lived. Because there is no refresh token, each delegated token lives for the access token lifespan that applies to actor-app (the realm default or the client override), after which the agent has to exchange again.

How do you configure an agent client for Keycloak token exchange delegation?

You need two feature flags, a confidential actor client with a service account and standard token exchange, a consent-required login client, and one FGAP V2 permission. The token exchange guide at 26.8.0 says that without a matching delegate permission the delegation scope “is silently dropped from the request” and the login still succeeds, so the permission is the step to verify first when nothing seems to happen.

Here is the checklist for a coding or operations agent called actor-app:

  1. Enable the features. Start the server with bin/kc.sh start --features=token-exchange-delegation,parameterized-scopes. The delegation scopes are then created as Optional client scopes in every realm, new and existing.
  2. Create the actor client. actor-app must be confidential, have Service accounts enabled, and have Standard Token Exchange enabled. Delegation is built on standard token exchange V2, which our practical token exchange guide walks through.
  3. Give the actor client the right downstream audience. Since the delegated token’s aud and scopes come from actor-app‘s own client scopes and role mappings, configure those for the APIs the agent should reach and nothing more.
  4. Turn on Consent required for the login client. The client that requests the delegation scope must have Consent required enabled, otherwise the authorization request fails with invalid_scope.
  5. Enable Admin Permissions (FGAP V2) on the realm. Go to Realm Settings, then Admin Permissions, and enable it.
  6. Create the delegate permission. Create a permission on the Users resource type with the delegate scope, leave All users selected (or use a Groups permission with delegate-members to limit it to specific groups), and attach a Client policy selecting actor-app.
  7. Request the scope at login. The login client asks for scope=openid delegation:client:actor-app.
  8. Optionally attach the may-act executor through Realm settings, then Client policies, and use Reject any may_act claim on clients outside the agent flow.

The agent then obtains its own token and performs the exchange, as shown in the guide:

POST /realms/myrealm/protocol/openid-connect/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&
client_id=actor-app&
client_secret=XXXXX
POST /realms/myrealm/protocol/openid-connect/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Accept: application/json

grant_type=urn:ietf:params:oauth:grant-type:token-exchange&
client_id=actor-app&
client_secret=XXXXX&
subject_token=eyJhbGci[...redacted...]&
subject_token_type=urn:ietf:params:oauth:token-type:access_token&
actor_token=eyJhbGci[...redacted...]&
actor_token_type=urn:ietf:params:oauth:token-type:access_token

The presence of actor_token is what selects the delegation flow, and requested_token_type, if you send it, can only be an access token. When things go wrong, the guide’s troubleshooting table maps symptoms to causes: no may_act in the token usually means a missing permission, a misspelled client ID or a missing service account, invalid_request on exchange means the actor does not match may_act, and access_denied means the requesting client is outside the audience of one of the tokens. Dropped scopes are always logged at WARN with the reason.

If your agent clients also use mTLS certificate-bound tokens, read our write-up of CVE-2026-97846, in which standard token exchange issued an unbound Bearer token for a client configured for certificate binding, and confirm the status of the fix for the Keycloak version you run.

What changes if you used the 26.7 experimental delegation?

Two things break: the scope name and the authorization model. The upgrading guide for 26.8.0 says the scope was renamed from delegation to delegation:user, so a request that used delegation:admin1 must now use delegation:user:admin1, and the impersonation role from realm-management is no longer used to authorize delegation.

The migration steps from the upgrading guide are short:

  • Update clients and automation to request delegation:user:<administrator> instead of delegation:<administrator>.
  • Enable Admin Permissions (FGAP V2) on each realm that uses delegation.
  • Create a User permission with the delegate scope, or a Group permission with delegate-members, targeting the administrators or service accounts allowed to delegate.
  • Remove the old delegation client scope once migration has created delegation:user and delegation:client.

The guide is explicit that FGAP V1 does not support delegation permissions. If a realm still depends on FGAP V1, for example because it runs legacy token exchange, plan that move before you depend on delegation there. Also note the new delegation:client type, which did not exist in the 26.7 form and is the one designed for agents. Agents that previously authenticated as an administrator to use delegation should usually move to client delegation, which needs no admin roles.

How does this compare with vendor “agent SSO” products?

It covers the token layer of what those products sell, but not the inventory and discovery layer, and it anchors trust differently. In Keycloak delegation the user consents interactively to a named actor, the actor is an ordinary confidential client, and the result is an RFC 8693 delegated token with act. The agentic IAM launches we reviewed in agentic IAM in September 2026 lead with agent registries and discovery, and Okta Agent SSO connects agents to applications through Cross App Access, where the identity provider issues an identity assertion that the agent trades for a token at the target app (covered in Cross-App Access (ID-JAG) and where Keycloak stands). Delegation fits well when you own both the agent and the APIs it calls and want users to approve each session, while a cross-domain assertion model fits better when the agent calls third-party SaaS that trusts your workforce identity provider.

What should you watch if you run managed Keycloak?

The two things to keep an eye on are the preview label and the FGAP policies. The Keycloak server guide on features says preview features “are disabled by default and are not recommended for use in production” and “may change or be removed at a future release”, and the 26.7 to 26.8 scope rename already showed that happening to delegation.

On a managed service, the server-level feature flag is something your provider controls, so ask whether token-exchange-delegation and parameterized-scopes are enabled on your cluster and how preview changes are communicated before an upgrade. Skycloak is identity management as a service built on upstream Keycloak, so where a preview flag like this is enabled it follows the upstream guide rather than a fork. The FGAP V2 policies themselves live in your realm, though, and reviewing who holds delegate or delegate-members belongs on the same schedule as reviewing admin roles.

If you want to try it, the practical order is to enable the two features on a test realm, create the FGAP delegate permission before anything else, confirm that may_act appears in the user’s token, and then attach the may-act executor with Reject any may_act claim to every client that is not part of the agent flow.

FAQ

Is Keycloak token exchange delegation production ready?

Not yet. It is a preview feature in Keycloak 26.8, and the Keycloak server guide says preview features are disabled by default, are not recommended for use in production, and may change or be removed. The 26.7 experimental version already changed its scope name and authorization model in 26.8, so build and test on a non-production realm and retest the flow on every upgrade.

Does client delegation give the agent access to the Admin REST API?

No. The 26.8.0 release notes state that client delegation does not grant Admin API access even if the client holds service account credentials, so a leaked delegation token cannot escalate privileges. The actor client also needs no admin roles of its own, because the delegate permission is granted through FGAP V2 rather than through admin roles.

Why does my token have no may_act claim?

Delegation scopes fail safe, so the scope is dropped while the login still succeeds. According to the token exchange guide, the usual causes are a missing delegate permission in FGAP V2, a misspelled client ID or username, or an actor client without a service account. Keycloak logs every dropped scope at WARN with the reason.

Can the agent refresh a delegated token?

No. The delegated token is issued in a transient session, so the exchange returns an access token only, with no refresh token and no session identifier. Because consent is not stored, the user approves the delegation again on each login session, and the agent must repeat the exchange to get a new delegated token.

Which claims inside may_act does Keycloak validate?

Only sub, client_id and iss. Any other claim you add through mappers is copied unchanged into the act claim of the delegated token. That makes extra claims useful for logging and for describing the actor, but resource servers should never base an authorization decision on them.

Sources

  • Keycloak, Keycloak 26.8.0 release notes (source at tag 26.8.0), https://github.com/keycloak/keycloak/blob/26.8.0/docs/documentation/release_notes/topics/26_8_0.adoc (published version: https://www.keycloak.org/docs/latest/release_notes/index.html)
  • Keycloak, Upgrading Guide, changes in 26.8.0 (source at tag 26.8.0), https://github.com/keycloak/keycloak/blob/26.8.0/docs/documentation/upgrading/topics/changes/changes-26_8_0.adoc
  • Keycloak, Configuring and using token exchange (source at tag 26.8.0), https://github.com/keycloak/keycloak/blob/26.8.0/docs/guides/securing-apps/token-exchange.adoc (published version: https://www.keycloak.org/securing-apps/token-exchange)
  • Keycloak, Enabling and disabling features (server guide, source at tag 26.8.0), https://github.com/keycloak/keycloak/blob/26.8.0/docs/guides/server/features.adoc
  • Keycloak, source tree at tag 26.8.0, https://github.com/keycloak/keycloak/tree/26.8.0
  • IETF, OAuth 2.0 Token Exchange (RFC 8693), 2020, https://datatracker.ietf.org/doc/html/rfc8693

The pattern above, already wired up

Skycloak gives you a managed Keycloak with OIDC and SAML, social and enterprise identity providers, MFA and fine-grained roles configured and running. Pick your framework during onboarding and you get a working sign-in in about three minutes.

Guilliano Molaire
Written by
Founder

Guilliano is the founder of Skycloak and a cloud infrastructure specialist with deep expertise in product development and scaling SaaS products. He discovered Keycloak while consulting on enterprise IAM and built Skycloak to make managed Keycloak accessible to teams of every size.

Start Free Trial Talk to Sales
© 2026 Skycloak. All Rights Reserved. Design by Yasser Soliman