Files
infra-keycloak/k8s/keycloak
Stéphane Tailland c1eaead5d2 Declare the Catalogue agent as a Keycloak client
First of the six agents to need an identity. It exchanges the end user's
token for one narrowly-scoped token per MCP server, so `azp` names the
agent while `sub` stays the human — which is what makes the audit trail
able to answer "which agent asked, on whose behalf".

Deliberately narrower than the librechat client it is modelled on:

  * no browser flow at all. standardFlowEnabled, implicitFlow and
    directAccessGrants are off, because the agent never logs a user in —
    it receives an already-issued token over A2A. Any of those three
    would be a way to obtain a token it has no business obtaining.
  * no service account. It has no standing access of its own; everything
    it can reach, it reaches on behalf of a user who asked.
  * two optional scopes, mcp-catalog-audience and mcp-sales-audience, and
    nothing else. librechat carries all of them because it fronts every
    domain; an agent serving the product manager must not be able to mint
    a payments token.

Adds classic-models-agent-catalogue-audience, the scope whoever issues
the user's token requests so the agent appears in that token's audience.
Keycloak's Standard Token Exchange refuses otherwise, with "Client is not
within the token audience" — which reads as a permissions problem on the
target rather than a missing audience on the source.

Verified against the running realm: catalog and sales exchange
successfully and return aud=[mcp-catalog] / aud=[mcp-sales] with
azp=classic-models-agent-catalogue, while payments is refused with
invalid_scope. The confinement is enforced by Keycloak, not by the
agent's own restraint.

Note this file is a bootstrap seed, not the live realm: Keycloak starts
with --import-realm under IGNORE_EXISTING and logs "Realm
'classic-models' already exists. Import skipped", so editing it changes
nothing on a restart. The client and scope were created through the admin
API and recorded here so a fresh install matches. That divergence is
worth closing separately.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 08:57:50 +02:00
..