High Level Design of Handling Multi-Authoritative Sources and Dynamic Attribute Population in SailPoint ISC

Problem

Understanding SailPoint ISC Identity Profile Priority

When an identity is discovered across multiple authoritative sources, SailPoint ISC uses Identity Profiles to determine which source takes precedence.

  • The Priority Rule: The evaluation order is determined by the priority number configured within the Identity Profiles. A lower priority number signifies a higher evaluation precedence (e.g., Priority 1 is higher than Priority 2).
  • Standard Behaviour: The identity profile with the higher priority (lower number) dictates the mapping configuration used to populate the Identity Attributes on the identity cube.

Diagnosis

The Challenge: The Inactive High-Priority Source

Let’s consider a scenario with two authoritative sources: Authz-A (Priority 1 - High) and Authz-B (Priority 2 - Low).

  1. If an identity has active accounts in both sources, the mapping configurations of Authz-A are automatically used.
  2. If the account in Authz-A becomes disabled or inactive, you might expect ISC to automatically fall back and populate identity attributes from the active Authz-B account.
  3. However, this does not happen automatically. If the identity remains correlated to the Authz-A profile, ISC will continue to evaluate the mappings defined for Authz-A, potentially resulting in stale or missing identity data if that source is no longer updating or providing valid data.

Conversely, if an identity transitions dynamically between profiles via native UI evaluation rules, the attributes will update automatically. But when you need to selectively pull data across both sources while an identity is tied to a specific profile, you must implement a custom solution using SailPoint Transforms.

Solution

Implementing a Master Calculation Transform

Step 1: Create a Custom Identity Attribute

First, define a new identity attribute that will track which source should be considered the active data provider at any given moment.

  • Name: Active Identity Profile (or calculatedActiveSource)
  • Type: String

Step 2: Build the Master Calculation Transform

Create a central transform (e.g., Test - Master - ActiveIdentityProfile) to evaluate the operational state of the accounts across both sources. This transform will inspect account attributes—such as lifecycle status, state, or start/end dates—and return a string indicating the winning source.

Conceptual Transform Logic:

  • Fetch the status/dates from Authz-A.
  • Fetch the status/dates from Authz-B.
  • Evaluate if Authz-A is active. If yes, return “Authz-A”.
  • If Authz-A is inactive and Authz-B is active, return “Authz-B”.

Step 3: Implement Conditional Attribute Transforms

For each identity attribute that needs dynamic population (e.g., Email, Department, Phone), apply a static transform pattern using Apache Velocity to conditionally source the value.

Here is the structural framework for these attribute-level transforms:

{

    "name": "Transform - Dynamic - [AttributeName]",

    "type": "static",

    "attributes": {

        "activeSource": {

            "type": "reference",

            "attributes": {

                "id": "<<Active Identity Profile – Transform Name>>"

            }

        },

        "valueFromSourceA": {

            "type": "accountAttribute",

            "attributes": {

                "sourceName": "Authz-A [Source]",

                "attributeName": "[Corresponding_Attribute_A]"

            }

        },

        "valueFromSourceB": {

            "type": "accountAttribute",

            "attributes": {

                "sourceName": "Authz-B [Source]",

                "attributeName": "[Corresponding_Attribute_B]"

            }

        },

        "value": "#if($activeSource == 'Authz-A')$valueFromSourceA#elseif($activeSource == 'Authz-B')$valueFromSourceB#else$valueFromSourceA#end"

    }

}


How the Logic Works:

1. Variable Declaration: The transform assigns the calculated active source state (from Step 2) to a variable (activeSource), and maps the raw account attribute values from both Authz-A and Authz-B to local variables.

  1. Conditional Evaluation: The Velocity script checks the value of $activeSource.

  2. Dynamic Output: If the master calculation points to Authz-A, it outputs the data from Source A. If it points to Authz-B, it seamlessly pulls the data from Source B, ensuring the identity record remains accurate and up-to-date even when the primary source goes dark.

Important Considerations: Handling Multiple Accounts

While the standard accountAttribute transform works perfectly for identities with a single account on a target source, you need to exercise caution when dealing with identities that possess multiple accounts on the same source.

The Default Behavior Risk

By default, if an identity has multiple accounts on the designated source, the accountAttribute transform will automatically default to pulling data from the oldest account (based on the account creation date). If your business logic expects data from the “active” or most recent account, this default behavior can lead to silent failures and data mismatch issues without throwing explicit errors.

Best Practice: Use Filtering and Sorting

To ensure your transform is robust and deterministically selects the correct account, leverage SailPoint’s built-in filtering and sorting attributes within your transform configuration:

  • accountFilter / accountPropertyFilter: Use these to narrow down the account selection based on specific criteria (e.g., targeting only accounts where status == “active”).
  • accountSortAttribute: Define the specific attribute to sort the accounts by (e.g., created or lastLogin).
  • accountSortDescending: A boolean flag (true/false) that allows you to control the sort order, ensuring you can reliably grab the newest or most relevant account.

Enhanced Transform Example

Here is how you can safeguard your transform configuration to handle multi-account scenarios safely:

{

  "type": "accountAttribute",

  "attributes": {

    "sourceName": "Authz-A [Source]",

    "attributeName": "[Corresponding_Attribute_A]",

    "accountFilter": "status == \"active\"",

    "accountSortAttribute": "created",

    "accountSortDescending": true

  }

}

Conclusion

While SailPoint ISC offers robust out-of-the-box identity profiling capabilities, complex multi-source lifecycles sometimes require finer data control. By leveraging a master evaluation transform alongside conditional static transforms, you can ensure that your identity cubes reflect real-world account states accurately without manual intervention.

Hello Rohit, nice article and the overall approach makes sense.

Small correction suggestion on the reference transform sample. The current example uses:

"activeSource": {
  "type": "reference",
  "attributes": {
    "name": "<<Active Identity Profile – Transform Name>>"
  }
}

For a SailPoint reference transform, the referenced transform should be passed under attributes.id, not attributes.name. So the sample should be:

"activeSource": {
  "type": "reference",
  "attributes": {
    "id": "<<Active Identity Profile – Transform Name>>"
  }
}

The official SailPoint reference transform docs mention that the target transform name must be specified in the attributes.id key. Without that change, anyone copying this sample may run into transform evaluation issues. The concept is useful, so this looks like a quick syntax correction rather than a design problem.

One more small suggestion for the accountAttribute examples. The KB uses:

{
  "type": "accountAttribute",
  "attributes": {
    "sourceName": "Authz-A [Source]",
    "attributeName": "[Corresponding_Attribute_A]"
  }
}

This works fine if the identity has only one account on that source. But if the identity has multiple accounts on the same source, the accountAttribute transform defaults to the oldest account by creation date.

For this use case, where you’re trying to read from the “active” account, it would be safer to add filtering or sorting. The docs support accountFilter, accountPropertyFilter, accountSortAttribute, and accountSortDescending for exactly this scenario.

The approach is solid, but that note would help prevent silent failures when identities have multiple accounts on the authoritative source.

Hello,

I have made the required changes in the sample transform where “name” is replaced with “id” for reference transform.

Thanks for pointing that out.

Regards,

Rohit Wekhande.

1 Like

Done! I considerations that I made was when a user has only 1 account in authz source. But, as per your suggestions, I have also added the scenario when user has multiple accounts in Authz Source.