Migrating Cloud Foundry UAA to Keycloak: The Playbook

Guilliano Molaire Guilliano Molaire 9 min read

Last updated: June 2026

TL;DR

If your apps authenticate against Cloud Foundry UAA and your platform team is moving off Tanzu, you can recreate every UAA behavior your applications depend on in Keycloak. The short version:

  • UAA’s clock is ticking. Broadcom replaced the open-source UAA component with a proprietary “Tanzu UAA” in Tanzu Platform for Cloud Foundry 10.2 and renamed the platform to Elastic Application Runtime in the 10.3 release. If you are leaving the platform, the identity layer leaves with it.
  • The concept mapping is clean. Identity zones become realms, UAA clients become Keycloak clients, scopes become client scopes, and authorities become roles. The table below covers every mapping you need.
  • Tokens are the real migration. Your apps do not care about your architecture diagram. They care that user_name and authorities are exactly where they were yesterday. Keycloak protocol mappers can reproduce the UAA token shape almost claim for claim.
  • Passwords need a decision. UAA stores bcrypt hashes and Keycloak defaults to Argon2, so pick between migrate-on-first-login federation, a hash-import extension, or a staged reset. We compare all three below.
  • Do not big-bang it. Run both IdPs in parallel and move apps in waves. Keycloak is the OIDC and SAML provider; UAA keeps serving the stragglers until the last wave lands.

We run managed Keycloak for teams doing exactly this kind of migration, so this playbook is the same one we walk customers through.

Why UAA exits are happening now

The User Account and Authentication service (UAA) has been the identity engine of Cloud Foundry for over a decade. It still works. So why are migration tickets suddenly showing up in every platform team’s backlog?

Because the platform underneath it is changing fast. Since the Broadcom acquisition of VMware closed in late 2023, the Tanzu line has been repriced, repackaged, and renamed. In the 10.2 release, Broadcom swapped the open-source UAA component for a proprietary build called Tanzu UAA, per the official release notes. In 2026 the platform itself was renamed to Elastic Application Runtime, per Broadcom’s component naming notice. Enterprises reading those tea leaves are moving workloads to Kubernetes platforms like Azure Red Hat OpenShift (ARO), and UAA does not make that trip.

The destination most teams pick is Keycloak: open source, CNCF, speaks OIDC and SAML natively, and currently on the 26.6 line (26.6.3 shipped June 2026). The catch is that a decade of apps grew up assuming UAA’s specific token shapes and quirks. That is what this playbook solves.

How do UAA concepts map to Keycloak?

Almost one to one, which is the good news that makes the rest of the migration tractable. Here is the mapping we use:

UAA concept Keycloak equivalent Notes
Identity zone Realm One zone = one realm. The default zone maps to a dedicated realm, not to Keycloak’s master.
Client (/oauth/clients) Client Confidential vs public carries over. Grant types map to Keycloak flow toggles.
Scope Client scope Dotted names like cloud_controller.read are valid Keycloak client scope names. Keep them identical.
Authority (client) Service account role UAA authorities on a client become realm or client roles on the Keycloak service account.
Group (SCIM group) Group or realm role If apps read it from scope, model it as a client scope or role. If it is organizational, use a group.
User (SCIM user) User UAA exposes SCIM, which makes export scripting pleasant.
Origin key (ldap, saml providers) Identity provider / user federation UAA origin becomes a Keycloak IdP alias or federation provider.
signup_redirect_url, login branding Realm themes and client settings Cosmetic, but plan for it or someone will notice on day one.

Two things deserve a closer look before you script anything: token validity and grant types. UAA sets access_token_validity and refresh_token_validity per client. Keycloak does the same through per-client advanced settings that override realm defaults. Audit every UAA client’s validity values now, because apps have silent assumptions about them (“the batch job refreshes every 11 hours because the token lives 12”).

Reproducing UAA token claims in Keycloak

This is the heart of the migration, so let’s be blunt: if you get the claim mapping right, the migration is boring. If you get it wrong, every app team opens an incident the morning of cutover.

A UAA access token carries claims your apps have been reading for years:

