Skip to main content

ADR 0008: The startupos-services client replaces the shared service client

  • Status: accepted, in progress
  • Date: 2026-11-07
  • Decision makers: the project owner, as recorded in the Keycloak fix plan

Context and problem statement​

All eight services used one Keycloak client, startupos-backend, for client-credentials calls. Its secret needed to be replaced with a generated one that exists only in the cluster. How should that happen without a window in which a service cannot get a token?

Decision drivers​

  • No downtime at any step.
  • Evidence of retirement without printing a secret.
  • Avoid enabling a preview feature on the identity provider of a live system.

Considered options​

  • Rotate the secret in place.
  • Enable the preview client-secret rotation executor.
  • A blue/green swap: create a new client with a generated secret, move services over, then retire the old client.

Decision outcome​

A blue/green swap. A new confidential client, startupos-services, has a generated secret stored in the Secret startupos-oidc-client and read by every service through secretKeyRef. The realm script refuses to use the repository default on a non-local URL, and a flagless re-run cannot re-enable the retired client. Services move over one at a time. The old client stays enabled until the last service has moved, and is then disabled and its secret regenerated or the client deleted.

Consequences​

  • Good: the rehearsal showed zero failures on old and new credentials during cutover, and the retired client refused even its own secret.
  • Bad: until the old client is retired, both clients are enabled.

Confirmation​

When complete: each Deployment's QUARKUS_OIDC_CLIENT_ID is startupos-services, and a client-credentials request for the old client is refused.

Sources​

docs/runbooks/keycloak-client-secret-rotation.md, docs/runbooks/keycloak-fix-final-report.md, .agents/tasks/keycloak-fix/plan.md, live read on 2026-11-07.