How do you keep Backstage catalog ownership in step with Keycloak?
To keep Backstage catalog ownership in step with Keycloak, you populate the catalog's users and groups from the same Keycloak realm that already holds your workforce identities, then point each component's owner at a group that Keycloak maintains. Sign-in and org data are separate concerns in Backstage. Sign-in proves who a person is when they open the portal, while org data decides which users and groups exist in the catalog and which team owns each service. This section covers the supported method for importing Keycloak users and groups described in the Backstage integrations documentation. Before you write the setup, confirm the exact Keycloak catalog module or entity provider name, its package, and its configuration keys against the current Backstage integrations documentation. Do not rely on a module name from a blog post or an older guide, because the name and keys are what your configuration file must match exactly.
The design decisions come before the configuration. Decide which Keycloak realm and which group tree are the source of truth for ownership, and whether teams are modeled as Keycloak groups, subgroups or client roles. Decide how often the catalog re-reads Keycloak and how a user removed from Keycloak is handled: whether their entity is deleted, kept as an orphan, or reassigned. Check that group names in Keycloak are stable enough to appear in owner fields, because renaming a group can break ownership references across many catalog entries. Also confirm which Keycloak attributes you need, such as email and display name, and whether the service account used to read Keycloak has only the read permissions the import requires.
DeployOpen plans and implements this work in your own infrastructure, including the Keycloak realm configuration, the Backstage catalog settings, the sign-in resolver that maps Keycloak identities to catalog users, and verification that a sample service shows the owner you expect after a sync. We also document the realm and group model so your identity team can change groups without breaking the portal. Because the Keycloak and Backstage releases you run will determine which module names and keys apply, we confirm them against your target versions before any change is made. Scope, deliverables and timelines are agreed in writing before work starts.
What must be in place before you connect Keycloak to Backstage
Connecting Keycloak as a source of org data only works when the identity side is stable first. The cards below cover the running identity provider, the realm model, the Backstage release line, the service account, the network path and the people who own the group model.
Self-hosted Keycloak with a supported database
Confirm Keycloak runs in production on a supported database, not the default dev-file database, which Keycloak documents as for development only. Supported production options include PostgreSQL 14 to 18, MariaDB, MySQL, Microsoft SQL Server, Oracle Database and Azure SQL. Decide the high availability design now, because both supported multi-site designs need a synchronously replicated database. Catalog ownership depends on this server being up, so treat it as a production dependency.
Realm with users and groups
Create or select the realm that holds your workforce users and the groups that mirror your org structure, such as teams, departments and business units. Backstage will read these groups to set ownership, so group names should describe real reporting lines rather than access roles. Decide whether groups are flat or nested, because that choice shapes how Backstage Group entities relate to each other. Users without a group cannot own anything in the catalog.
Supported Backstage release line
Run Backstage on a release line that the versioning policy currently supports, and confirm the Node.js versions that release line accepts in that policy before you install anything. The policy has supported two adjacent even-numbered Node.js releases, and the matching pair changes between releases. Pin your Node.js version to the one the policy lists for your Backstage line, so the module you add for Keycloak builds against the same toolchain.
Service client with read-only directory access
Create a confidential client in Keycloak that the Backstage backend uses to read users and groups, separate from the client used for sign-in. Grant it only the view permissions the chosen module needs, and check the module documentation for the exact scopes and roles it requires. Creating this client needs a Keycloak administrator role on the realm, so confirm who will perform that step. Store the client secret in your secrets manager, never in the repository.
Network path and trusted TLS
Confirm the Backstage backend can reach the Keycloak base URL over the network path your security team approves, including any proxy, firewall rule or private DNS entry. The backend must trust the certificate chain Keycloak presents, so add your internal certificate authority to the Node.js trust store if needed. Test the connection from the same host and container image that runs Backstage, because a successful test from a laptop proves little.
Named owner for the group model
Assign one accountable person or team to own the Keycloak group structure that Backstage will read. This owner approves new groups, decides when a team is renamed or merged, and answers when a catalog owner looks wrong. Without a named owner, group changes in the identity provider silently change catalog ownership, and nobody is responsible for fixing the drift. Document the owner and the change process before the first sync runs.
Why sign-in resolvers and org data must agree
Signing a user in and loading that user into the catalog are two separate jobs, and they must resolve to the same identity. Sign-in answers who is logging into the portal right now. Org data import answers which users and groups exist and which teams own which components. The Backstage authentication documentation advises configuring sign-in resolvers so that every provider resolves to the same identity. For this topic, that means the Keycloak sign-in resolver and the Keycloak-sourced catalog User entity must point to one canonical user reference. Decide that reference before go-live, typically the Keycloak username or a stable identifier, and confirm with your team which attribute Backstage uses for it in your configuration.
When the two paths disagree, the symptoms are predictable. A user signs in through Keycloak, but the session is attached to a User entity that the org import never created, so the person owns nothing and sees no team pages. Or the same person appears twice, once from a sign-in that created a user record and once from the import, and ownership fields on components point at one copy while the other copy holds the team membership. Both problems surface as ownership gaps during catalog reviews or as access decisions that look wrong to the user. Illustratively, if a team lead's group membership is updated in Keycloak but the sign-in resolver maps her to a differently named user, her new team permissions will not apply to the entities she signs in to manage.
The authentication documentation also advises against offering guest access in production. A guest identity is not tied to any record in your identity provider, so it cannot match a catalog owner, and it weakens the audit trail that ownership is meant to support. Treat guest access as a development convenience only, and confirm during testing that every production sign-in path requires a Keycloak login that resolves to a catalog entity. Before you finish the design, test one user from each Keycloak group end to end, and check that the signed-in identity, the User entity and the group memberships shown in the catalog all describe the same person.
How to configure Keycloak org data in Backstage, step by step
This sequence connects Backstage to Keycloak as a source of users and groups, so catalog ownership follows the same directory that handles sign-in. It produces a read-only integration, a scheduled ingestion, and a verified link between Keycloak groups and the owner fields on catalog components.
Create a read-only Keycloak service client
A Keycloak administrator creates a dedicated confidential client in the realm that holds your users and groups, then grants it only the read roles for users and groups that the Keycloak server administration guide documents. Use a client separate from the one Backstage uses for sign-in, so each credential can be rotated or revoked on its own. Done means a token request for this client succeeds from the Backstage backend host, a test call that lists users returns results, and a write attempt is refused.
Store the client secret in your secrets manager
Place the client secret in the secrets store your organization already operates, such as the vault or cloud secret manager used for other backend credentials. Expose it to the Backstage backend as an injected environment value, and keep it out of app-config.yaml files committed to Git. Limit read access to the Backstage runtime identity and to the people who rotate the secret. Done means the secret does not appear in the repository or in logged configuration, and the backend starts with the value resolved from the store.
Add the Keycloak provider to the backend
Add the Keycloak catalog entity provider module that your Backstage release documents, install it with the package manager the project uses, and register it in the catalog plugin setup of the backend. Take every configuration key, package name and option from the Keycloak section of the Backstage catalog documentation for your version, and check them against the release notes, because keys change between releases. Done means the backend builds and starts, and the startup log shows the provider registered without errors.
Set user and group filters and the schedule
Limit ingestion to the realm and to the groups that own services, and choose which Keycloak attributes populate display name, email and group membership. Set the ingestion frequency and timeout using the options in the same documentation, starting with a conservative interval that the directory team agrees to. Keep the schedule off until the verification steps pass. Done means the configuration passes the backend config check and the group filter values match the groups you reviewed in Keycloak.
Confirm the sign-in resolver maps identities
Review the Keycloak sign-in provider and its resolver so a user who signs in resolves to the User entity created by ingestion. Match on an attribute that your realm enforces as unique, such as username or email. The Backstage authentication documentation advises that every provider resolve to the same identity and that guest access stay off in production. Done means signing in as a test Keycloak user lands on the existing catalog user record, no duplicate user appears, and guest access is disabled.
Run one ingestion and inspect entities
Trigger a single ingestion run, using a manual refresh in the catalog or a backend restart if your setup ingests at startup, and watch the backend logs for the provider's run summary. Open the catalog and confirm that each expected Keycloak user appears as a User entity and each group appears as a Group entity, with members, parent group and profile fields populated. Done means the counts match the filtered Keycloak scope, and no entity shows an ingestion error or a missing owner.
Verify group ownership on a sample component
Pick one component whose catalog-info file names a Keycloak group as its owner, then open its entity page. Confirm the owner field resolves to the Group entity and that the group's members appear as the people responsible for it. Next, remove a test user from that group in Keycloak, run ingestion, and confirm the membership change appears in the catalog. Done means the owner link resolves and the membership change is reflected, which is your evidence that the catalog matches the identity provider.
Turn on the ingestion schedule
Enable the recurring schedule you configured earlier, and record who owns it, when the Keycloak client secret is due for rotation, and how to disable the schedule during an incident. Watch the first scheduled runs in the logs to confirm they finish without errors and that no users or groups are removed unexpectedly. Done means two consecutive scheduled runs complete cleanly and the catalog reflects the Keycloak changes you tested in the previous step.
Which Keycloak attributes map to which Backstage catalog fields
This table compares each Keycloak user and group attribute with the Backstage User or Group field it populates, and notes when the default mapping should change. Confirm every default in the documentation for the module you choose, since the mapping depends on that module's configuration. The main takeaway is that ownership only matches the identity provider if group paths and disabled-user handling are decided before the first ingestion run.
| Keycloak source | Backstage target | When to change the mapping |
|---|---|---|
| Username | User entity metadata name, used as the reference in spec.memberOf and owner fields | Change it if usernames contain characters that are awkward in entity references, or if your naming standard uses a different stable identifier. |
| User entity spec.profile.email | Change it when Keycloak emails are unverified or shared, since the catalog will display them to every signed-in user. | |
| First and last name (display name) | User entity spec.profile.displayName | Map a different attribute if your directory stores a preferred display name in a custom user attribute. |
| Custom user attribute (for example, a team code) | No default target; requires a custom transformer or a mapped field | Flag every custom attribute for a transformer decision, and confirm in the module documentation how it is read and where it is stored. |
| Group path (for example, /engineering/payments) | Group entity metadata name and spec.type, with the full path normalized into a valid entity name | Change the normalization when two groups share a leaf name in different parents, otherwise they may collide in the catalog. |
| Nested groups (parent and child) | Child Group entity sets spec.parent to the parent group, and the parent lists it in spec.children | Review the hierarchy before ingestion, because a flattened or restructured Keycloak tree produces a different ownership chain. |
| Group membership | User entity spec.memberOf lists each group the user belongs to | Confirm whether direct membership only or inherited membership is imported, since this determines how ownership resolves for members of subgroups. |
| Realm roles | No default catalog field; usually not imported as Group entities | Map roles to groups only when a team owns resources by role, and confirm the module supports it before planning a custom transformer. |
| Disabled Keycloak users | Confirm whether the entity is removed, left in place or flagged; the default behavior depends on the module and its schedule | Decide the policy before go-live so owners who leave do not keep ownership of catalog entities indefinitely. |
| Deleted Keycloak users and groups | Removed from the catalog on a later ingestion run if the module is configured to remove orphaned entities | Confirm the removal setting, and plan how entities owned by a deleted user are reassigned. |
How to secure the Keycloak and Backstage connection
The Keycloak connection carries two kinds of access: a service account that reads users and groups into the catalog, and sign-in flows that decide who can enter the portal. The cards below cover the controls that keep both narrow, traceable and consistent with the identity provider, so ownership in the catalog stays trustworthy.
Least-privilege service client
Create a dedicated Keycloak client for catalog ingestion with read-only access, limited to the realm and the groups in scope for the catalog. Confirm which realm roles and client scopes the ingestion account needs, and remove anything it does not read. A service client that can write users or change group membership turns a catalog bug into an identity change. Verify the granted permissions with a test run before the first scheduled ingestion.
Secret storage and rotation
Keep the client secret out of the Backstage configuration files and inject it at runtime from your secrets manager or Kubernetes secret store. Restrict read access to the Backstage backend workload only. Agree a rotation procedure with the team that owns the Keycloak realm, and confirm how Backstage picks up a rotated secret, since a restart may be required. Record who can read the secret and when it last changed.
TLS and the certificate trust chain
Serve Keycloak over HTTPS and set the public hostname correctly so tokens and metadata point at the right address. Backstage must trust the certificate chain of the Keycloak endpoint it calls, which often means adding an internal certificate authority to the Node.js trust store used by the backend. Follow the production configuration guide for hostname and TLS settings, and test the connection from the Backstage runtime, not from an administrator workstation.
No guest access and strict sign-in resolvers
Disable guest sign-in in production and configure sign-in resolvers so each Keycloak identity maps to exactly one catalog user. A resolver should reject identities that match no catalog entry, rather than creating a new user or falling back to a generic identity. Test with an account that exists in Keycloak but not in the catalog, and confirm that sign-in fails with a clear error. Unmatched identities must be refused, not admitted.
Audit logging of ingestion and sign-in
Confirm what each component logs before relying on it as evidence. Check whether the Backstage backend records catalog ingestion runs, including counts of users and groups added, changed or removed, and whether Keycloak admin and login events are enabled and retained in your log platform. Ingestion logs should identify the service client, and sign-in logs should show which resolver accepted each identity. Agree the retention period with your security team.
Separate service and admin accounts
Keep the ingestion service client apart from human administrator accounts in Keycloak. Administrators should use named accounts with multi-factor authentication, and the service client should never be used to log in to the admin console or to make manual changes. Review who holds realm administration rights, and confirm that changes to the service client itself are logged and approved. This separation keeps audit trails readable and limits the impact of a stolen credential.
How to test org data before it drives ownership
Start in a test environment with a copied Keycloak realm. This stage is about whether the ingestion logic reads the right users and groups at all, and it is the cheapest place to find attribute mapping mistakes, missing group filters and sign-in resolver conflicts. Use a copy that contains representative accounts, including some you know are disabled, so you can see how the catalog treats them. Do not point this stage at the live realm.
- User count against Keycloak: Compare the number of users the catalog ingests with the number Keycloak returns for the same realm and filter. Any gap should be explained before you continue.
- Group membership spot checks: Pick a handful of users with known group memberships and confirm the catalog Group entities and parent relationships match what the Keycloak admin console shows.
- Disabled user handling: Disable a test account in the copied realm, run ingestion, and confirm the catalog behaves the way your policy requires.
- Sign-in resolution: Sign in as a test user and confirm the session resolves to the expected catalog User entity, not a duplicate or a guest identity.
- Group change propagation: Add and remove a user from a group in the copied realm, then confirm the change appears after the next scheduled run.
Ask your identity team to define the acceptance criteria for each check before testing begins, including what counts as an acceptable gap.
Staging should resemble production in group structure, realm size and sign-in configuration, but it should not hold production identities. The goal here is to surface problems that only appear with real nesting depth, large group counts and the full set of sign-in paths your users rely on. Run the same checks as the test environment, then add the checks that depend on scale and structure.
- User count against Keycloak: Repeat the count comparison against the staging realm, including service and non-human accounts if your catalog is meant to include them.
- Nested group spot checks: Verify that users inherited through parent or child groups appear under the groups your model expects.
- Disabled and removed users: Confirm that accounts disabled or removed in staging leave the catalog in the way your offboarding process assumes.
- Sign-in resolution across paths: Test every sign-in method you plan to enable, and confirm each resolves to the same catalog User.
- Ownership check on a sample Component: Choose a Component that a known team owns, confirm its owner reference points to the expected Group, and confirm the team's members can see it in the portal.
Record the run times and any errors, because these become the baseline you compare against during production monitoring. Confirm the scale expectations with your platform team before you rely on them.
The production cutover is the point where catalog ownership starts to follow the identity provider. Treat it as a controlled change with a rollback path, not as a routine ingestion run. Keep the previous ownership data available until the first scheduled runs have completed and your reviewers have signed off on the results.
- Pre-cutover count and sample: Capture the production user and group counts from Keycloak and the catalog before the change, so you can compare them after the first run.
- Group membership spot checks: Review a sample of teams whose ownership matters most to incident response, and confirm their members and groups are correct.
- Disabled user review: Confirm that accounts disabled in production are handled as agreed, and that no active owner is left without a valid catalog User.
- Live sign-in test: Sign in with accounts from several groups and confirm each resolves to the expected catalog User entity.
- Change and ownership check: Add a test user to a group in a controlled way, confirm the change after the next run, then reverse it, and check the ownership of a sample Component.
Document who approved each check and keep the evidence, since it will be needed when auditors ask how ownership was validated. Confirm your rollback steps with the team that operates the portal before the change window opens.
Why Keycloak users or groups are missing or duplicated in the catalog
This table maps the symptoms teams see when Keycloak org data does not match the catalog to their most likely causes and fixes. Read each row against your own logs and configuration, and confirm log messages and configuration keys against the Backstage and Keycloak documentation for your versions before changing anything. The main takeaway is that most mismatches trace back to the service account's permissions, the entity references used at sign-in, or ingestion that runs less often than group membership changes.
| Symptom | Likely cause | Fix |
|---|---|---|
| No users loaded into the catalog | The service client used for ingestion lacks the read permissions needed to list users, or it points at the wrong realm. | Confirm the client's service account roles and the realm name in the provider config, then rerun ingestion and check the backend logs for authorization errors. |
| Groups load but have no members | Membership is not included in the query, or a filter excludes the users inside the groups. | Check that group membership is requested by the provider and review user filters so they do not exclude group members. Verify against one known group. |
| Duplicate users appear after first sign-in | The sign-in resolver builds a user entity reference that does not match the one created by ingestion, so Backstage creates a second entity. | Align the resolver's entity reference with the ingestion naming, such as the username or email attribute used by both. Remove the duplicate and confirm one entity per person. |
| Signed-in user has no catalog entity | Ingestion has not run since the user was created, or a filter excludes that user from the import. | Trigger a manual ingestion run, confirm the user matches the filter, and check the schedule. Confirm the expected behavior for the sign-in resolver in the authentication docs. |
| TLS errors between the Backstage backend and Keycloak | The certificate chain for the Keycloak endpoint is incomplete or signed by an internal CA that the backend does not trust. | Install the full chain, including the internal CA, in the backend's trust store, and confirm the base URL uses the expected hostname. Test the connection from the backend host before rerunning ingestion. |
| Ownership is stale after a group move | The ingestion schedule is longer than the rate of group changes, or ingestion fails without raising a visible error. | Shorten the schedule to match how often groups change, and set up alerts on ingestion failures. Confirm the failure signal in your logs and metrics before relying on it. |
What buyers ask before connecting Keycloak org data to Backstage
How much effort does connecting Keycloak org data to Backstage take?
The effort depends mainly on the quality of your group model, not on Backstage itself. The main drivers are how cleanly your groups map to teams and owners, how many Keycloak realms hold users and groups, whether you need custom user attributes such as cost centers or manager links, and how many sign-in resolvers must agree with the org data. A flat group model with one realm and standard attributes is a small job. Several realms, nested groups and attributes that exist only in an HR feed add design and testing work. Ask any partner to show how each driver changes the written scope before you compare offers.
Can our team do this integration without outside help?
Yes, if you already run Keycloak and Backstage and can own two things: a Keycloak service client that lets Backstage read users and groups, and a configuration change in the Backstage backend. Decide the group model first, because it determines which Keycloak groups become Backstage groups and which entities own which systems. Teams that skip that step usually rework the catalog after the first import. An outside partner adds most value in the group design, the resolver review and the test plan, which are the parts that are hard to undo later.
What do we need to provide for the work?
Plan for four inputs. First, administrative access to the Keycloak realm that will be read, so a service client and its permissions can be created and reviewed. Second, a named owner for the group model who can say which Keycloak group represents each team and who approves changes. Third, a test realm or staging Keycloak with sample users, so mapping can be checked without touching production identities. Fourth, a written sign-off on the attribute mapping, including which fields reach the catalog and which stay out. Missing any of these usually delays the sign-off stage rather than the build.
Must sign-in and org data come from the same identity provider?
No. Keycloak can serve both sign-in and org data, and that is the simplest pairing, but the two functions are configured separately. The important rule is that the Backstage sign-in resolver must map each authenticated user to the same catalog user that the org data import created. If sign-in comes from a different provider than the catalog import, the resolver logic has to match the identifiers on both sides, such as username or email. Mismatched identifiers create duplicate users or orphaned ownership, so test one user from sign-in through to catalog ownership before rollout.
Can Keycloak replace Entra ID or LDAP as our directory?
That is a design decision, not a default outcome. Keycloak can federate users from existing directories and can also hold users directly, so it may act as a broker or as a primary store. Whether it should replace Entra ID or an LDAP directory depends on where your joiner and leaver process lives, which systems depend on that directory, and who administers accounts today. Before committing, document the source of truth for each user and group, the sync direction and the owner of each attribute. Moving the directory itself is a separate migration project with its own risk review.
What happens when a Keycloak group is renamed or moved?
The catalog reflects the group as it exists at the next import, so renaming or moving a group changes which entities it owns after synchronization. Stable identifiers matter here. If Backstage references groups by a display name that someone can edit, a rename can orphan ownership or assign systems to the wrong team. Agree on which identifier the catalog uses, and define a review step for moves between parent groups. Test a rename in staging so you know how the catalog responds before a reorganization reaches production.
How does DeployOpen scope this work?
DeployOpen plans and implements this work under a written, fixed-scope plan. The plan states the Keycloak realm and Backstage components in scope, the group and attribute mapping, the sign-in resolver changes, the test cases and the deliverables, agreed before work starts. Ongoing support, upgrades and continuous testing are available as separate retainers. DeployOpen does not publish a price list, so a quote follows from the written scope. Ask for the list of drivers behind the quote, so you can see which decisions move cost and timing.
How DeployOpen scopes and delivers Backstage and Keycloak org data
DeployOpen is a Chainscore Labs company that plans, implements, integrates, hardens, documents and supports self-hosted open-source platforms inside your own infrastructure. For Backstage and Keycloak org data, we start from the identity model your organization already uses, then connect Keycloak users and groups to the Backstage catalog so ownership matches the identity provider.
How we scope
- Inventory which Keycloak realms, groups and client roles should become catalog users and groups, and which should stay out.
- Agree how sign-in resolvers will map each Keycloak identity to a single catalog user before any build work starts.
- Record the written scope, deliverables and timeline together, since most engagements are fixed-scope.
How we build
- Configure the Keycloak connection for org data with a dedicated service account that has read-only access to users and groups.
- Set the ingestion schedule and group mapping, then test that group membership produces the expected ownership on sample entities.
- Verify that sign-in and org data resolve to the same identity, and that guest access is disabled in the production configuration.
How we hand over
- Document the realm, client and group mappings, the service account, and the ingestion settings in your own repository.
- Walk your platform, identity and catalog owners through the ownership model and the steps for adding a new group.
- Provide a test checklist covering sign-in, catalog users, group membership and entity ownership for future upgrades.
How we support
- Offer ongoing support, Backstage and Keycloak upgrades and continuous testing as a retainer if your team wants it.
- Plan Backstage version bumps and Keycloak upgrades together, reviewing the org data configuration against each release.
- Confirm with your identity team how Keycloak release changes and the Operator approval mode will be handled in your environment.