{
  "jti": "8f1c2…",
  "sub": "f7d3a1e2-…",
  "user_name": "jdoe",
  "user_id": "f7d3a1e2-…",
  "origin": "ldap",
  "client_id": "orders-service",
  "cid": "orders-service",
  "authorities": ["orders.admin", "uaa.user"],
  "scope": ["openid", "cloud_controller.read"],
  "zid": "uaa",
  "grant_type": "authorization_code",
  "aud": ["openid", "cloud_controller", "orders"]
}

One precision before you copy that into a test: the example above is a composite for illustration. In real UAA, user access tokens carry scope, while authorities shows up on client_credentials tokens. Map both, but test them against the right grant type.

Keycloak emits sub, scope, aud, azp, and friends out of the box, but user_name, authorities, origin, zid, and cid are UAA dialect. You recreate each with a protocol mapper:

  • user_name: a User Property mapper on username, token claim name user_name. Spring Security OAuth-era resource servers read this constantly.
  • authorities: a User Realm Role (or Client Role) mapper with token claim name authorities, multivalued, added to the access token. Model each UAA authority string as a role with the identical dotted name.
  • cid and client_id: hardcoded-style mappers exist, but the cleaner route is a Client ID mapper writing to both claim names. Some legacy middleware reads cid, some reads client_id, and you will find out which only by looking.
  • origin and zid: hardcoded claim mappers per realm (for zid) and per identity-provider-sourced user attribute (for origin). Most apps never read these; verify before you bother.

Mappers script cleanly, so put them in your migration pipeline rather than clicking them together. Creating the user_name mapper on a client with kcadm.sh:

kcadm.sh create clients/$CLIENT_UUID/protocol-mappers/models -r orders-realm 
  -s name=uaa-user-name 
  -s protocol=openid-connect 
  -s protocolMapper=oidc-usermodel-property-mapper 
  -s 'config."user.attribute"=username' 
  -s 'config."claim.name"=user_name' 
  -s 'config."jsonType.label"=String' 
  -s 'config."access.token.claim"=true'

The verification step matters more than the mapping step. Decode a real UAA token and a candidate Keycloak token side by side and diff the claims. Our free JWT token analyzer exists for exactly this kind of A/B inspection, and it runs entirely in your browser so no token leaves your machine.

One structural difference you cannot mapper away: UAA puts scope-derived entries into aud, while Keycloak builds aud from audience mappers and client scopes. Decide the target audience contract per resource server, then enforce it with dedicated Audience mappers. Sloppy audiences are how you end up with tokens that work everywhere, which is just a polite phrase for tokens that are unsafe everywhere.

Exporting UAA config and importing it into Keycloak

UAA’s saving grace is that everything is reachable from the uaac CLI and plain REST. The export side of the pipeline:

# clients, paginated JSON
uaac clients > uaa-clients.txt
# or raw: GET /oauth/clients with an admin token

# users and groups via SCIM
uaac curl "/Users?count=500&startIndex=1" > users-page1.json
uaac curl "/Groups?count=500" > groups.json

# signing keys currently in rotation
uaac curl /token_keys > token-keys.json

On the Keycloak side you have three import paths, and we recommend them in this order:

  1. Realm JSON + partial import for clients, client scopes, roles, and mappers. Generate the realm representation from your UAA export with a script, review it in git, and import it through the admin console or kcadm.sh create partialImport. Declarative, reviewable, repeatable.
  2. kcadm.sh for the long tail. Per-client tweaks, validity overrides, and service-account role grants script cleanly against the admin CLI.
  3. SCIM-to-SCIM for users, with care. Keycloak 26.6 added a SCIM 2.0 API as a preview feature, and community SCIM extensions are mature. For one-time bulk loads, transforming UAA SCIM JSON into Keycloak’s user import format is usually simpler than wiring live SCIM.

Whatever you script, make it idempotent. You will run it more than once. Nobody ever ran an IAM migration script exactly one time, and the people who claim otherwise are not the people who operated the cutover.

What about passwords?

