Commit Graph

5 Commits

Author SHA1 Message Date
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
Stéphane Tailland aac85b2f7a Update of classic models realm config 2026-08-23 17:22:57 +02:00
Stéphane Tailland cf456f10a1 fix(realm): Persist client secret and realm CaC 2026-08-23 15:54:16 +02:00
Stéphane Tailland d5242f68ca fix(secrets): Update kong-token-exchange-broker secret to match Vault/ExternalSecret 2026-08-23 08:05:23 +02:00
Stéphane Tailland 08200a7df0 feat(k8s): Add Keycloak 26.6.0 with PostgreSQL 16 and classic-models realm CaC 2026-08-23 07:40:40 +02:00