All news

Identity and security

The Keycloak kit: one pinned image, a theme per product

· Toolkit · 2 min read

Diagram: the Keycloak kit feeds Reputo and Leadgener; each adds its own login theme on top of the same pinned image.

Each product signs users in through its own Keycloak, and the toolkit's API packages trust what that Keycloak writes into a token. Reputo and Leadgener used to build from quay.io/keycloak/keycloak:26.0, a tag that moves with every patch, so two builds of one commit could run different Keycloak versions.

What the kit holds, and what it leaves out

On 11 October 2026 we decided that the Keycloak kit would be one base image carrying only what must be the same in every product's Keycloak: Keycloak pinned by digest, jq pinned by checksum, 32 of Keycloak's login messages in Slovenian, and two commands that run inside the container through docker exec.

  • setup provisions what the API reads from a token: the audience, realm roles flattened into a roles claim that ASP.NET reads, and a declared organization_id attribute, which Keycloak 26 would otherwise drop without an error.
  • require-terms makes accepting the terms of use a required action for every user, so Keycloak issues no token until the user accepts them. Only the time of acceptance is stored.

The kit holds no product defaults: realm name, client IDs and origins live in a wrapper in the product, and setup stops before any change, naming each one that is missing. It holds no login theme either, because a theme carries its product's brand on top of the shared design system. The product's Dockerfile builds the theme JAR in an earlier stage, then:

FROM <kit image>:<X.Y.Z>@sha256:<digest>
COPY --from=theme /app/keycloak-theme/dist_keycloak/reputo-keycloak-theme.jar /opt/keycloak/providers/
RUN /opt/keycloak/bin/kc.sh build --db=postgres --health-enabled=true

Tested, pinned, upgraded by choice

Every merge request that changes the kit runs six test suites against the built image. One checks each Slovenian message against the Keycloak inside the image: a key it knows, the same placeholders.

There is no latest tag, and a published version is never overwritten. On 13 October Reputo and Leadgener were pinned to the same version and digest. The changelog flags what a version asks of a product: [keycloak] (back up the database first), [contract] (a command, variable or path changed) or [behaviour] (the realm comes out different). Any Keycloak version change is a major kit version, because Keycloak migrates its database one way. By 13 October the kit had five versions; how the kit was harvested is told in the post on the harvest rule.

For a team building on the toolkit, the identity rules arrive with the image: tokens carry what the API checks, and no token is issued before the terms are accepted. Your login pages and your realm's values stay yours.