The awkward part. UAA stores bcrypt hashes. Keycloak has defaulted to Argon2 since version 24 and does not ship a bcrypt provider in core, so you cannot just paste hashes across. Three options, in the order we recommend them:

  1. Migrate on first login. Stand up a thin user storage federation provider that validates the user’s first Keycloak login against UAA (or against the exported bcrypt hash), then writes the password natively into Keycloak. Users never notice. The shim retires when the trickle stops.
  2. Import hashes with a bcrypt extension. Community password-hash providers add bcrypt support to Keycloak, letting you import UAA hashes directly and let Keycloak rehash to Argon2 on each user’s next successful login. Solid choice when the UAA database is available offline.
  3. Staged reset. Export users without credentials and trigger reset-password emails per migration wave. Honest, simple, and occasionally the right call for small user bases, but it converts your migration into a customer-facing event. Avoid for workforce SSO where users are already federated from LDAP or SAML anyway.

That last clause is worth repeating: if most UAA users actually came from an upstream LDAP or SAML origin, you do not migrate passwords at all. You recreate the federation in Keycloak and the upstream source keeps owning credentials.

The cutover: dual-run beats big-bang

We have yet to meet a 50-plus-app estate that survived a single-weekend IdP cutover with its change advisory board’s dignity intact. The pattern that works is dual-run:

  1. Stand up Keycloak beside UAA. Same user source of truth, token mappings verified per the section above.
  2. Rank apps into waves. Easy first: stateless OIDC apps with library-managed discovery. Hard last: anything reading authorities from opaque tokens through /check_token style introspection.
  3. Move one wave, watch, move the next. Each app flips its issuer URL, client ID, and secret. Rollback per app is a config revert, not a platform event.
  4. Keep UAA read-only at the end. Freeze client and user writes once the final wave lands, hold UAA warm for a rollback window, then decommission.

The week-one failures are predictable, so test for them up front: clock-skew on token validation, introspection endpoints (UAA’s /check_token semantics differ from Keycloak’s RFC 7662 introspection), refresh token rotation behavior, and CORS settings on the new issuer. None of them are hard. All of them are pager-noise if discovered in production.

Frequently asked questions

Can Keycloak fully replace Cloud Foundry UAA?

Yes. Keycloak covers UAA’s OAuth2, OIDC, and SAML duties, maps identity zones to realms and scopes to client scopes, and reproduces UAA’s token claims through protocol mappers. The pieces needing real work are password hash migration and apps that depend on UAA-specific introspection behavior.

Does Keycloak support UAA’s token format?

Not by default, but protocol mappers close the gap. Claims like user_name, authorities, cid, and origin are UAA dialect and must be recreated explicitly. Decode tokens from both systems and diff them with a JWT analyzer until the contract matches what your apps actually read.

How long does a UAA to Keycloak migration take?

The Keycloak build and claim mapping is days of work. The calendar time is the app waves: small estates land in a few weeks, while a 100-app enterprise estate typically runs one to two quarters of dual-run, dominated by app-team coordination rather than identity engineering.

Can I migrate UAA passwords into Keycloak?

Directly only with a bcrypt extension, since Keycloak defaults to Argon2 and does not ship bcrypt in core. Most teams choose migrate-on-first-login federation instead, and estates where users federate from LDAP or SAML skip password migration entirely because the upstream keeps owning credentials.

The part nobody budgets for

The claim mapping takes a sprint. The thing that actually consumes a quarter is operating two identity providers in parallel while running migration waves, which means HA, patching, monitoring, and backups for a brand-new Keycloak estate at exactly the moment your team is busiest.

That part is outsourceable. Skycloak runs hardened, highly available Keycloak with the upgrades and the on-call handled, so your team spends the migration quarter migrating apps instead of babysitting the new IdP. If you are staring down a UAA exit, talk to us and we will sanity-check your wave plan for free.

Guilliano Molaire
Written by Guilliano Molaire Founder

Guilliano is the founder of Skycloak and a cloud infrastructure specialist with deep expertise in product development and scaling SaaS products. He discovered Keycloak while consulting on enterprise IAM and built Skycloak to make managed Keycloak accessible to teams of every size.

Ready to simplify your authentication?

Deploy production-ready Keycloak in minutes. Unlimited users, flat pricing, no SSO tax.

© 2026 Skycloak. All Rights Reserved. Design by Yasser Soliman