Current Limitation
When a login flow disambiguates between users who share an identifier, the OU selector presents the organization unit handle rather than its display name. The user is asked to choose between values like lsf and ldf instead of LSF Root and LDF.
Handles are slugs intended as stable machine identifiers. At a login screen the person choosing has no reason to know them, and they recognise their organization by its name. The OU's display name exists precisely for this purpose and is what the Console shows everywhere else.
The options come from extractDisambiguationOptions in backend/internal/flow/executor/identifying_executor.go, which builds the ouHandle option set from each candidate's OUHandle.
This is not a one-line change, because of three constraints in the current model:
-
The OU display name is not available to the executor. providers.Entity (backend/pkg/thunderidengine/providers/model.go:730-740) carries OUID and OUHandle but no OU name, so the candidate data the executor works with has no name to show. Producing one requires resolving the OU by ID.
-
Options cannot carry a label distinct from their value. providers.Input.Options is a plain []string (model.go:980), serialized as a flat list of strings. There is currently no way to display LSF Root while submitting lsf.
-
The submitted value has to stay a stable identifier. Candidate filtering matches on the handle (filterUsersByAttributes, case "ouHandle"), and OU display names are not unique. There is no uniqueness constraint on ORGANIZATION_UNIT.NAME (backend/dbscripts/entitydb/sqlite.sql), and OUs under different parents may legitimately share a name. Swapping the name in as the value would be ambiguous as well as fragile, since renaming an OU would change what the flow submits.
So the fix is to separate what is shown from what is sent, rather than to substitute one string for the other.
Reported by a user configuring OU selection at login.
Suggested Improvement
Present the OU display name in the selector while continuing to resolve on a stable identifier.
Suggested scope:
- Extend the input option model so an option can carry a display label alongside its value, and have the flow execution response expose both.
- Make the OU display name available where disambiguation options are built, by resolving it from the OU ID on the candidates.
- Populate the label with the OU display name and keep the handle (or OU ID) as the value, so filtering and resolution are unchanged.
- Have the gate and SDK render the label and submit the value.
Points for whoever picks this up:
- API compatibility.
options is part of the flow execution response consumed by the gate and the SDKs. Changing its shape from []string to objects would break existing clients, so an additive field, or accepting both shapes during a transition, is likely preferable to replacing it.
- Name collisions. Since OU names are not unique, two candidates could present identical labels. Worth deciding on a disambiguating treatment, such as showing the parent or path, or falling back to the handle when labels collide.
- Other attributes. The same prompt can offer
userType and schema attributes as disambiguation options. A label/value split would let those be presented properly too, so the change is worth designing generally rather than special-casing the OU.
Related: #5330, which covers adding user disambiguation to the default flows. This improvement determines how that selector actually reads to an end user, so the two are best considered together.
Current Limitation
When a login flow disambiguates between users who share an identifier, the OU selector presents the organization unit handle rather than its display name. The user is asked to choose between values like
lsfandldfinstead ofLSF RootandLDF.Handles are slugs intended as stable machine identifiers. At a login screen the person choosing has no reason to know them, and they recognise their organization by its name. The OU's display name exists precisely for this purpose and is what the Console shows everywhere else.
The options come from
extractDisambiguationOptionsinbackend/internal/flow/executor/identifying_executor.go, which builds theouHandleoption set from each candidate'sOUHandle.This is not a one-line change, because of three constraints in the current model:
The OU display name is not available to the executor.
providers.Entity(backend/pkg/thunderidengine/providers/model.go:730-740) carriesOUIDandOUHandlebut no OU name, so the candidate data the executor works with has no name to show. Producing one requires resolving the OU by ID.Options cannot carry a label distinct from their value.
providers.Input.Optionsis a plain[]string(model.go:980), serialized as a flat list of strings. There is currently no way to displayLSF Rootwhile submittinglsf.The submitted value has to stay a stable identifier. Candidate filtering matches on the handle (
filterUsersByAttributes,case "ouHandle"), and OU display names are not unique. There is no uniqueness constraint onORGANIZATION_UNIT.NAME(backend/dbscripts/entitydb/sqlite.sql), and OUs under different parents may legitimately share a name. Swapping the name in as the value would be ambiguous as well as fragile, since renaming an OU would change what the flow submits.So the fix is to separate what is shown from what is sent, rather than to substitute one string for the other.
Reported by a user configuring OU selection at login.
Suggested Improvement
Present the OU display name in the selector while continuing to resolve on a stable identifier.
Suggested scope:
Points for whoever picks this up:
optionsis part of the flow execution response consumed by the gate and the SDKs. Changing its shape from[]stringto objects would break existing clients, so an additive field, or accepting both shapes during a transition, is likely preferable to replacing it.userTypeand schema attributes as disambiguation options. A label/value split would let those be presented properly too, so the change is worth designing generally rather than special-casing the OU.Related: #5330, which covers adding user disambiguation to the default flows. This improvement determines how that selector actually reads to an end user, so the two are best considered together.