Skip to main content

Practical examples

Configuring and using the anchor property

  1. Configure the anchor property in the data model.

Configure the Data Model by adding an 8objectDetail to the user object (or the corresponding object). Add the following line:

<objectDetail name="AnchorProperty" value="$.id"/>

$.id points to the id field in the response from the target system.

note

If your target system returns the UUID under a different field name (for example: userId), adjust accordingly:

<objectDetail name="AnchorProperty" value="$.userId"/>

  1. Verify the external anchor is stored.

After creating the user, verify that the external anchor was saved correctly. For example, in the execution log:

External anchor: 1101aa88-8f22-4033-8485-30a0536cef5e

confirms that the anchor property was correctly captured and stored by Omada (the id field in the response: 1101aa88-8f22-4033-8485-30a0536cef5e).

  1. Use the JobAnchor in task mappings.

To use the saved JobAnchor in subsequent tasks (for example, when adding the user to a group), configure the task mapping using the following expression:

Extensions.GetFirstValue(ROPE_DistinguishedName, ROPE_AccountExternalAnchor, JobAnchor)

This expression will return the first non-null value among the available options:

  • from the imported ROPE_DistinguishedName.
  • from the ROPE_AccountExternalAnchor already stored.
  • from the JobAnchor of the current provisioning job.

This ensures that the mapping will work regardless of whether the user information comes from a previous import or from the current provisioning task.


Configuring ResultValuesJsonPath

ResultValuesJsonPath is used when the response from the target system wraps the actual user object inside another property - for example, inside an array or a nested object. By configuring the correct JSONPath, Omada knows where to find the relevant user information (such as the user ID) to complete the provisioning flow.

Example: The target system returns the following response after creating a new user:

In this case, the actual user data is inside the newUsers array, and not directly at the root of the response. If you do not configure anything, Omada will not be able to locate the userId.

  1. Configure ResultValuesJsonPath.

Add the following setting to the data model:

<objectDetail name="ResultValuesJsonPath" value="$.newUsers[0]"/>

ResultValuesJsonPath tells Omada to navigate inside the newUsers array and pick the first object ([0]). After that, Omada will treat this object as the "root" for finding fields like userId, uri, email, and other.

  1. When correctly configured, the execution log will now display the information properly:

PATCH does not perform reconciliation, while PUT does.

PUT with reconciliation: When using PUT as the update method, you can enable reconciliation to ensure that fields not explicitly mapped in your task mapping are preserved. This is configured by adding the following lines in your Data Model:

<objectDetail name="VerbForUpdate" value="PUT"/>
<objectDetail name="ReconcileOnUpdate" value="True"/>

Reconciliation

Omada first performs a GET on the target system to retrieve the full object. An example of a GET request:

GET https://abc4120.id.cyberark.cloud/scim/v2/Users/3c8c5490-0441-4ef8-9b40-4ed86c2161fc

Example response:

