Why Backstage sign-in resolvers decide who you trust as a catalog user
A sign-in resolver takes a login that your identity provider has already verified and turns it into a Backstage identity tied to a catalog User entity. That step decides which people Backstage treats as known users, which groups and ownership relationships they inherit, and what they can see or change. Treat the choice of resolver as an access control decision, not a login detail. If you already have an identity provider such as Okta, Microsoft Entra ID, Keycloak, GitHub or GitLab, the question to answer first is which catalog User each verified person should map to, and what should happen when no match exists.
The Backstage authentication documentation advises configuring sign-in resolvers so that every provider resolves to the same identity. This matters when your organization offers more than one sign-in method, for example a corporate directory for employees and a source control login for contractors. If two providers can create two different identities for the same person, ownership, permissions and audit records split across them. Plan the mapping before you enable a second provider, and confirm in your own environment that each provider's user identifier, such as an email address or a provider-specific user ID, is stable and unique enough to match against your catalog.
The same documentation advises against offering guest access in production. A guest sign-in gives people an identity without a verified connection to your directory or catalog, which is the wrong default for a system that holds ownership data and software templates. Before go-live, list every sign-in path your Backstage instance exposes, confirm that none of them creates an unmatched identity by default, and record who approved each one. Your sign-in design should also say what happens when a verified user has no catalog entity, because that case determines whether your portal admits strangers or stops them at the door.
What goes wrong when a resolver is too permissive
A sign-in resolver decides which catalog identity a successful login becomes, so a loose rule can grant one person another person's access. The cards below cover the failure modes we see most often in review, and each one is a setting or behavior you can check in your own configuration today.
Users with no catalog entity
If a resolver can issue a session for a user who has no matching catalog entity, that person signs in with an identity Backstage cannot tie to an owner, group or permission. Check whether your resolvers throw an error when nothing matches, or whether a fallback quietly creates a user. Confirm that unmatched logins are rejected and that guest access is off for production, as the authentication documentation advises.
Attributes users can change
A resolver that matches on a display name, a free-text profile field or any value a user can edit in the identity provider lets that user claim another catalog identity. Review which claim each resolver reads and who can write to it in your directory. Prefer stable, administrator-controlled identifiers such as a verified email or a provider user ID, and confirm the provider only issues the claim after verification.
Email domains outside the organization
Accepting any email address that a provider returns can admit people from partner or consumer domains if the provider allows them to sign in. The allowedDomains setting limits which domains a provider may use. Check that the list contains only domains your organization controls, and that a domain change is reviewed like any other access change.
Conflicting identities across providers
When one person signs in through two providers, each can resolve to a different catalog user, which splits ownership and permissions across two records. Decide which provider is authoritative for each person, then align resolvers so every provider lands on the same entity. Test with one account per provider and confirm both logins show the same user.
Resolver order that hides errors
Resolvers run in the order you list them, and a permissive fallback placed early can match before a stricter resolver runs. Review the resolver list in each provider block and confirm that the strictest match comes first and that a NotFoundError from every resolver ends the sign-in. Verify the result with a test user who has no catalog entity.
How the built-in email and annotation resolvers match users
Backstage's built-in resolvers take the identity a provider returns and look for a matching user entity in the software catalog. The two families to understand are email-based matching, which compares the email claim from the provider with the email on a catalog User entity, and annotation-based matching, which looks for a provider identifier stored on the catalog entity itself. Email matching needs little setup, but it only works if the catalog email is accurate and the provider reports the same address. Annotation matching is more exact, but it requires every catalog user to carry the provider's identifier, so an entity that was created by hand or imported from another source may simply not have it. In both cases, a failed match means no catalog user is found, and the sign-in fails rather than falling back to a guess.
Each resolver fails in a different way, and those failures should be planned before rollout. Email matching fails when a person has several addresses, changes name or domain, or when a provider returns an alias. It can also match the wrong person if a catalog entry carries an address that has been reassigned. Annotation matching fails silently when the identifier is missing or stale, so a user who was reachable yesterday may be locked out after an import. The allowedDomains setting restricts which email domains the sign-in flow accepts, which narrows who can get through at all, but it does not confirm that the person is the catalog user you expect. Treat it as a first filter, not as proof of identity.
Confirm the exact resolver names, the configuration keys under the sign-in provider block, and how allowedDomains interacts with each provider against the Backstage authentication documentation for the version you run, because these details have changed across releases. Then test with a sample of real accounts from each provider, including a user without a catalog entity, and record which resolver matched each one.
Resolver options and when each fits
This table compares the main ways Backstage can map a signed-in identity to a catalog user, from the built-in email and annotation resolvers to custom code and the NotFoundError path. Read each row for what identifies the user, what the catalog must contain, where the approach fails, and the setup it suits. The main takeaway is that a resolver is only as strict as the catalog data and domain checks behind it.
| Option | What identifies the user | What the catalog must contain | Main abuse or failure risk | Typical fit |
|---|---|---|---|---|
| Built-in email resolver | Email address returned by the identity provider | A User entity whose email matches the provider address exactly | Email claims that are unverified or belong to a different tenant, so allowedDomains must be set | Single identity provider where emails are verified and organization-owned |
| Annotation resolver | A stable identifier passed through a provider-specific annotation, such as a user ID | A User entity carrying the matching annotation, usually populated by ingestion | Entities without the annotation silently fail to match, and stale annotations can point at the wrong person | Providers where email is mutable or missing and a durable ID is available |
| Chained resolver order | Tries each resolver in the configured sequence until one succeeds | Entities that satisfy at least one of the chained methods | A looser resolver placed first can match before a stricter one is tried | Mixed populations where most users match by one key and a fallback covers the rest |
| Custom resolver | Whatever your code reads from the provider profile or token claims | Whatever your code queries, such as a catalog lookup by a verified claim | Bugs in custom logic can grant identity to the wrong user, so it needs review and tests | Requirements the built-in resolvers cannot express, with an owner who maintains it |
| NotFoundError path | No catalog user is found for the signed-in identity | Nothing, because the sign-in is refused | Users who authenticate but lack an entity may be turned away or, if handled loosely, signed in without an entity | Default stance for production, so access depends on a catalog entry existing |
| Guest or unmatched sign-in | No verified identity is required | Nothing | Anyone reaching the portal gets an identity that the catalog does not govern | Local development only, not production |
Configure a resolver order that cannot be abused
This sequence turns sign-in from a permissive login into a controlled match: every accepted identity maps to one existing catalog User, and anything else is refused. Each step ends with a check you can repeat after every configuration change.
Inventory catalog user entities and identifiers
Before touching configuration, export the User entities your catalog already holds and list which identifiers each one carries: the email in spec.profile, the annotations that name a provider user ID, and the Group memberships. Ask the team that owns your identity provider which claims it issues for each user, including whether email is verified. The step is done when you can show, for a sample of real users, which identifier links each person to a catalog entry and where any gaps are. Gaps you find here are the cases the resolver order must handle deliberately.
Choose the primary matching attribute
Pick one attribute that identifies a person uniquely and that your identity provider controls, such as a verified work email or a stable provider user ID. Avoid display names and free-text fields, because any user can change them. Record the choice in the configuration review with the reason it cannot be edited by the user. The step closes when the team agrees on one primary attribute and knows which catalog field carries it for every User entity.
Set allowedDomains for the provider
Set the allowedDomains list in the sign-in provider configuration to the email domains your organization controls, and confirm the list with the team that owns DNS and the identity provider. This setting rejects sign-ins whose email domain is not on the list before any resolver runs, so an account from an unlisted domain never reaches catalog matching. The step is done when a test sign-in from an account on an unlisted domain is refused at the provider layer and the refusal appears in the backend logs.
Add resolvers in order with a deliberate fallback
List the resolvers in the order you intend them to run, usually the most specific identifier first and the email match second, and write down what each one does when it finds nothing. Keep the fallback narrow: a fallback that creates or guesses a user is the main route to account takeover. Have a second engineer review the list against the inventory from the first step. The step closes when the reviewed order is committed to version control and every resolver has a written outcome for a match, a miss and an error.
Decide how NotFoundError is handled
When no resolver matches, the sign-in must fail with a NotFoundError rather than issue a token for an unknown identity. Confirm that your version of the sign-in code surfaces this error to the user as a refusal, and that the message gives the user a route to ask for access without revealing catalog contents. Ask your engineers to confirm the exact behavior in the release you run, because resolver handling changes between versions. The step is done when a user with no catalog entry is refused and the refusal is logged with the provider and identifier used.
Disable guest access for production
Remove or disable the guest sign-in provider in the production configuration, and confirm that no environment variable or Helm value re-enables it. The Backstage authentication documentation advises against offering guest access in production, so this check belongs in the deployment pipeline as well as the initial setup. The step is done when a production sign-in page shows only the organization's identity providers and a guest login attempt returns no session.
Test with an account that has no catalog entity
Sign in with a valid account from an allowed domain that has no User entity in the catalog. Expected result: the sign-in is refused with the NotFoundError path, no session is created, and no User entity is written. Repeat with an account whose email matches a catalog user but whose provider identifier does not, to confirm that the email fallback does not bind a different identity. Record both results in the change ticket. The step closes when both tests produce the refusal you wrote down in the resolver review.
Test with an account from an unlisted domain
Sign in with an account from a domain outside allowedDomains, ideally one that uses the same provider but a different tenant or a personal address if your provider permits it. Expected result: the sign-in is refused before resolver matching and no catalog entity is read or changed. Check the backend logs to confirm the refusal reason. Repeat this test after every change to the provider configuration or the resolver list. The step is done when the refusal is reproducible and the logs show the domain check, not a resolver failure.
When a custom resolver is justified and what it must prove
Write a custom sign-in resolver only when the built-in resolvers cannot match a provider's identity to a catalog user without guessing. The usual reasons are a non-standard claim that carries the user's identity, a user directory whose records do not line up with the catalog's email or annotation fields, or a requirement to refuse sign-in for anyone who has no catalog entity. Before writing one, check whether a documented resolver, a different claim, or a corrected catalog annotation solves the problem, because every custom resolver becomes code your team must keep working through each Backstage upgrade. Confirm the current custom resolver API and its return types against the Backstage authentication documentation for the release you run, since the signatures have changed across versions.
A custom resolver must prove four things. First, matching is deterministic: the same identity always resolves to the same catalog entity, and a failed lookup never falls back to a looser match such as a partial name. Second, the resolver keys on values the identity provider controls and users cannot edit, such as a verified subject identifier or a claim issued by the provider, and never on a display name, a free-text profile field, or an email the user has not verified. Third, when no entity exists, the resolver rejects the sign-in explicitly, normally by throwing a NotFoundError, rather than issuing a token with a guessed or empty identity. Fourth, each of these branches has a test: one for a unique match, one for no match, one for multiple matches, and one for an attempt to use an editable field. Ask your team to keep these tests in the repository so that an upgrade cannot quietly weaken them.
Security and operational checks for resolver configuration
A resolver is only as safe as the catalog data and configuration behind it. The checks below cover who controls the User entities that matching depends on, how rejected sign-ins are seen, and how resolver settings stay consistent as providers change and Backstage is upgraded.
Catalog ownership of User entities
Resolvers match a sign-in to a User entity, so whoever can create or change those entities can decide who a sign-in becomes. Confirm which team owns the User descriptors and that they come from your identity directory or a reviewed source, not from ad hoc files. Check that no sign-in path can create a user entity that a resolver will then trust. Ask whether your ingestion source can be edited by people outside that owner group.
Write access to matching YAML
Catalog YAML that carries emails, annotations such as user IDs, or memberships feeds the matching step. Restrict edit rights on those repositories and branches, require review for changes, and log who merged them. Treat a change that adds or alters an email or user-ID annotation as a sign-in change, not a catalog cleanup. Confirm this review path covers every source that writes User entities.
Logging of rejected sign-ins
A failed resolver match is often the first visible sign of a misconfigured provider or an attempted misuse. Confirm which sign-in failures your deployment logs, where those logs go, and who reviews them. Alert on spikes in rejections for one provider and on repeated attempts from the same domain. Verify that log entries do not record tokens or other secrets.
Review after provider changes
Changing an OAuth app, a tenant, a domain, or an identity provider can alter the claims a resolver receives, such as the email format or the subject value. Re-test sign-in for each affected provider after any such change, using a test account that maps to a known User entity. Record the expected result so a later reviewer can see whether behavior moved.
Consistent resolvers across providers
The Backstage authentication documentation advises that every provider resolves to the same identity. Compare resolver order, allowed domains, and fallback behavior across all configured providers in one review, so a weaker resolver on one provider does not become the easy path into the portal. Keep the configuration in one place and review diffs for each provider together.
Stay on a supported release line
Resolver code and provider modules change between Backstage releases, so security fixes matter here as well. The versioning policy says high and critical severity vulnerabilities will be backported to releases from the last 6 months where feasible. Plan upgrades so your deployment stays on a supported release line, and retest sign-in after each upgrade.
Questions teams ask about Backstage sign-in resolvers
Can our team configure Backstage sign-in resolvers without outside help?
Yes, a team with Backstage and identity provider experience can configure resolvers, but the work is mostly decisions rather than code. Your engineers need to decide which claim identifies a person (email, provider user ID or an annotation), which domains may sign in, and what happens when no catalog entity matches. Those decisions depend on how your identity provider stores users and how your catalog is maintained. Teams that already run the catalog and know their identity provider usually finish the core configuration in-house. Outside help tends to add value when several providers must resolve to one identity, or when a custom resolver is needed. The Backstage authentication documentation at Backstage: Authentication is the starting point for either path.
What drives the effort of a sign-in resolver project?
The main drivers are the number of identity providers, the quality of your catalog data, and whether custom logic is required. Each provider adds its own redirect configuration, scopes, and resolver behavior that must be tested. Catalog quality matters because a resolver can only match a user to an entity that exists and carries the expected email or annotation. If user entities are missing, stale or duplicated, the cleanup often takes more time than the resolver itself. Custom resolvers add design, code review and test cases for every edge case, such as users with several emails or accounts that move between departments. Ask any provider to break the quote into providers, catalog cleanup, custom logic and testing.
What do we need to provide for a resolver engagement?
You need to provide read access to your catalog user and group data, admin access or a named contact for each identity provider, and test accounts that represent each kind of user. Test accounts should include a regular employee, a contractor, a user whose email domain differs from the company domain, and a user with no catalog entity. Your team should also confirm which email domains are allowed to sign in and who approves changes to that list. If your organization imports users from a directory, know which system is the source of truth before the work starts. Ask the provider to list these inputs in the written scope so that delays caused by missing access are visible early.
How long does a sign-in resolver project take?
The duration depends on the scope, so no general figure applies. The main inputs are the number of providers, the state of your catalog user data, whether a custom resolver is needed, and how quickly your identity provider administrators can make changes and run tests. Fixed-scope work at DeployOpen is agreed in writing before it starts, and the timeline is part of that written scope. Ask for the sequence of milestones, the dependencies on your teams, and the test evidence delivered at each step. Be cautious about any timeline given before someone has reviewed your provider setup and catalog contents.
Is guest access ever acceptable for Backstage in production?
In general, guest access should not be offered in production. The Backstage authentication documentation advises against it, because a guest sign-in does not tie the visitor to an identity your organization controls, which weakens audit trails and access decisions. Guest access can still be useful in a local development or demo environment, as long as that environment is separated from production data. If a team wants a read-only public view, that is a design choice that should be made explicitly, reviewed by security, and built with the same resolver and permission discipline as any other access. Confirm the policy with your security team before the configuration reaches production.
What changes when we add another identity provider later?
Adding a provider means a new authentication module configuration, a new redirect URI and client registration, and a decision about how its users map to existing catalog entities. The resolver order matters: a new provider can match users differently from the ones already in use, so a user could end up with two identities if the matching keys are not aligned. Each new provider should be tested with the same account types used in the original setup, and existing sign-in flows should be checked for regressions. Plan for the catalog to be reviewed as well, because providers that carry different identifiers may need annotations or user data added to entities. Treat the addition as a change with its own review and rollback steps.
Why does signing in users without catalog entities create risk?
A sign-in that succeeds without a matching catalog entity can grant a user access without any record of who they are or which team they belong to, which makes ownership and permission decisions unreliable. Attackers who control or obtain an account at an allowed provider may then reach the portal with no approved identity behind it. Safer designs reject unmatched users with a clear error, or create entities only through a reviewed process such as an identity import. The Backstage documentation describes resolver behavior and the NotFoundError pattern that leads to rejection. Confirm with your security team which behavior is acceptable before the resolver ships.
How DeployOpen works on this
DeployOpen scopes resolver work as a written, fixed-scope engagement that starts from your identity providers and your catalog data. We build and test resolvers against the sign-in paths your users actually take, then hand over configuration, tests and runbooks your team can operate.
How we scope
- Inventory every identity provider, its user identifiers and which users must have a matching catalog entity.
- Confirm the allowedDomains list, resolver order and whether any user may sign in without a catalog entity.
- Agree in writing whether guest access is excluded from production and how exceptions are approved.
How we build
- Configure built-in resolvers per provider and write custom resolvers only where the built-in ones cannot match identities safely.
- Test sign-in with matched, unmatched and mismatched accounts, confirming that unknown users are rejected with NotFoundError.
- Review resolver code against the Backstage authentication documentation before anything reaches a production environment.
How we hand over
- Deliver resolver configuration, test cases and a record of the identity mapping rules in your repository.
- Document how each provider resolves to the same catalog identity, with a walkthrough for your platform team.
- Run a handover session so your engineers can add a provider or change a resolver without introducing new exposure.
How we support
- Review resolver changes during Backstage upgrades, since sign-in code often changes with @backstage package versions.
- Offer ongoing support, upgrades and continuous testing as a retainer after the initial engagement.
- Retest sign-in paths when identity providers change their claims, group formats or domain settings.

