Last updated: July 2026
TL;DR
Federate when the legacy store is still the source of truth and you cannot move it yet. Migrate when you can, because federation trades a migration project for a permanent runtime dependency: someone else’s database is now in your login path, and their maintenance window is your outage. The short version:
- Federation is a deferral, not a decision. A User Storage SPI lets you adopt Keycloak without moving a single user record. It also means every login depends on a system another team patches on their own schedule.
- The user cache will not save you. Keycloak caches user lookups, not credential validation. Password logins hit the upstream on every attempt, so an upstream outage is a login outage even with a warm cache.
- Timeouts are the whole ballgame. A federated provider with no query timeout does not fail one login, it exhausts request threads and takes the realm down with it.
- Import mode is the escape hatch. Copying users local on first lookup, then upgrading credentials on login, turns a permanent dependency into a migration that runs itself.
- Know your exit condition up front. If you cannot name the metric that says the SPI is safe to delete, you did not choose federation, you postponed the choice.
This is the decision post, not the build guide. For the code, see how to build a custom UserStorageProvider and our Keycloak SPI development guide.
Should you federate or migrate your legacy user store?
Federate if the legacy store is still authoritative, owned by someone else, or holds data you cannot yet reproduce. Migrate if you can get a clean export and own the write path, spending project time now instead of paying an availability tax forever. Most teams land in the middle, which is fine, as long as it is a choice with an end date.
Here is the honest comparison:
| Situation | Federate | Migrate |
|---|---|---|
| Legacy app still writes users | Yes | No |
| Another team owns the store | Yes, cautiously | Best long-term goal |
| Passwords are hashed with something Keycloak supports (bcrypt, PBKDF2, Argon2) | Optional | Yes, bulk import and be done |
| Passwords are a proprietary or unknown hash | Yes, this is the classic case | Only with a forced reset |
| Store holds authz data (permissions, tenants) too | Yes, at first | Split the concerns first |
| Upstream has a real SLA and change process | Yes | Later |
| Upstream patches on their own schedule, at will | Treat as high risk | Prioritize the migration |
| You need Keycloak live next quarter | Yes | Rarely realistic |
The one row that decides more architectures than any other is the password hash. If Keycloak understands the hash, or you can accept a reset campaign, migration is a weekend and a script. If the hash is proprietary, homegrown, or locked in a stored procedure nobody has read since 2011, you cannot bulk import credentials. Federation stops being a preference. That is the fork.
The mistake is treating that fork as permanent. Federation is how you get Keycloak into production without a migration project. It is not how you should still be running in three years.
What does federating a legacy store actually buy you?
Three things, and they are genuinely worth having.
No big-bang migration. Point a User Storage SPI at the legacy store and users authenticate through Keycloak on day one, against credentials that never moved. No export, no hash conversion, no forced reset email to 400,000 people.
Gradual cutover. With import mode on, each user is copied into Keycloak’s local store the first time they are looked up. Pair that with credential upgrade on login and the migration runs itself, paid for by ordinary traffic instead of a change window.
The legacy store stays right. If a legacy console, HR feed, or provisioning job still writes users, you do not have to freeze it or dual-write to it. It stays the source of truth until you are ready for it not to be.
That last point is where it gets interesting, because the store rarely holds just accounts. In one large European retail group running Keycloak as its primary auth service, the federated Oracle stack carries accounts and the per-store, per-tenant permission model. The SPI is not just answering “does this password match”, it feeds the data that shapes tokens. If that sounds familiar, read token and claims modeling for a legacy IdP next.
What does it cost you?
One thing, and it is not small: you moved a system you do not control into your login critical path.
Every architecture diagram draws federation as a tidy sidecar. In production it is a hard runtime dependency. Keycloak’s availability is now bounded by the upstream store, its network path, its connection pool, and the change calendar of whichever team owns it. You did not avoid the migration risk. You converted it into availability risk, spread across every day of the year.
Here is the part that surprises people, because the docs make it sound solved: the user cache does not protect credential validation. The cache stores user lookups (getUserByUsername, attributes, group membership). Password validation is a separate path through CredentialInputValidator.isValid(), and it hits your provider on every login attempt. A warm cache plus an unreachable Oracle instance still equals zero logins. Cache policy tunes read load, it is not a high-availability strategy.
Why do upstream maintenance windows become login outages?
Because the upstream team is patching a database, not an authentication system, and nobody told them their maintenance window is now your login path. Federation makes their routine change your incident.
Not hypothetical. From a senior IAM engineer at a large European retail group, describing exactly this setup:
“Multiple times in a year, they have some patching, upgrading that is causing us outages… during this patching time we saw outages, like we could clearly see logging fails due to the timeouts. So for us, that is a single point of failure.”
Sit with the detail in the middle: logging fails due to the timeouts. That is the signature. Not a clean error, not a fast rejection. Requests hang until something gives up. And retail traffic peaks at store opening, so the failures land when the login rate is highest.
The mechanics matter, because the blast radius is wider than the federated users:
- Upstream starts patching. Connections stall rather than refuse.
- Federated logins block, waiting on a query with a generous timeout, or no timeout at all.
- Each blocked login holds a Keycloak request thread.
- Threads run out.
- Now every login fails, including the local users and the brokered ones that never touched Oracle.
One team’s Tuesday night patch takes down authentication for the whole realm. Not because Keycloak is fragile, but because an unbounded call in a request thread is a shared-fate bug.
How do you de-risk a federated user store?
You cannot make someone else’s database highly available from inside Keycloak. You can contain the failure so it stays small, fast, and local to the users who actually depend on the upstream.
Set timeouts that are shorter than your patience
The highest-value change, and the one most often skipped. A federated provider must fail fast. If your SPI talks to Oracle over JDBC, bound every layer:
# Oracle JDBC, on the DataSource your provider builds
oracle.net.CONNECT_TIMEOUT=3000
oracle.jdbc.ReadTimeout=5000
Bound the statement too. A connection that is up but a database that is busy is exactly the patch-window scenario:
statement.setQueryTimeout(3); // seconds, not minutes
Cap the connection pool too. An unbounded pool under a stalled upstream is just a slower way to exhaust threads. A federated login that fails in three seconds is a bad login. One that hangs for sixty is an outage.
Use cache policy for load, and know its limits
Set the provider’s cache policy deliberately in the admin console (DEFAULT, EVICT_DAILY, EVICT_WEEKLY, MAX_LIFESPAN, or NO_CACHE). MAX_LIFESPAN with a sane value keeps lookup traffic off the upstream and cuts the calls that can hang during a window.
Just do not confuse it with resilience. It reduces exposure, it does not remove the credential call. Say that out loud in the design review so nobody leaves thinking the cache is the mitigation.
Break the circuit and degrade on purpose
Keycloak does not ship a circuit breaker for your SPI, so you build it or you inherit the pile-up. Wrap upstream calls (Resilience4j is the usual pick), trip the breaker after a short run of timeouts, and while it is open, fail federated lookups immediately instead of queueing them.
Then decide what “degraded” means before the incident, not during it:
- Users already imported locally, with local credentials, keep logging in. The strongest argument for import mode.
- Federated-only users get a fast, honest failure and a status page, not a spinner.
- Admin and break-glass accounts live locally, always. If your admins are federated, an upstream outage also locks you out of fixing it.
That is the real win: an upstream outage should degrade to “users who still live upstream cannot log in”, not “authentication is down”.
Choose read-only unless you truly need writes
If your provider does not implement the write interfaces, federated users are read-only and Keycloak will not push changes upstream. That is usually correct. A writable store doubles the failure surface (their outage now breaks profile updates and registrations too) and makes the legacy schema a constraint on your roadmap.
What does the exit path look like?
Sync, then cut over, then delete the SPI. The mechanism is import mode plus credential upgrade on login. What makes it real is a number you agree on in advance.
Turn on import. The built-in LDAP provider has an Import Users toggle. A custom provider gets equivalent behavior through ImportedUserValidation, so the first successful lookup writes a local copy into Keycloak’s database. Now the read path has a local answer.
Upgrade credentials on first successful login. When the upstream validates a password, you hold the plaintext for exactly that moment. Write it to Keycloak’s local credential store with a modern hash, and that user’s next login never touches the upstream. This is the step that turns federation into migration, and the custom provider guide covers it.
Watch the ratio, not the calendar. Track the percentage of logins still resolving against the upstream. It should fall on its own. When it flattens, you have found your tail: seasonal users, dormant accounts, service accounts nobody claims.
Sweep the tail deliberately. The tail never migrates by itself. Export what is left, force a reset for accounts you cannot carry, and let dead ones expire. Do not keep a runtime dependency open for users who have not logged in since 2023.
Then delete the SPI. You are done when upstream-resolved logins hit zero for a full business cycle, every remaining user has local credentials, and the authz data the store fed you has a new home. If that last one is not true, you are not migrating users anymore. You are migrating a permission model, which is its own project.
Cutting over a large estate rather than one store? The wave-based approach in our dual-run IAM migration post is the sibling to this one.
FAQ
Can Keycloak federate an Oracle database directly?
Not out of the box. Keycloak ships built-in federation for LDAP and Active Directory only. Any relational store, Oracle included, needs a custom UserStorageProvider that you build and deploy as a JAR. That is the SPI everything in this post is about.
Does the Keycloak user cache keep logins working if the upstream store is down?
No. The cache holds user lookups, not credential validation. Password checks call your provider on every attempt, so if the upstream is unreachable, federated logins fail regardless of cache state. Only users with locally stored credentials (via import plus credential upgrade) keep authenticating.
What happens to federated users if the external store goes offline permanently?
Users that were never imported effectively disappear: Keycloak cannot resolve them, so lookups and logins fail. Imported users still exist locally, but any attribute Keycloak did not copy is gone. This is the strongest reason to enable import from day one rather than “later”.
How do we migrate users whose passwords use a proprietary hash?
Federate, then upgrade on login. Your provider validates against the legacy hash, and on success you write a modern hash into Keycloak’s local credential store. Users migrate silently as they log in. The accounts that never log in get a reset or get retired.
How do we know when we can delete the SPI?
When upstream-resolved logins sit at zero across a full business cycle (that catches quarterly and seasonal users), every remaining account has local credentials, and any authorization data the store provided has a new home. Track that login ratio from day one.
The honest summary
Federation is a good answer to a real constraint. It gets Keycloak into production without a migration project and moves users at the speed of ordinary traffic. That is worth a lot.
Just be clear-eyed about what you signed. You did not remove risk, you rescheduled it: from one scary weekend into a dependency that is live every day, owned by someone whose patch calendar you do not control. So bound it. Fast timeouts, a real circuit breaker, local break-glass accounts, import on from day one, and a login-ratio metric with a date attached. Then file the delete-the-SPI ticket while you still remember why you wrote it.
We run managed Keycloak for teams doing exactly this, and the timeout conversation is usually the shortest, most useful hour of the engagement.