{
"name": {
"formatted": "Rudolf Eisenbarth",
"familyName": "Eisenbarth",
"givenName": "Rudolf"
},
"displayName": "Rudolf Eisenbarth",
"active": true,
"emails": [
{
"type": "work",
"primary": true,
"value": "rudeis@corporate.com"
}
],
"userName": "rudeis",
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "3c8c5490-0441-4ef8-9b40-4ed86c2161fc",
"meta": {
"resourceType": "User",
"created": "2025-05-13T13:46:58.876687Z",
"lastModified": "2025-05-13T13:46:58.876687Z",
"location": "https://abc4120.id.cyberark.cloud/Scim/v2/Users/3c8c5490-0441-4ef8-9b40

Omada updates only the mapped fields. If, for example, your task mapping only includes the employeeNumber for update, Omada will:

  • keep all other fields exactly as received from the GET.
  • replace only the mapped fields (e.g., employeeNumber).
  • send a full object via PUT, containing both:
    • unchanged fields from the GET response.
    • updated fields from your task mapping.

An example of PUT payload:

{
"name": {
"formatted": "Rudolf Eisenbarth",
"familyName": "Eisenbarth",
"givenName": "Rudolf"
},
"displayName": "Rudolf Eisenbarth",
"active": true,
"emails": [
{
"type": "work",
"primary": true,
"value": "rudeis@corporate.com.br" // updated email
}
],
"userName": "RUDEIS", // updated username
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:core:2.0:User"
],
"id": "3c8c5490-0441-4ef8-9b40-4ed86c2161fc",
"meta": {
"resourceType": "User",
"created": "2025-05-13T13:46:58.876687Z",
"lastModified": "2025-05-13T13:46:58.876687Z",
"location": "https://abc4120.id.cyberark.cloud/Scim/v2/Users/3c8c5490-0441-4ed86c2161fc"
},
"employeeNumber": "00001202" // newly added field
}
important

If ReconcileOnUpdate is not enabled, Omada sends only the fields mapped in your task mapping - which could lead to data loss if the system expects full objects. Make sure that your GET request retrieves all necessary fields that you want to maintain.

PATCH (Comparison)

When using PATCH instead of PUT, Omada only sends the fields that are explicitly mapped for update, without needing to perform a full GET first. PATCH requests typically use the following operation structure:

[
{
"op": "replace",
"path": "emails[type eq \"work\"].value",
"value": "newemail@company.com"
}
]

This makes PATCH lighter in payload size compared to PUT.

Why reconciliation is not possible with PATCH

Although, in theory, reconciliation could also involve reading a GET response, PATCH requires additional information (such as op, path, and specific attribute structures) that is not typically returned by a normal GET. Because of this:

  • Omada cannot rebuild the PATCH structure properly based on a simple GET.
  • some systems require more context for PATCH (like exact array indexes, path expressions, operation types), which are not available through a standard GET.

Thus, reconciliation is not supported when using PATCH.

PUT vs PATCH

FeaturePUTPATCH
Data sentFull object (can be built manually or via reconciliation)Only mapped fields
GET before updateOptional (only required if using reconciliation)Not required
ReconciliationSupported when enabledNot supported
Payload sizeLargerSmaller
Risk of missing dataLow (with reconciliation)Higher (partial update only)
UsageUse when full consistency is neededUse for lightweight updates without full object consistency
important
  • PUT without reconciliation: Omada sends only the mapped fields, based on your task mapping.
  • PUT with reconciliation: Omada performs a GET first, fills missing fields, and then sends the full object.
  • PATCH: Omada only sends small, operation-based updates and reconciliation is not supported because of the format (op, path, value).

Using multivalue properties when updating APIs

In many APIs, there are fields that accept multiple values instead of just one. These are known as multivalue properties. For example, when managing a group object, a field like members may contain a list of users:

{
"members": [
{ "value": "user-12345" },
{ "value": "user-67890" },
{ "value": "user-54321" }
]
}

When working with multivalue properties, updates usually require sending the complete list of values, not just the new value you want to add. If you send only the new value without including the existing ones, you may accidentally overwrite the full list.

To update a multivalue property correctly:

  1. Retrieve the current values from the API (for example, by performing a GET request).
  2. Add the new value to the list.
  3. Send the full updated list back in the update request (PUT, PATCH, and similar).

Example

Current group members:

{
"members": [
{ "value": "user-12345" },
{ "value": "user-67890" }
]
}

New member to add: user-54321

Correct update:

{
"members": [
{ "value": "user-12345" },
{ "value": "user-67890" },
{ "value": "user-54321" }
]
}

Incorrect update (this configuration would remove existing members):

{
"members": [
{ "value": "user-54321" }
]
}


Configuring multivalue properties in Omada

When configuring Omada to work with multivalue attributes, you must ensure the platform treats the property correctly:

  1. Data model configuration.

In the Data Model, define the property as multivalued by setting multiValued="true". Example:

<property name="members[].value" multiValued="true" />

  • members[] indicates it is an array/list.
  • .value indicates the specific field to map (the user ID, for example).
  1. Task mapping configuration.

In the Task Mapping for the provisioning task:

  • Map members[].value for the create, update, and delete operations.
  • Set the action correctly:
    • Add: when adding new values.
    • Remove: when removing values.
    • Modify: when updating values in general.
    • Set: Multi valued = Yes.

Example in Omada Task Mapping:

Configure separate mappings depending on the type of operation (create, update, delete).

  1. Reconciliation.

If Omada cannot inherently know all existing values in the target system:

  • Enable reconciliation so Omada will GET the current state before updating.
  • Omada will compare the current members list with the intended list.
  • Based on the difference, Omada will add or remove only the necessary entries.

This prevents accidental data loss and ensures consistent multivalue property management.

Resource-driven attributes (RDA)

Resource-driven attributes (RDA) is a mechanism in Omada Identity that allows you to assign attribute values to a resource based on the values of another resource assigned to the same identity.

Zendesk example

You are integrating Zendesk with Omada and you want to assign a specific role to a user (for example: admin, agent). In Zendesk, when you create or update a user via API, the role is sent within the same payload as the user:

{
"user": {
"name": "Maria da Silva",
"email": "maria@company.com",
"role": "admin"
}
}

In Omada, you model this with two separate resources:

  • Zendesk Account (the actual user account)
  • Zendesk Role (example: Admin, Agent, Light Agent)

The user can only request the role through an access request or receive it through a policy.

How does Omada know it needs to include the role in the account payload?

This is where resource-driven attributes (RDA) come in:

The user is assigned the Zendesk Role: Admin resource.

The user also has the Zendesk Account resource.

The RoPE (ReferencePathAttributesValueResolver) detects that the Zendesk Role defines an attribute like role = "admin".

Omada automatically injects that value into the account CRA before provisioning.

So when Omada provisions the Zendesk user, it sends the following payload:

{
"user": {
"name": "Maria da Silva",
"email": "maria@company.com",
"role": "admin" // comes from the "Zendesk Role" resource
}
}

Configuration in RoPE (EngineConfiguration.config)

You need to define the resolver paths in the EngineConfiguration.config file using the ReferencePathAttributesValueResolver. Example configuration:

<add key="ZendeskCustomRole"
name="Zendesk Account:C_ZENDESKCUSTOMROLES"
extraInfo="Type:ReferencePath"
value="/#ASSIGNMENTS_PER_RESOURCETYPE/Zendesk Custom Role:[ROLEID]"/>

<add key="ZendeskRole"
name="Zendesk Account:C_ZENROLE"
extraInfo="Type:ReferencePath"
value="/#ASSIGNMENTS_PER_RESOURCETYPE/Zendesk Role:[C_ZENROLE]"/>

This configuration provides Omada with the following information:

  • When provisioning a Zendesk Account, look for any assigned Zendesk role or Zendesk custom role resources.
  • Copy the attribute C_ZENROLE or ROLEID from the respective resource.
  • Inject it into the CRA of the Zendesk Account.

RoPE XML Fields

key - logical name of the mapping (used internally by the resolver).
name - format: <TargetResource>:<TargetProperty> (where the value will be set).
extraInfo - must be Type:ReferencePath to enable the path-based resolver logic.
value - path to the source value (example: another resource assigned to the identity).

Omada can automatically take attribute values from other resources assigned to the same user and inject them into the main resource (like an account), without scripting or duplication. This behavior is called resource-driven attributes (RDA).

Expressions

{{PropertyName}}.Replace(" ", "")

Purpose:
Removes all space characters from the value of the specified property.

Example:
If {{PropertyName}} is RLM_NAME and its value is Access Group, the result after applying the expression will be AccessGroup.

Common use case:
This is commonly used when the final value must not contain any spaces. For example, to generate system-friendly identifiers, usernames, or values required by APIs and external systems.


string.Format("{0}@{1}", {{Property1}}, {{Property2}})

Purpose:
Combines two property values into a single email-like string using the format value1@value2.

Example:
If {{Property1}} is ROPE_AccountName with the value _jdoe_and {{Property2}} is ConnectorConfiguration.GetValue("DomainName") returning example.com, the result will be: jdoe@example.com.

Common use case:
Typically used to generate an email address or user principal name (UPN) by combining a username with a domain name.


accountEnabled ? "Active" : "Disabled"

Purpose:
Converts a Boolean value into a string value accepted by Omada, since Omada does not accept true or false directly for this field.

Example:
If accountEnabled is true, the result will be Active. If accountEnabled is false, the result will be Disabled.

Some systems, like Omada, expect the status to be represented as a string (example: Active or Disabled) rather than a Boolean (true or false). This expression ensures compatibility by converting the boolean to the expected format.

Common use case:
Used when mapping user status or account enablement in identity provisioning or synchronization processes.


userPrincipalName.Substring(0, userPrincipalName.IndexOf("@"))

Purpose:
Extracts the username part from an email address or UPN (User Principal Name), removing the domain.

Example:
If userPrincipalName is jane.doe@example.com, the result of this expression will be jane.doe.

IndexOf("@") finds the position of the @ character. Substring(0, ...) returns everything before that position.

Common use case:
Used when only the username portion is needed (example: for account names, aliases, or constructing login IDs without the domain).


(string.IsNullOrEmpty(validto) || validto == "00000000")? null : (DateTime?) DateTime.ParseExact(validto,"yyyyMMdd",null)

Purpose:
Converts a string to a nullable DateTime only if the value is valid. If the string is empty or contains a placeholder like 00000000, it returns null.

Example:
If validto is 20251231, the result is a DateTime object: 31/12/2025. If validto is "" or 00000000, the result is null.

Some systems use 00000000 or an empty string to represent "no date", which is not valid for DateTime.ParseExact. This expression ensures only properly formatted dates are converted, avoiding runtime errors.

Common use case:
Used when importing or transforming date values from external sources that may include placeholder or missing values. Especially useful when the target system expects a nullable DateTime.


DateTime.ParseExact(validfrom, "yyyyMMdd", null)

Purpose:
Converts a date string in the format yyyyMMdd (example: 20250523) into a DateTime object.

Example:
If validfrom is 20250523, the result will be the DateTime object representing May 23, 2025.

yyyyMMdd is the expected format: 4-digit year, 2-digit month, and 2-digit day with no separators. ParseExact ensures the format is strictly followed. Ff the input does not match, an error will be returned.

Common use case:
Used when importing dates from external systems that store them as plain strings. Ensures the date is properly parsed and handled as a DateTime object in workflows, validations, or database operations.


Operation == "Create" && Value != null && Value.Length > 0 ? string.Format("https://graph.microsoft.com/v1.0/users/{0}@{1}", Value, ConnectorConfiguration.GetValue("DomainName")) : null

Purpose:
Generates a properly formatted Microsoft Graph API URL for each owner when creating a resource, only if the Value is not null or empty.

Example:
If Value is jdoe and the domain is example.com, the result will be: https://graph.microsoft.com/v1.0/users/jdoe@example.com

The operation checks if the operation is Create and the value exists. If valid, it builds the full URL pointing to the user in Microsoft Graph using the provided domain from connector configuration. If not, it returns null.

Common use case:
This expression is used for multi-valued properties like owners, where each value must be converted into a full Microsoft Graph URL. Omada will process each value in the list individually using this expression.

note

Ensure that the Value passed corresponds to the user’s alias or account name — not the full UPN — as the domain will be appended automatically.