user-storage artifact split, narrowed: 24.0.0 (and a 25.0.3 Maven Central anomaly)
- Host
- local laptop; Maven container + curl
- Condition
- Narrow the model/storage split to a release (☐ row in both provider-types records)
Why this run existed
2026-08-26-provider-types established that org.keycloak.storage. UserStorageProvider moved out of keycloak-server-spi and changed Maven
artifact — keycloak-model-legacy (≤ 23) → keycloak-model-storage (24+) —
with keycloak-model-legacy gone by 25.0.6. It left the exact boundary open,
bracketed to (23.0.7, 24.0.5]. This run closes the bracket by inspection of
Maven Central coordinates and the published jars.
Environment
| Field | Value |
|---|---|
| Artifacts inspected | keycloak-model-legacy, keycloak-model-storage |
| Versions | 23.0.7, 24.0.0, 24.0.5, 25.0.0–25.0.6 |
| Method | Maven Central directory listing + per-coordinate HTTP status + jar tf for org/keycloak/storage/UserStorageProvider.class |
| Host | local laptop; Maven container + curl |
Findings
Finding 1 — the relocation happens at exactly 24.0.0 ⭐
UserStorageProvider.class moves between artifacts on the 23 → 24 boundary:
| Version | UserStorageProvider.class in keycloak-model-legacy | in keycloak-model-storage |
|---|---|---|
| 23.0.7 | yes | artifact not published |
| 24.0.0 | no | yes |
| 24.0.5 | no | yes |
keycloak-model-storage is first published at 24.0.0, and from that release
keycloak-model-legacy no longer contains the class. So the customer-relevant
break is the 23 → 24 hop: a user-storage provider built against
keycloak-model-legacy keeps its imports (org.keycloak.storage.*, unchanged)
but must change its Maven coordinate to keycloak-model-storage at 24.0.0.
Notably, keycloak-model-legacy is still published at 24.0.x — it just no
longer carries UserStorageProvider, so a 24.x build that still declares the
old coordinate resolves but fails to link the class.
Finding 2 — keycloak-model-legacy is dropped at 25.0.0, but 25.0.3 is a one-off anomaly ⭐
The publish history of keycloak-model-legacy on Maven Central is not a clean
cut. Per-coordinate HTTP checks:
| Version | keycloak-model-storage POM | keycloak-model-legacy POM |
|---|---|---|
| 25.0.2 | 200 | 404 |
| 25.0.3 | 404 | 200 |
| 25.0.4 | 200 | 404 |
keycloak-model-legacy is absent for 25.0.0–25.0.2, reappears at 25.0.3 and
there carries UserStorageProvider.class again (verified by jar tf), then
is gone again from 25.0.4 onward. The mirror image holds for
keycloak-model-storage: published for every 25.0.x except 25.0.3, where it
is missing.
So the two artifacts invert at exactly 25.0.3 — a one-off publishing anomaly in that release. Practical consequences, both worth a line in the assessment:
- a build pinned to
keycloak-model-storage:25.0.3fails with "could not resolve dependency" (404); - a build still declaring
keycloak-model-legacyand bumped to 25.0.3 silently works (200, class present), then fails again at 25.0.4 (404) — the stale coordinate masks the migration for exactly one release and breaks the next.
Finding 3 — the stable end state from 25.0.4
From 25.0.4 onward the state is what the earlier record reported:
keycloak-model-storage published, keycloak-model-legacy gone. The split is
real and permanent at 24.0.0; the 25.0.3 inversion is a transient anomaly, not a
reversal of the move.
Verification
| Claim | Primary source | Checked |
|---|---|---|
keycloak-model-storage first published at 24.0.0 | Maven Central directory listing | ☑ |
UserStorageProvider.class in model-storage (not legacy) from 24.0.0 | jar tf of both artifacts at 23.0.7 / 24.0.0 / 24.0.5 | ☑ |
| model-legacy dropped for 25.0.0–25.0.2 | per-coordinate HTTP 404 | ☑ |
| model-legacy reappears at 25.0.3 carrying the class | HTTP 200 + jar tf | ☑ |
| model-storage missing at 25.0.3 | HTTP 404 | ☑ |
| stable end state from 25.0.4 | model-storage 200, model-legacy 404 | ☑ |
Publishable extract
Your user-federation provider does not change its imports between Keycloak 23 and 24 — it changes its Maven coordinate.
org.keycloak.storage.UserStorageProvidermoved from thekeycloak-model-legacyartifact tokeycloak-model-storageat exactly 24.0.0. The import line is identical; the dependency is not. The old artifact kept publishing through the 24.0.x line but stopped containing the class, so a stale build resolves and then dies at runtime — the worst kind of break.And there is a one-release trap: at Keycloak 25.0.3 the two artifacts inverted on Maven Central —
keycloak-model-storagewas not published (404) andkeycloak-model-legacywas (200, class present), before settling back at 25.0.4. A dependency audit that checks "does the coordinate resolve" rather than "which artifact actually carries the class" misses both halves.